Spring AOP无法拦截内部方法调用-- expose-proxy=true用法

news/2024/7/7 23:53:11

假设一个接口里面有两个方法:

package demo.long;public interface CustomerService {  public void doSomething1();  public void doSomething2();  
}

接口实现类如下:

package demo.long.impl;import demo.long.CustomerService; public class CustomerServiceImpl implements CustomerService {  public void doSomething1() {  System.out.println("CustomerServiceImpl.doSomething1()");  doSomething2();  }  public void doSomething2() {  System.out.println("CustomerServiceImpl.doSomething2()");  }  }  

现在我需要在CustomerService接口的每个方法被调用时都在方法前执行一些逻辑,所以需要配置一个拦截器:

package demo.long;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;@Aspect
public class CustomerServiceInterceptor {@Before("execution(* demo.long..*.*(..))")public void doBefore() {System.out.println("do some important things before..."); }
}

把Bean加到Spring配置中

<aop:aspectj-autoproxy /><bean id="customerService" class="demo.long.impl.CustomerServiceImpl" />
<bean id="customerServiceInterceptor" class="demo.long.CustomerServiceInterceptor" />

如果现在外部对象调用CustomerService的doSomething1()方法的时候,会发现只有doSomething1()方法执行前打印了“do some important things before...”,而doSomething1()内部调用doSomething2()时并没有打印上述内容;外部对象单独调用doSomething2()时会打印上述内容。

public class CustomerServiceTest {@AutowiredICustomerService customerService;@Testpublic void testAOP() {customerService.doSomething1();}
}

原因分析

拦截器的实现原理就是动态代理,实现AOP机制。Spring 的代理实现有两种:一是基于 JDK Dynamic Proxy 技术而实现的;二是基于 CGLIB 技术而实现的。如果目标对象实现了接口,在默认情况下Spring会采用JDK的动态代理实现AOP,CustomerServerImpl正是这种情况。

JDK动态代理生成的CustomerServiceImpl的代理类大致如下:

public class CustomerServiceProxy implements CustomerService {  private CustomerService customerService;  public void setCustomerService(CustomerService customerService) {  this.customerService = customerService;  }  public void doSomething1() {  doBefore();  customerService.doSomething1();  }  public void doSomething2() {  doBefore();  customerService.doSomething2();  }  private void doBefore() {  // 例如,可以在此处开启事务或记录日志System.out.println("do some important things before...");  }  }  

客户端程序使用代理类对象去调用业务逻辑:

public class TestProxy {  public static void main(String[] args) {  // 创建代理目标对象// 对于Spring来说,这一工作是由Spring容器完成的。  CustomerService serviceProxyTarget = new CustomerServiceImpl();  // 创建代理对象// 对于Spring来说,这一工作也是由Spring容器完成的。 CustomerServiceProxy serviceProxy = new CustomerServiceProxy();  serviceProxy.setCustomerService(serviceProxyTarget);  CustomerService serviceBean = (CustomerService) serviceProxy;  // 调用业务逻辑操作  
        serviceBean.doSomething1();  }  
}  

执行main方法,发现doSomething1()中调用doSomething2()方法的时候并未去执行CustomerServiceProxy类的doBefore()方法。其实doSomething2()等同于this.doSomething2(),在CustomerServiceImpl类中this关键字表示的是当前这个CustomerServiceImpl类的实例,所以程序会去执行CustomerServiceImpl对象中的doSomething2()方法,而不会去执行CustomerServiceProxy类对象中的 doSomething2()方法。

在使用Spring AOP的时候,我们从IOC容器中获取的Bean对象其实都是代理对象,而不是那些Bean对象本身,由于this关键字引用的并不是该Service Bean对象的代理对象,而是其本身,因此Spring AOP是不能拦截到这些被嵌套调用的方法的。

解决方案

  1. 修改类,不要出现“自调用”的情况:这是Spring文档中推荐的“最佳”方案;
  2. 若一定要使用“自调用”,那么this.doSomething2()替换为:((CustomerService) AopContext.currentProxy()).doSomething2();此时需要修改spring的aop配置:
<aop:aspectj-autoproxy expose-proxy="true" />

 转自:https://www.jianshu.com/p/6534945eb3b5

转载于:https://www.cnblogs.com/ithfm/p/10281355.html


http://lihuaxi.xjx100.cn/news/252325.html

相关文章

【MATLAB】find 函数 总结

【MATLAB版本为2014a】 MATLAB中函数find函数的作用是进行矩阵元素的查找&#xff0c;它通常与关系函数和逻辑运算相结合。 indfind(X,...)&#xff1a;该函数查找矩阵中的非零元素&#xff0c;函数返回这些元素的双下标[row,col]find(X,...)&#xff1a;该函数查找矩阵X中的…

【青少年编程】【二级】货运飞船

「青少年编程竞赛交流群」已成立&#xff08;适合6至18周岁的青少年&#xff09;&#xff0c;公众号后台回复【Scratch】或【Python】&#xff0c;即可进入。如果加入了之前的社群不需要重复加入。 我们将有关编程题目的教学视频已经发布到抖音号21252972100&#xff0c;小马老…

nagios npc安装后状态为off的解决方法

1、检查ndo2db的进程是不是二个 nagios 16825 0.0 0.1 6784 396 ? Ss 19:05 0:00 /usr/local/nagios/bin/ndo2db -c /usr/l nagios 17032 0.0 0.3 6784 1268 ? S 19:09 0:00 /usr/local/nagios/bin/ndo2db -c 2、检查nagios.log日志看…

《精通 ASP.NET MVC 3 框架(第三版)》----第2章 准备工作 2.1 准备工作站

本节书摘来自异步社区《精通 ASP.NET MVC 3 框架&#xff08;第三版&#xff09;》一书中的第2章&#xff0c;第1节&#xff0c;作者&#xff1a; 【美】Adam Freeman , Steven Standerson&#xff0c;译者&#xff1a; 林逸 , 李萍 &#xff0c; 更多章节内容可以访问云栖社区…

【青少年编程(第31周)】一个有趣又有料的抖音号!

2021年09月19日&#xff08;周日&#xff09;晚20:00我们在青少年编程竞赛交流群开展了第三十一次直播活动。我们直播活动的主要内容如下&#xff1a; 首先&#xff0c;我们奖励了上周测试超过30分的小朋友。 其次&#xff0c;我们讲解了上次测试中小朋友们做错的题目Scratch青…

数理统计思维导图

推荐一款好的思维导图软件&#xff1a;幕布 https://mubu.com/inv/1289295

【译】表变量和临时表的比较(转)

关于表变量是什么&#xff08;和表变量不是什么&#xff09;&#xff0c;以及和临时表的比较让很多人非常困惑。虽然网上已经有了很多关于它们的文章&#xff0c;但我并没有发现一篇比较全面的。在本篇文章中&#xff0c;我们将探索表变量和临时表是什么&#xff08;以及不是什…

autoLayout

第一次使用自动布局&#xff0c;记录下来,或许以后用第三方用不到这个&#xff0c;但是第一次接触VFL语言。 一个按钮&#xff0c;不论横竖屏&#xff0c;都要在屏幕底部。 UIView *bottomV [[UIView alloc]init]; bottomV.backgroundColor [UIColor whiteColor];[bottomV se…