解决spring|解决spring AOP中自身方法调用无法应用代理的问题
目录
- spring AOP中自身方法调用无法应用代理
- 如下例
- 可以使用如下两种方式修改代码以应用事务
- (1)在MyServiceImpl中声明一个MyService对象
- (2)使用AopContext类
- spring aop 内部方法调用事务不生效
- 方法1:
- 方法2:
spring AOP中自身方法调用无法应用代理
如下例
public class MyServiceImpl implements MyService { public void do(){//the transaction annotation won't work if you directly invoke handle() method with 'this'this.handle(); } @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class) public void handle() {//sth with transaction }}
如果直接调用this的handle()方法则事务无法生效,原因是spring的AOP是通过代理实现的,像这样直接调用本对象的方法是不会应用代理的。
可以使用如下两种方式修改代码以应用事务
(1)在MyServiceImpl中声明一个MyService对象
public class MyServiceImpl implements MyService { @Autowired private MyService myService; public void do(){//use myService objectmyService.handle(); } @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class) public void handle() {//sth. with transaction }}
(2)使用AopContext类
public class MyServiceImpl implements MyService { public void do(){//fetch current proxy objet from AopContext((MyService)AopContext.currentProxy()).handle(); } @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class) public void handle() {//sth with transaction }}
注意,原生的AspectJ是不会有这种自身调用的问题的,因为它不是基于代理的AOP框架。
spring aop 内部方法调用事务不生效
方法1:
基于 proxy 的 spring aop 带来的内部调用问题可以使用 AopContext.currentProxy() 强转为当前的再调用就可以解决了
例如:
错误用法:
public Account getAccountByName2(String userName) {return this.getAccountByName(userName); }
【解决spring|解决spring AOP中自身方法调用无法应用代理的问题】修改为:
public Account getAccountByName2(String userName) {return ((AccountService)AopContext.currentProxy()).getAccountByName(userName); }
另外注意:要设置aop实体暴露出来。在springboot的application.java里面加上
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
方法2:
利用初始化方法在目标对象中注入代理对象
在目标对象类中注入spring上下文,通过context获取代理对象,并调用代理对象的方法。
注意:该方案对于scope为prototype的bean无法适用,因为每次获取bean时都返回一个新的对象。
方法2.1:
//延迟加载方式private TestService testService; @Autowired@Lazypublic void setTestService(TestService testService) {this.testService = testService; }
方法2.2:
import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Service; import com.blog.common.aop.service.TestService; @Servicepublic class TestServiceImpl implements TestService {@Autowiredprivate ApplicationContext context; private TestService proxyObject; @PostConstruct// 初始化方法,在IOC注入完成后会执行该方法private void setSelf() {// 从spring上下文获取代理对象(直接通过proxyObject=this是不对的,this是目标对象)// 此种方法不适合于prototype Bean,因为每次getBean返回一个新的BeanproxyObject = context.getBean(TestService.class); }public void methodA() throws Exception {System.out.println("method A run"); System.out.println("method A 中调用method B,通过注入的代理对象,调用代理对象的方法,解决内部调用实现的问题。"); proxyObject.methodB(); //调用代理对象的方法,解决内部调用失效的问题}public void methodB() {System.out.println("method B run"); }}
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
推荐阅读
- parallels|parallels desktop 解决网络初始化失败问题
- 考研英语阅读终极解决方案——阅读理解如何巧拿高分
- 由浅入深理解AOP
- Activiti(一)SpringBoot2集成Activiti6
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- 2018-07-09|2018-07-09 Spring 的DBCP,c3p0
- Spark|Spark 数据倾斜及其解决方案
- 解决SyntaxError:|解决SyntaxError: invalid syntax