AOP 插件就这?上手不用两分钟!!
小伙伴们好呀,今天 4ye 来分享这个 Spring AOP 插件篇 啦😝

项目一览
这个 demo 分为两个模块 :
👉 插件模块 springboot-aop-plugin
👉 业务模块 springboot-aop-plugin-used

模块功能介绍
👉 插件模块 springboot-aop-plugin 里面提供两个插件
👉 业务模块 springboot-aop-plugin-used

使用
将 插件模块 打包成一个 jar 包,然后在 业务模块 中配置好 plugins.json 的 jar 包地址,随后 激活/停用插件,就可以在控制台看到不同的输出效果啦😄
原理图 👇
主要知识点

效果演示
API 如下🐖

激活插件1
调用方法时会统计该方法的调用次数

关闭插件1

再次激活插件1
顺便激活插件2 效果

还挺好玩的 哈哈 其他就等小伙伴们自己优化了 🐷
主要源码说明
MethodCountingTimesPlugin 插件通过实现这个 MethodBeforeAdvice 来达到 @Before 注解的效果
MethodSpendTimePlugin 插件通过实现这个 MethodInterceptor 来达到 @Around 注解的效果
代码也很简单,就不多介绍啦👇
package com.java4ye.demo.advice;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* 方法调用次数插件
*
* @author Java4ye
* @微信公众号: Java4ye
* @GitHub https://github.com/Java4ye
* @CSDN https://blog.csdn.net/weixin_40251892
* @掘金 https://juejin.cn/user/2304992131153981
*/
@Slf4j
public class MethodCountingTimesPlugin implements MethodBeforeAdvice {
/**
* 针对不同类中的方法做统计
*/
private Map methodMap = new HashMap<>();
@Override
public void before(Method m, Object[] args, Object target) throws Throwable {
String className = target.getClass().getSimpleName();
String methodName = m.getName();
String key = className + "." + methodName;
Integer methodCount = methodMap.getOrDefault(key, 0);
++methodCount;
methodMap.put(key, methodCount);
log.info("{}", this.getClass().getName());
log.info("call class: {} , method {} , times : {}", className, methodName, methodCount);
}
}
package com.java4ye.demo.advice;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StopWatch;
/**
*
* 计算方法花费时间插件
*
* @author Java4ye
* @微信公众号: Java4ye
* @GitHub https://github.com/Java4ye
* @CSDN https://blog.csdn.net/weixin_40251892
* @掘金 https://juejin.cn/user/2304992131153981
*/
@Slf4j
public class MethodSpendTimePlugin implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
String name = invocation.getMethod().getName();
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Object rval = invocation.proceed();
stopWatch.stop();
String s = stopWatch.prettyPrint();
log.info("{}",this.getClass().getName());
log.info("call method {} spend time : {}",name,s);
return rval;
}
}
PluginConfig
这个配置类呢,就是在初始化时去加载,解析这个配置文件 plugins.json,然后放到这个 map 中

DefaultPluginFactory
激活插件方法如下 👇
也就是通过这个 编程式AOP 来实现

完整项目在 Github 上,链接在文末自取就可以啦~
接下来说说搭建这个小demo 遇到的坑🕳
坑🕳
JDK11

JDK8

所以在 JDK11 中无法通过将 AppclassLoader 转换成 URLClassLoader 去判断有没有加载过某个 jar 包
问题思考
完成这个 demo 后,4ye 对 AOP 又有了以下的这些思考~
一. AOP 发生的条件
我们都知道 AOP 是 面向切面编程 ,所以我们得告诉它往哪里切,才有机会创建这个 代理对象 出来~
比如 Spring 提供的这几个注解
事务 @Transactional
异步 @Async
缓存 @Cacheable , @CacheEvict ,@CachePut , @Caching 等
这些在 spring-aspects 模块中
同时,创建代理对象时,CGLIB 只能代理 非final 类中的 非final,非static 方法。
二. 为啥采用编程式的AOP
这就突出它的优点啦!毕竟编程式才是最灵活的 哈哈。就像 编程式事务 一样,你可以控制事务的粒度,在编程式 AOP 中,你可以控制 Advice 的启动,停止。
三. 优化地方
新发现
我们这篇的主题是插件,插件可插拔的特点十分方便,同时,我们利用 ClassLoader 实现了 热加载!
但是呢,我了解到它不仅仅有这个功能,它还可以实现对 class 文件的加解密,同时 4ye 也是间接了解到这个 阿里的 pandora 以及解锁了新的源码篇章 spring boot devtools ,很有意思的,争取早点分享出来 嘿嘿 😋
总结
通过该项目来实现这个 AOP 插件,学会了一项装13技能 哈哈哈

最后
本文就分享到这里啦🐖
仓库地址 👇 (感谢每一颗 star !)
喜欢的话可以 关注 并 星标 下公众号 Java4ye 支持下 4ye 呀😝,这样就可以第一时间收到更文消息啦🐷
我是4ye 咱们下期应该……很快再见!! 😆