好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

解决spring AOP中自身方法调用无法应用代理的问题

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测试数据mon.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

查看更多关于解决spring AOP中自身方法调用无法应用代理的问题的详细内容...

  阅读:59次