服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - 解决spring AOP中自身方法调用无法应用代理的问题

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

2021-12-08 12:00tangtong1 Java教程

这篇文章主要介绍了解决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.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

延伸 · 阅读

精彩推荐
  • Java教程Mybatis中实体类属性与数据列表间映射方法介绍

    Mybatis中实体类属性与数据列表间映射方法介绍

    这篇文章主要介绍了Mybatis中实体类属性与数据列表间映射方法介绍,一共四中方法,供大家参考。...

    lmy862635672021-01-22
  • Java教程深入理解Java之HashMap源码剖析

    深入理解Java之HashMap源码剖析

    这篇文章主要介绍了深入理解Java之HashMap源码剖析,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    牛奶、不加糖1692020-08-12
  • Java教程jfreechart画折线图的方法

    jfreechart画折线图的方法

    这篇文章主要为大家详细介绍了jfreechart画折线图的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    yuhentian5542021-05-10
  • Java教程java动态代理和cglib动态代理示例分享

    java动态代理和cglib动态代理示例分享

    这篇文章主要介绍了java动态代理和cglib动态代理示例,JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期间创建接口的代理实例,下面我们使用示...

    java教程网3822019-11-15
  • Java教程项目依赖Springboot jar失败解决方案

    项目依赖Springboot jar失败解决方案

    这篇文章主要介绍了项目依赖Springboot jar失败解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以...

    陶海军3032020-08-20
  • Java教程Java实现四种微信抢红包算法,拿走不谢

    Java实现四种微信抢红包算法,拿走不谢

    14年微信推出红包功能以后,很多公司开始上自己的红包功能,到现在为止仍然有很多红包开发的需求,实现抢红包算法也是面试常考题。...

    科技农民工10742021-11-24
  • Java教程通过简单方法实现spring boot web项目

    通过简单方法实现spring boot web项目

    这篇文章主要介绍了通过简单方法实现spring boot web项目,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可...

    贾树丙4042020-09-19
  • Java教程JVM中的flag设置详解

    JVM中的flag设置详解

    这篇文章主要介绍了JVM中的flag设置详解,涉及堆大小设置,收集器设置等香公馆内容,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下...

    Mirhunana10502021-03-30