摘要
spring 全家桶帮助 java web 开发者节省了很多开发量, 提升了效率. 但是因为屏蔽了很多细节, 导致很多开发者只知其然, 不知其所以然, 本文就是分析下使用 spring 的一些注解, 不能够自调用的问题. 因为本身这类文章很多, 所以有些地方不会详述, 直接引用其他文章.
问题
使用了 Spring 中哪些注解不能进行自调用
为什么代理了就不能自调用
Spring 常用的 @Cache , @Async , @Transaction 这三种原理上有什么区别吗
如何解自调用的问题
使用不同的解法各自有什么坑
AOP 的概述
首先需要澄清几个需要区分的名词 AOP SpringAOP AspectJ
AOP
Aspect-oriented programming, 面向切面编程, 一种解决问题的思想, 将一些重复性的编码问题通过切面来实现. 很多人了解切面是通过 Spring 来了解的, 所以会有种误解将 SpringAOP 和 AOP 划等号, 其实不然.
Spring AOP
Spring AOP 算是 一种简单的 AOP 的落地实现方式, 它主要提供在 Spring 容器内的一种 AOP 实现方式, 脱离了 Spring 就不 work 了. Spring AOP 并不是一套完整的 AOP 解决方案.
Spring 的的众多组件都是这样, Spring-Session,Spring-jdbc,Spring-Cache 等等, 都能解决一部分通用的需求, 但是会有很多限制, 想用深了, 更灵活的实现功能, 还是要使用其他的专业组件 / 框架.
SpringAOP 默认使用代理模式实现的, 也就是 JDK Proxy/CGLib. 关于代理以及 JDK Proxy 和 CGLib 不在赘述了.
AspectJ
Spring AOP 并不是一套完整的 AOP 解决方案, AspectJ 是的. AspectJ 在编译器织入切面到目标类
解法
上面介绍了 SpringAop 的实现, 下面着重介绍解法.
方法 1 - 注入代理 bean 到自己
这个原理没啥好解析的
Note
会有循环依赖的问题, 使用 @Lazy 解决
方法 2 - AopContext.currentProxy() 获取当前代理对象
使用
首先需要配置 @EnableAspectJAutoProxy(exposeProxy=true) , 允许代码中获取 proxy 类
原理解析
这个实现可以看下 AopContext 类,
然后就是 Spring Aop 自动设置代理, 设置 exposeProxy 属性的问题了. 有人写过了, 就不写了
- https://cloud.tencent.com/developer/article/1497700
- Note
因为使用了 SpringAOP, 所以会有代理模式的限制
AopContext.currentProxy() 使用的是 ThreadLocal 的, 所以不能跨线程了
bean 设置的限制, 比如 @Async 代理创建方式不同其他 | 方式
方法 3 - 直接使用 AspectJ
既然自调用的问题是由于 SpringAOP 由代理模式实现引起的, 那就不使用代理模式不就解决了吗
使用
切换为代理模式
添加 aspectj 织入包依赖
使用
启动方式 AspectJ 是编译器将切面织入到目标 class 的, 启动的使用需要加上 java agent 的参数
总结
方法 | 限制 |
---|---|
自调用 | 代理模式的限制,比如只能作用于 public ,非 static 的方法 |
AopContext.currentProxy() | 1. 代理模式的限制 2.ThreadLocal 的限制,不能跨线程了 3.bean 设置的限制,比如 @Async 代理创建方式不同其他 |
AspectJ | 无限制,使用起来麻烦一点 |
关注公众号 [方丈的寺院] , 第一时间收到文章的更新, 与方丈一起开始技术修行之路
参考
- http://blog.kezhuw.name/2017/08/31/spring-aspectj-load-time-weaving/
- https://cloud.tencent.com/developer/article/1497700
- https://frightanic.com/software-development/spring-proxy-self-invocation/
- https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/ProxyAsyncConfiguration.html#asyncAdvisor--
- https://www.baeldung.com/spring-aop-vs-aspectj
来源: http://www.tuicool.com/articles/RNNn6zf