AopContext.currentProxy()该用法的意义
今天在看同事代码的时候,发现在一个Service层,A方法调用B方法的时候,用了
((Service)AopContext.currentProxy()).B()
这种方式去调用,我没遇到过这种方式,不太理解,后来百度了一下,终于明白这样用法的意义,现在记录下来!
原来在springAOP的用法中,只有代理的类才会被切入,我们在controller层调用service的方法的时候,是可以被切入的,
但是如果我们在service层 A方法中,调用B方法,切点切的是B方法,那么这时候是不会切入的,
解决办法就是如上所示,在A方法中使用
((Service)AopContext.currentProxy()).B() 来调用B方法,这样一来,就能切入了!
引申出来的问题:当同一个类中两个方法互相调用时,被调用的方法@Transactional注解失效
问题详述
- 我们使用spring容器进行bean管理时;
- 我们使用spring进行事务管理也就是使用@Transactional;
- 我们在同一个业务类中,不同的两个方法上都使用了@Transactional注解,一个记为方法A,另一个记为方法B;
- 该业务类中的方法A调用了方法B,且B中我们使用传播级别为无论如何都创建一个新的事务执行,且异常处理后不影响外层,也就是Propagation.NESTED;
- 结果发现被调用的方法B中的事务失效了,也就是部分成功提交,部分未成功执行;
解决办法
比较简单的一种:就是在该类中自动注入本类bean,使用@Autowired即可,然后使用这个注入的bean去调用本类方法,即可达到两方法事务都起效
第二种方式就是上面所写的方式使用AopContext.currentProxy()获取代理对象,进而调用方法
疑问
查过上述解决办法的各种理解,感觉很迷;主要是说,直接调用同类方法使用的是this.xxx()的方式;这个说法没有任何问题。
问题是:自动注入的spring容器中的该类对象本来就是加强过的代理对象,那么this此时指代的不应该就是这个代理对象吗,那么调用到的为什么不是增强过的对象的方法呢?
或者说,代理对象其实是在每次调用时才产生的?实际存在于容器中的还是原始对象?
学习和理解
针对问题3:看了spring书中的aop方面的介绍,代理对象生成是bean后处理器处理的,那么很明显,就是在容器初始化的时候生成的代理对象了(前提:我们使用的是ApplicationContext的这个子容器,而不是BeanFactory这个最原始的容器,一般都是用的前者);
因为bean后处理器的处理时机是紧跟着bean的初始化结束后的。也就是说,容器中存储的就已经是增强结束的代理对象了,而不是原始对象!
针对问题2:从动态代理的原理出发可以发现问题:
其实代理对象维护着一个原始对象的引用,在执行代理对象的增强方法时,只是在使用原始对象调用原始方法的前后,去执行了一些增强操作。也就是说,实际上,还是要调用原始对象的原始方法,而且使用的就是原始对象。
那也就清晰了,因为在调用增强方法时,也就是增强方法A时;先执行了执行前的增强,再用原始对象去调用方法A的;然后在方法A中调用方法B,所以这里的this指向的就是原始对象;而非增强对象!!!那么一切就能够合理解释了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)