博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于AOP注解实现业务功能的动态配置
阅读量:5236 次
发布时间:2019-06-14

本文共 8532 字,大约阅读时间需要 28 分钟。

一、导入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 Map
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
result = (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 List
queryAll() { return billLineMapper.queryInfos(); }}

 

转载于:https://www.cnblogs.com/domi22/p/9096233.html

你可能感兴趣的文章
游戏偶感
查看>>
Leetcode: Unique Binary Search Trees II
查看>>
C++ FFLIB 之FFDB: 使用 Mysql&Sqlite 实现CRUD
查看>>
Spring-hibernate整合
查看>>
c++ map
查看>>
exit和return的区别
查看>>
discuz 常用脚本格式化数据
查看>>
洛谷P2777
查看>>
PHPStorm2017设置字体与设置浏览器访问
查看>>
SQL查询总结 - wanglei
查看>>
安装cocoa pods时出现Operation not permitted - /usr/bin/xcodeproj的问题
查看>>
GIT笔记:将项目发布到码云
查看>>
JavaScript:学习笔记(7)——VAR、LET、CONST三种变量声明的区别
查看>>
JavaScript 鸭子模型
查看>>
SQL Server 如何查询表定义的列和索引信息
查看>>
GCD 之线程死锁
查看>>
NoSQL数据库常见分类
查看>>
一题多解 之 Bat
查看>>
Java 内部类
查看>>
{面试题7: 使用两个队列实现一个栈}
查看>>