基于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();
}
}
上一篇:Excel 中 VLOOKUP() 函数小结


下一篇:cucumber_java从入门到精通(5)使用maven创建cucumber_java项目