问题

在spring 中使用 @Transactional 、 @Cacheable 或 自定义 AOP 注解时,对象内部方法中调用该对象的其他使用aop机制的方法会失效。

     @Transactional
    public void saveFile(FileDetail sourceFile, FileDetail targetFile, FileRelation fileRelation) {

            sourceFile = fileDao.queryFileByMd5(sourceFile.getMd5());
            fileDao.insertFile(sourceFile);
            fileRelationDao.insertFileRelation(fileRelation);
            sendMessage();
    }

    public void sendMessage(){
        System.out.println("打日志");
        System.out.println("发送消息...");
    }
    

在同一个类中的方法级别调用也会导致 aop 注解失效

原因

Spring AOP使用JDK动态代理和CGLib,由于没有接口的类,所以使用CGLib代理。当方法被代理时,其实通过动态代理生成了代理对象,然后代理对象执行invoke方法,在调用被代理对象的方法时,执行其他操作。问题就在于被代理对象的方法中调用被代理对象的其他方法时,使用的是被代理对象本身,而非代理对象。这就导致了一个方法时代理对象调用的,一个是被代理对象调用的。他们的调用始终不出于同一个对象。

实例

(1)当我们调用saveFile(),spring的动态代理会动态生成一个代理对象(serviceFile)。
(2)当我们调用saveFile的时候实际上是serviceFile调用。
(3)当调用saveFile()方法内调用同一个类的另外一个注解方法sendMessage时,实际上是使用this.saveFile(),而this指当前对象而非代理对象,所以注解失效。

解决方案

通过AopContext.currentProxy()获取当前代理对象。

1.AopContext.currentProxy();

2.修改 xml

     @Transactional
    public void saveFile(FileDetail sourceFile, FileDetail targetFile, FileRelation fileRelation) {

            sourceFile = fileDao.queryFileByMd5(sourceFile.getMd5());
            fileDao.insertFile(sourceFile);
            fileRelationDao.insertFileRelation(fileRelation);
            (FileService)AopContext.currentProxy().sendMessage();
    }

    @Transactional
    public void sendMessage(){
        System.out.println("打日志");
        System.out.println("发送消息...");
    }
    

配置

   <tx:annotation-driven transaction-manager="transactionManager"/>
<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSourceForSqlServer" />
</bean>

注意事项

1.在需要事务管理的地方加@Transactional 注解。@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上 。
2.@Transactional 注解只能应用到 public 可见度的方法上 。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会展示已配置的事务设置。
3.注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据。必须在配置文件中使用配置元素,才真正开启了事务.
4.spring事物是基于类和接口的所以只能在类里面调用另一个类里面的事物,同一个类里面调用自己类的事物方法是无效的。spring事物也不要频繁使用,在事物处理的同时操作的第一张表会被限制查看的(即被临时锁住)。数据量大的时候会有一定影响。

参考

