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

package demo.long;public interfaceCustomerService {public voiddoSomething1();public voiddoSomething2();

}

接口实现类如下:

package demo.long.impl;import demo.long.CustomerService;public class CustomerServiceImpl implementsCustomerService {public voiddoSomething1() {

System.out.println("CustomerServiceImpl.doSomething1()");

doSomething2();

}public voiddoSomething2() {

System.out.println("CustomerServiceImpl.doSomething2()");

}

}

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

package demo.long;importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.annotation.Before;

@Aspectpublic classCustomerServiceInterceptor {

@Before("execution(* demo.long..*.*(..))")public voiddoBefore() {

System.out.println("do some important things before...");

}

}

把Bean加到Spring配置中

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

public classCustomerServiceTest {

@Autowired

ICustomerService customerService;

@Testpublic voidtestAOP() {

customerService.doSomething1();

}

}

原因分析

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

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

public class CustomerServiceProxy implementsCustomerService {privateCustomerService customerService;public voidsetCustomerService(CustomerService customerService) {this.customerService =customerService;

}public voiddoSomething1() {

doBefore();

customerService.doSomething1();

}public voiddoSomething2() {

doBefore();

customerService.doSomething2();

}private voiddoBefore() {//例如,可以在此处开启事务或记录日志

System.out.println("do some important things before...");

}

}

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

public classTestProxy {public static voidmain(String[] args) {//创建代理目标对象//对于Spring来说,这一工作是由Spring容器完成的。

CustomerService serviceProxyTarget = newCustomerServiceImpl();//创建代理对象//对于Spring来说,这一工作也是由Spring容器完成的。

CustomerServiceProxy serviceProxy = newCustomerServiceProxy();

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是不能拦截到这些被嵌套调用的方法的。

解决方案

修改类,不要出现“自调用”的情况:这是Spring文档中推荐的“最佳”方案;

若一定要使用“自调用”,那么this.doSomething2()替换为:((CustomerService) AopContext.currentProxy()).doSomething2();此时需要修改spring的aop配置:

aop阻止方法运行_Spring AOP无法拦截内部方法调用相关推荐

  1. 计算机管理打开报mmc.exe,Win10打开软件提示“管理员已阻止你运行此应用mmc.exe”解决方法...

    Win10系统下,运行很多软件运行提示用户账户控制"为了对电脑进行保护,已经阻止此应用.管理员已经阻止你运行此应用.有关详细信息,请与管理员联系",关闭了防火墙也无法解决.那么遇到 ...

  2. 管理员已阻止你运行此应用——一步解决方法

    学校上课用的软件,下载下来进行安装,提示"用户账户控制 为了对电脑进行保护,已经阻止此应用 管理员已阻止你运行此应用.有关详情信息,请与管理员联系".尝试右键以管理员方式打开/关闭 ...

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

    假设一个接口里面有两个方法: package demo.long;public interface CustomerService { public void doSomething1(); publ ...

  4. java aop注解日志记录_spring aop通过注解实现日志记录

    首先是几个概念:连接点(Joinpoint).切点(Pointcut).增强(Advice).切面(Aspect) 另外也要使用到注解. 需求:通过注解定义LogEnable.然后程序运行能够识别定义 ...

  5. powermock跳过某方法_如何使用powermock验证内部方法调用?

    我尝试使用powermockito通过验证内部 审计() 方法调用. 此内部呼叫由 审计师 对象中正在实例化的 () 类的方法.因为它没有注射,我不能直接模仿它.当我用mock i to验证它时,它总 ...

  6. AOP、ASPECT、Spring AOP、JDK动态代理、CGLib动态代理

    AOP.ASPECT.Spring AOP.JDK动态代理.CGLib动态代理 1 AOP介绍 1.1 基本定义 AOP(Aspect Oriented Programming)称为面向切面编程,它是 ...

  7. springboot 调用方法事物_SpringBoot 内部方法调用,事务不起作用的原因及解决办法...

    在做业务开发时,遇到了一个事务不起作用的问题.大概流程是这样的,方法内部的定时任务调用了一个带事务的方法,失败后事务没有回滚.查阅资料后,问题得到解决,记录下来分享给大家. 场景 我在这里模拟一个场景 ...

  8. Spring,为内部方法新起一个事务,此处应有坑。

    事务的作用,使我们操作能够连贯起来.而spring则是提供了一个更简单的方法,只要使用 @Transactional 一个注解,就可以保证操作的连贯性了. 普通用法,稍后再说,这里要说的是: 在最外面 ...

  9. aop阻止方法运行_新型AOP高级氧化高浓度COD废水处理系统介绍

    AOP高级氧化高浓度COD废水处理系统,去除率90%-100%AOP高级氧化高浓度COD废水处理系统 1.AOP简介 高级氧化处理(AOP)是一套先进的化学处理过程,用于去除废水中的有机物和无机物. ...

最新文章

  1. Linux内核常见FAQ
  2. Py之BaseHTTPServer:Python库之BaseHTTPServer的简介、安装、使用方法之详细攻略
  3. 电子增稳云台_揭秘Dobby自拍无人机,电子增稳是黑科技?
  4. 微信生态下的营销洞察
  5. SWT实现Text输入自动提示
  6. larvel 中的api.php_laravel route api.php 与 web.php 的区别
  7. git依赖python_python爬虫之git的安装
  8. python创建列表副本的方法_Python之列表方法
  9. 拳王公社:网络操盘手必备的400款新媒体运营工具大全!
  10. object c中的多态
  11. 曾国藩论“慎独”:人生第一自强之道 寻乐之方
  12. wps白色背景设置为淡绿色保护眼睛预防眼疲劳
  13. 习题5-3 使用函数计算两点间的距离 (10 分)
  14. 应急响应中的入侵排查和权限维持
  15. GPU并行计算版函数图像生成器
  16. python读写、导入导出数据操作(简)
  17. 微信公众号怎样运营涨粉?
  18. 腾讯云上申请免费的安全证书--【域名身份验证】
  19. OAI网络切片三切片配置
  20. 计算机技术 食堂管理,食堂管理系统需求规格说明.doc

热门文章

  1. OpenCASCADE绘制测试线束:布尔运算命令之两个操作数的布尔运算
  2. wxWidgets:更新到最新版本的 wxWidgets
  3. boost::pfr::for_each_field相关的测试程序
  4. boost::histogram::detail::argument_traits用法的测试程序
  5. boost::graph模块演示 GGCL Vertex 接口
  6. boost::geometry::enrich_intersection_points用法的测试程序
  7. boost的chrono模块特殊值的测试程序
  8. VTK:图表之NOVCAGraph
  9. OpenCV放大图像:多输出
  10. c++Hash Search哈希搜索的实现算法(附完整源码)