Spring AOP内部调用失效问题

Spring AOP基本原理

Spring AOP是基于动态代理机制实现的,通过动态代理机制生成目标对象的代理对象,当外部调用目标对象的相关方法时,Spring注入的其实是代理对象Proxy,通过调用代理对象的方法执行AOP增强处理,然后回调目标对象的方法。


AOP基本原理

我们来看下面一个需要进行AOP增强的类,外部调用methodA()且该方法中调用methodB(),调用methodB()不会执行AOP的增强逻辑。

import org.springframework.stereotype.Service;
/**
 * 目标对象类
 * @author Gufung
 */
@Service
public class TestAopService {

    public void methodA() {
        System.out.println("method A run");
        //内部调用方法B时AOP的增强处理方法不会执行
        methodB();
    }
    
    public void methodB() {
        System.out.println("method B run");
    }
}

通过上图的AOP基本原理,我们知道真正执行methodA()的是目标对象,那么methodA()中调用methodB()就是目标对象的方法而不是代理对象的,也就自然不会执行AOP的增强逻辑。

解决方案

最基本的思路就是在内部调用时要调用代理对象的方法这样就可以执行AOP的增强逻辑了。

A.开启暴露代理对象

1.配置spring-context.xml通过注解实现AOP

<!-- 通过@Aspect注解实现AOP -->
<!-- proxy-target-class="true"表示使用CGlib动态代理 -->
<!-- expose-proxy="true"暴露代理对象 -->
<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>

2.目标对象内部调用时获取代理对象,再调用代理对象的方法

import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
/**
 * 目标对象类
 * @author Gufung
 *
 */
@Service
public class TestAopService {

    public void methodA() {
        System.out.println("method A run");
        //methodB();
        //从spring上下文获取代理对象执行方法
        ((TestAopService) AopContext.currentProxy()).methodB();
    }
    
    public void methodB() {
        System.out.println("method B run");
    }
}
B.利用初始化方法在目标对象中注入代理对象

在目标对象类中注入spring上下文,通过context获取代理对象,并调用代理对象的方法。

注意:该方案对于scope为prototype的bean无法适用,因为每次获取bean时都返回一个新的对象。

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");
    }

}
参考
Spring事务处理时自我调用的解决方案及一些实现方式的风险
spring之aop方法内部调用问题
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,293评论 19 139
  • 什么是Spring Spring是一个开源的Java EE开发框架。Spring框架的核心功能可以应用在任何Jav...
    jemmm阅读 16,629评论 1 133
  • Spring简介 spring框架由Rod Johnson开发,2004年发布了Spring框架的第一版。Spri...
    qiuqiu_hz阅读 4,669评论 0 15
  • 文章作者:Tyan博客:noahsnail.com 3.4 Dependencies A typical ente...
    SnailTyan阅读 9,678评论 2 7
  • 你不愿意种花,你说,我不愿看见它一点点凋落。是的,为了避免结束,你避免了一切开始。 ...
    哲_5ccd阅读 1,943评论 0 0