一、导入jar包
org.springframework.boot spring-boot-starter-aop
二、自定义注解
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> funcGroups = getAnnotationFuncGroup(joinPoint); //触发业务功能 return executeBusinessFunc(joinPoint,funcGroups); } /** * 执行业务功能 * @param joinPoint 切面 * @param funcGroups 功能分组 * @return * @throws Throwable */ private Object executeBusinessFunc(ProceedingJoinPoint joinPoint,Map > funcGroups) throws Throwable{ //新增业务方法描述 BusinessMethodParam businessMethodParam = new BusinessMethodParam(joinPoint.getArgs()); //before处理 List beforeFuncs = funcGroups.get(BEFORE_POINT); if(!CollectionUtils.isEmpty(beforeFuncs)){ executeFunc(beforeFuncs,businessMethodParam); } //overwrite处理 List 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 afterFuncs = funcGroups.get(AFTER_POINT); if(!CollectionUtils.isEmpty(afterFuncs)){ executeFunc(afterFuncs,businessMethodParam); } return businessMethodParam.getResult(); } /** * 触发功能 * @param funcs 功能beanName集合 * @param businessMethodParam 业务方法描述 */ private void executeFunc(List 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 > getAnnotationFuncGroup(ProceedingJoinPoint joinPoint)throws Exception{ MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature(); BusinessFuc businessFuc = methodSignature.getMethod().getAnnotation(BusinessFuc.class); List beforeFuncNames = new ArrayList<>(); List overwriteFuncNames = new ArrayList<>(); List 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 > 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 MapparamMap; 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(); Listresult = (List )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 ListqueryAll() { return billLineMapper.queryInfos(); }}