zoukankan      html  css  js  c++  java
  • 基于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();
        }
    }
  • 相关阅读:
    .net正在终止线程异常
    js判断客户浏览器类型,版本
    C#中ToString格式大全
    WPF TextBox 搜索框 自定义
    C#:获取设备电量相关信息
    C#中的委托与事件并存的理由
    WPF中的Pack URI
    SQLServer中的数据库备份和还原
    使用Aspose.Cells读取Excel
    SQLServer存储过程事务用法
  • 原文地址:https://www.cnblogs.com/domi22/p/9096233.html
Copyright © 2011-2022 走看看