1. 程式人生 > >基於AOP註解實現業務功能的動態配置

基於AOP註解實現業務功能的動態配置

引擎 sin equal cgroups list tro com pan inter

一、導入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註解實現業務功能的動態配置