基于AOP注解实现业务功能的动态配置
Posted 老人与JAVA
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于AOP注解实现业务功能的动态配置相关的知识,希望对你有一定的参考价值。
一、导入jar包
<dependency><!-- 4.引入AOP--> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
二、自定义注解
package com.test.domi.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 标注业务功能注解 */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface BusinessFuc { /** * 校验功能 * beanNames,point(before | overwrite | after) */ String[] funcNames(); }
三 、定义切面切中注解并织入相关业务
package com.test.domi.aspect; import com.test.domi.annotation.BusinessFuc; import com.test.domi.common.util.SpringContextUtil; import com.test.domi.func.BusinessMethodParam; import com.test.domi.func.IBusinessFunc; import org.apache.commons.lang.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 业务功能切面处理 */ @Component @Aspect @Order(1) public class BusinessFuncAspect { /** * 前置扩展 */ public static final String BEFORE_POINT = "before"; /** * 后置扩展 */ public static final String AFTER_POINT = "after"; /** * 覆盖扩展 */ public static final String OVERWRITE_POINT = "overwrite"; /** * funcName和切面的分隔符 */ public static final String FUNC_SEPARATOR = "|"; /** * JS引擎 */ public static final String NASHORN_ENGINE = "nashorn"; /** * 业务功能类型 -JAVA */ public static final String JAVA_FUNC = "JAVA"; /** * 业务功能类型 -JS */ public static final String JS_FUNC = "JS"; /** * 业务功能类型 -groovy */ public static final String GROOVY_FUNC = "GROOVY"; /** * 拦截@BusinessFuc注解,执行业务功能 * @param joinPoint * @return * @throws Exception */ @Around(value="@annotation(com.test.domi.annotation.BusinessFuc)") @Transactional(rollbackFor = Throwable.class) public Object businessFunc(ProceedingJoinPoint joinPoint) throws Throwable{ //获取注解中的Func分组 Map<String,List<String>> funcGroups = getAnnotationFuncGroup(joinPoint); //触发业务功能 return executeBusinessFunc(joinPoint,funcGroups); } /** * 执行业务功能 * @param joinPoint 切面 * @param funcGroups 功能分组 * @return * @throws Throwable */ private Object executeBusinessFunc(ProceedingJoinPoint joinPoint,Map<String,List<String>> funcGroups) throws Throwable{ //新增业务方法描述 BusinessMethodParam businessMethodParam = new BusinessMethodParam(joinPoint.getArgs()); //before处理 List<String> beforeFuncs = funcGroups.get(BEFORE_POINT); if(!CollectionUtils.isEmpty(beforeFuncs)){ executeFunc(beforeFuncs,businessMethodParam); } //overwrite处理 List<String> overwriteFuncs = funcGroups.get(OVERWRITE_POINT); if(!CollectionUtils.isEmpty(overwriteFuncs)){ //如果有多个功能,只执行最后一个 int overSize = overwriteFuncs.size(); executeFunc(overwriteFuncs.subList(overSize - 1,overSize),businessMethodParam); }else{ //没有配置overwrite功能,则执行原业务方法 Object returnObj = joinPoint.proceed(); businessMethodParam.setResult(returnObj); } //after处理 List<String> afterFuncs = funcGroups.get(AFTER_POINT); if(!CollectionUtils.isEmpty(afterFuncs)){ executeFunc(afterFuncs,businessMethodParam); } return businessMethodParam.getResult(); } /** * 触发功能 * @param funcs 功能beanName集合 * @param businessMethodParam 业务方法描述 */ private void executeFunc(List<String> funcs,BusinessMethodParam businessMethodParam) throws Throwable{ for (String funcName : funcs){ executeFunc(funcName,JAVA_FUNC,businessMethodParam); } } /** * 触发功能 * @param func 业务功能 * @param func 业务功能类型:JAVA/JS * @param businessMethodParam 业务方法描述 */ private void executeFunc(String func,String funcType,BusinessMethodParam businessMethodParam) throws Throwable{ if(JAVA_FUNC.equalsIgnoreCase(funcType)){ //JAVA功能 IBusinessFunc businessFunc = (IBusinessFunc) SpringContextUtil.getBean(func); businessFunc.executeFunc(businessMethodParam); }else if (JS_FUNC.equalsIgnoreCase(funcType)){ //JS功能 ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName(NASHORN_ENGINE); scriptEngine.eval(func); Invocable invocable = (Invocable)scriptEngine; invocable.invokeFunction("executeFunc",businessMethodParam); }else if (GROOVY_FUNC.equalsIgnoreCase(funcType)){ //执行groovy功能 } } /** * 读取注解上的func配置 * @param joinPoint 切面 * @return func分组,按照before|after|overwrite分组 */ private Map<String,List<String>> getAnnotationFuncGroup(ProceedingJoinPoint joinPoint)throws Exception{ MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature(); BusinessFuc businessFuc = methodSignature.getMethod().getAnnotation(BusinessFuc.class); List<String> beforeFuncNames = new ArrayList<>(); List<String> overwriteFuncNames = new ArrayList<>(); List<String> afterFuncNames = new ArrayList<>(); for (String func : businessFuc.funcNames()){ String point = StringUtils.substringAfter(func,FUNC_SEPARATOR); if(BEFORE_POINT.equals(point)){ beforeFuncNames.add(StringUtils.substringBefore(func,FUNC_SEPARATOR)); }else if(AFTER_POINT.equals(point)){ afterFuncNames.add(StringUtils.substringBefore(func,FUNC_SEPARATOR)); }else if(OVERWRITE_POINT.equals(point)){ overwriteFuncNames.add(StringUtils.substringBefore(func,FUNC_SEPARATOR)); }else{ //没有配置point,默认取overwrite overwriteFuncNames.add(func); } } Map<String,List<String>> funcGroup = new HashMap<>(); funcGroup.put(BEFORE_POINT,beforeFuncNames); funcGroup.put(AFTER_POINT,afterFuncNames); funcGroup.put(OVERWRITE_POINT,overwriteFuncNames); return funcGroup; } }
四、封装承载参数和返回值的VO
package com.test.domi.func; import java.util.HashMap; import java.util.Map; /** * 业务方法描述 */ public class BusinessMethodParam { /** * 业务方法参数 */ private Object[] args; /** * 业务方法返回结果 */ private Object result; /** * 自定义参数Map */ private Map<String,Object> paramMap; public BusinessMethodParam(){ this.paramMap = new HashMap<>(); } public BusinessMethodParam(Object[] args){ this.args = args; this.paramMap = new HashMap<>(); } /** * 获取业务方法参数 */ public Object[] getArgs(){ return args; } /** * 获取业务方法的返回结果 */ public Object getResult(){ return result; } /** * 设置业务方法参数返回结果 */ public void setResult(Object result){ this.result = result; } /** * 获取自定义参数值 */ public Object get(String key){ return paramMap.get(key); } /** * 设置子弟你参数值,可用于不同功能之间传递自定义参数 */ public void put(String key,Object value){ paramMap.put(key,value); } }
五、为业务功能提供统一的约束接口
package com.test.domi.func; /** * 报销类型关联功能接口 */ public interface IBusinessFunc { /** * 执行业务功能 */ void executeFunc(BusinessMethodParam businessMethodParam) throws Exception; }
六、编写业务功能扩展代码
package com.test.domi.func.impl; import com.alibaba.fastjson.JSONObject; import com.test.domi.dto.RefundBillLine; import com.test.domi.func.BusinessMethodParam; import com.test.domi.func.IBusinessFunc; import org.springframework.stereotype.Component; import java.util.List; @Component("testFunc") public class TestFunc implements IBusinessFunc { @Override public void executeFunc(BusinessMethodParam businessMethodParam) throws Exception { Object[] args = businessMethodParam.getArgs(); List<RefundBillLine> result = (List<RefundBillLine>)businessMethodParam.getResult(); result.add(new RefundBillLine()); } }
七、在service使用,在controller捕获异常
package com.test.domi.service.impl; import com.test.domi.annotation.BusinessFuc; import com.test.domi.dao.BillLineMapper; import com.test.domi.dto.RefundBillLine; import com.test.domi.service.BillLineService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service("billLineService") public class BillLineServiceImpl implements BillLineService { @Autowired private BillLineMapper billLineMapper; @Override @BusinessFuc(funcNames = {"testFunc|after"}) public List<RefundBillLine> queryAll() { return billLineMapper.queryInfos(); } }
以上是关于基于AOP注解实现业务功能的动态配置的主要内容,如果未能解决你的问题,请参考以下文章