当一个切面对一个业务类生效时,我们使用的业务类对象实际上是Spring帮我们生成的一个代理对象,而这个代理的粒度,是类级别的。
自调用,是指一个类的方法调用本类的其他方法。
1、简单的 AOP 使用示例
示例代码中有3个类:
TestBean.java
TestAspect.java
Main.java
执行结果如下:
2、代理的粒度是类级别的,所以自调用时不会走切面逻辑
我们对 TestBean 稍作改造,让hello函数:
如果我们调用 hi 函数,会输出:
如果我们调用 hello 函数,会输出:
注意,hi之前没有我是前置通知
。
Spring的事务管理中有个 @Transactional
注解可以方便的管理事务,也是基于 AOP 实现的。该注解在下面的情况下会失效:外部类调用本类的一个没有 @Transactional
注解的函数,该函数调用本类的一个有 @Transactional
注解的函数。失效原因就是因为代理是类级别的。
3、为什么要这样设计?
技术上能实现自调用的时也走切面逻辑,比如 cglib 的 MethodInterceptor (Java:使用 cglib 实现动态代理)。
有些场景自调用走代理更合适,而另外一些场景不走代理更合适。选择类级别的代理是权衡的结果。
我们有办法让自调用走代理吗?有。
4、让自调用走代理的方法1:自装配
将 TestBean 改造为:
如果一个 Bean 没有被代理,也可以这样使用。如果在你的测试中运行失败,请将 Spring 升级到最新版本。
5、让自调用走代理的方法2:启用 exposeProxy
使用 @EnableAspectJAutoProxy
注解时,指定 exposeProxy 为 true。
业务逻辑中使用AopContext.currentProx
获取当前的代理。
比如将 TestBean 改造为: