问题

在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. CTSC&APIO被教做人记

    DAY 0: 早早起来从衡水出发,在去火车站的路上明白了HZOI总是差点误车的真相……上了绿皮火车之后由于没网没流量就开始看政治书应付学考,然而并不是很能看进去,感觉初中学的比高中学的不知道高到哪里去 ...

  2. android_MultiAutoCompleteTextView

    package cn.com.sxp;import android.app.Activity;import android.os.Bundle;import android.view.View;imp ...

  3. Java面试题汇总---基础版(附答案)

    基于我个人对面试的认知和招聘经验,在此我总结一下Java开发者的基础知识掌握要求,及应聘者面试的需要准备的内容. 首先,Java基础是每个面试官都会问到的,可能只是针对工作经验的多少,对问题追踪深度有 ...

  4. Lucene05-分词器

    Lucene05-分词器 1.概念 Analyzer(分词器)的作用是把一段文本中的词按规则取出所包含的所有词.对应的是Analyzer类,这是一个抽象类,切分词的具体规则是由子类实现的,所以对于不同 ...

  5. Java 8 终于支持 Docker!

    Java 8曾经与Docker无法很好地兼容性,现在问题已消失. 请注意:我在本文中使用采用GNU GPL v2许可证的OpenJDK官方docker映像.在Oracle Java SE中,这里描述的 ...

  6. C#3.0新增功能09 LINQ 基础04 基本 LINQ 查询操作

    连载目录    [已更新最新开发文章,点击查看详细] 本篇介绍 LINQ 查询表达式和一些在查询中执行的典型操作. 获取数据源 在 LINQ 查询中,第一步是指定数据源. 和大多数编程语言相同,在使用 ...

  7. 关于C#多线程、易失域、锁的分享

    一.多线程 windows系统是一个多线程的操作系统.一个程序至少有一个进程,一个进程至少有一个线程.进程是线程的容器,一个C#客户端程序开始于一个单独的线程,CLR(公共语言运行库)为该进程创建了一 ...

  8. org.mybatis.spring.MyBatisSystemException异常及处理

    org.mybatis.spring.MyBatisSystemException异常处理 测试场景 在测试springboot中使用MyBatis/通用Mapper的自定义方法时出现此异常. 异常如 ...

  9. spring使用thymeleaf

    一.spring使用thymeleaf做解析器其实很简单,这是基于xml配置的方式 <?xml version="1.0" encoding="UTF-8" ...

  10. 敏捷和DevOps:是敌是友?

    DevOps是敏捷在软件开发团队的另一应用.那么相比之下,哪个更胜一筹? 一边,有业界认可的scrum master,它的朋友极限编程者,以及由其衍生的 LeSS.SAFe.DAD等,是敏捷. 另一边 ...