spring AOP中自身方法调用无法应用代理
如下例
1
2
3
4
5
6
7
8
9
10
|
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对象
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public class MyServiceImpl implements MyService { @Autowired private MyService myService; public void do (){ //use myService object myService.handle(); } @Transactional (propagation=Propagation.REQUIRED, rollbackFor=Exception. class ) public void handle() { //sth. with transaction } } |
(2)使用AopContext类
1
2
3
4
5
6
7
8
9
10
|
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() 强转为当前的再调用就可以解决了
例如:
错误用法:
1
2
3
|
public Account getAccountByName2(String userName) { return this .getAccountByName(userName); } |
修改为:
1
2
3
|
public Account getAccountByName2(String userName) { return ((AccountService)AopContext.currentProxy()).getAccountByName(userName); } |
另外注意:要设置aop实体暴露出来。在springboot的application.java里面加上
1
|
@EnableAspectJAutoProxy (proxyTargetClass = true , exposeProxy = true ) |
方法2:
利用初始化方法在目标对象中注入代理对象
在目标对象类中注入spring上下文,通过context获取代理对象,并调用代理对象的方法。
注意:该方案对于scope为prototype的bean无法适用,因为每次获取bean时都返回一个新的对象。
方法2.1:
1
2
3
4
5
6
7
|
//延迟加载方式 private TestService testService; @Autowired @Lazy public void setTestService(TestService testService) { this .testService = testService; } |
方法2.2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
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; @Service public class TestServiceImpl implements TestService { @Autowired private ApplicationContext context; private TestService proxyObject; @PostConstruct // 初始化方法,在IOC注入完成后会执行该方法 private void setSelf() { // 从spring上下文获取代理对象(直接通过proxyObject=this是不对的,this是目标对象) // 此种方法不适合于prototype Bean,因为每次getBean返回一个新的Bean proxyObject = 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" ); } } |
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/tangtong1/article/details/54893624