[1][spring aop注解失效之谜](http://blog.csdn.net/u012373815/article/details/77345655)
[2][Spring @Transactional事物配置无效原因](http://blog.csdn.net/weitao233136/article/details/51841707)
[3][Does Spring @Transactional attribute work on a private method?](https://stackoverflow.com/questions/4396284/does-spring-transactional-attribute-work-on-a-private-method)

Spring aop注解失效的更多相关文章

  1. Spring AOP注解为什么失效?90%Java程序员不知道

    使用Spring Aop注解的时候,如@Transactional, @Cacheable等注解一般需要在类方法第一个入口的地方加,不然不会生效. 如下面几种场景 1.Controller直接调用Se ...

  2. spring aop注解方式与xml方式配置

    注解方式 applicationContext.xml 加入下面配置 <!--Spring Aop 启用自动代理注解 --> <aop:aspectj-autoproxy proxy ...

  3. spring aop注解配置

    spring aop是面向切面编程,使用了动态代理的技术,这样可以使业务逻辑的代码不掺入其他乱七八糟的代码 可以在切面上实现合法性校验.权限检验.日志记录... spring aop 用的多的有两种配 ...

  4. Spring AOP 注解和xml实现 --转载

    AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向切面编程.可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术. ...

  5. spring Aop 注解

    个人理解: spring Aop 是什么:面向切面编程,类似于自定义拦截操作,支持拦截之前操作@Before,拦截之后操作@After,拦截环绕操作@Around. 什么情况下使用spring Aop ...

  6. Spring aop 注解参数说明

    在spring AOP中,需要使用AspectJ的切点表达式语言来定义切点. 关于Spring AOP的AspectJ切点,最重要的一点是Spring仅支持AspectJ切点指示器(pointcut ...

  7. 【学习笔记】Spring AOP注解使用总结

    Spring AOP基本概念 是一种动态编译期增强性AOP的实现 与IOC进行整合,不是全面的切面框架 与动态代理相辅相成 有两种实现:基于jdk动态代理.cglib Spring AOP与Aspec ...

  8. spring事务注解失效问题

    问题描述: 由于工作需要,需要在spring中配置两个数据源,有一天突然发现@Transactional注解失效 环境框架: springmvc+spring+spring jdbcTemplate ...

  9. 6.spring:AOP(注解)

     spring Aop AOP面向切面编程,与OOP面向对象编程相辅相成 AOP中最基本的单元是切面 问题: 代码混乱:越来越多的业务需求(日志&验证)加入后,原有的业务方法急剧膨胀,每个方法 ...

随机推荐

  1. Drools规则引擎-memberOf操作

    场景 规则引擎技术讨论2群(715840230)有同学提出疑问,memberOf的使用过程中如果,memberOf之后的参数不是集合也不是数组,而是格式如"1,2,3,4"的字符串 ...

  2. 基于go语言结合微信小程序开发的微商城系统

    最近在慕课网上录制了一门<Golang微信小程序微商城系统原型>,这门免费课程特别适合在校大学生或者刚毕业的大学生,go语言初学者以及想要从事微商城开发项目入门的小伙伴们来学习.在课程当中 ...

  3. centos7 添加用户,组

    centos7添加用户,组. groupadd projectUsers //添加组,组名projectUser. cat /etc/group //查看最后一行是projectUser. 添加用户并 ...

  4. JS时间处理,获取天时分秒。以及浏览器出现的不兼容问题

    //获取时间的天,小时,分钟,秒 function ToTime(second) { second = second / ; var result ; ) % ; ) % ; * )); ) { re ...

  5. Android调试移动端webview

    尝试了各种Mac版本的安卓模拟器,包括Android Studio.Genymotion以及国内的网易MuMu.夜神.蓝叠.腾讯手游助手,做的最好的是Android Studio,最难上手的也是And ...

  6. 【SpringCloud】Ribbon如何自定义客户端配置和全局配置

    起因 事情的起因是这样的,公司内部要实现基于Zuul网关的灰度路由,在上线时进行灰度测试,故需要配置业务微服务向Eureka注册的metadata元数据,和自定义Ribbon的负载规则达到只访问灰度服 ...

  7. 「PowerBI」Tabular Editor 一个对中文世界很严重的bug即将修复完成

    之前介绍过Tabular Editor这款开源工具,对PowerBI建模来说,非常好用,可以极大的增强自动化水平. 详细可查看此文章: 「PowerBI相关」一款极其优秀的DAX建模工具Tabular ...

  8. C#7.2 新增功能

    连载目录    [已更新最新开发文章,点击查看详细] C# 7.2 又是一个单点版本,它增添了大量有用的功能. 此版本的一项主要功能是避免不必要的复制或分配,进而更有效地处理值类型. C# 7.2 使 ...

  9. 在Ubuntu中安装Docker和docker的使用

    1.在Ubuntu中安装Docker 更新ubuntu的apt源索引 sudo apt-get update 安装包允许apt通过HTTPS使用仓库 sudo apt-get install \ ap ...

  10. MySQL不停地自动重启怎么办

    近期,测试环境出现了一次MySQL数据库不断自动重启的问题,导致的原因是强行kill -9 杀掉数据库进程导致,报错信息如下: --24T01::.769512Z [Note] Executing ' ...