对于像我这种喜欢滥用AOP的程序员,遇到坑也是习惯了,不单单是事务,其实只要脱离了Spring容器管理的全部对象,对于SpringAOP的注解都会失效,由于他们不是Spring容器的代理类,SpringAOP,就切入不了程序员
固然可使用原生ASPECTJ,不用SpringAOP,可是基于生态链问题,仍是尽可能使用SpringAOPide
这里简单说一下,Spring如何选择使用CGLIB,或者是JDK代理,this
简单来讲,若是实现了某个接口,那么Spring就选择JDK代理(不必定),若是没有,那么就选择CGLIB代理,提及来简单,Spring还会闹脾气,不代理呢spa
一直以来比较多的状况是在Controller 调用Service 的方法,把事务直接在Service的方法上,妥妥的没问题,事务正常执行.net
考虑如下问题: 同对象的方法B 调用本身的方法A,这里的事务将会失效(严格上来讲,只要对方法A使用注解AOP均会失效),缘由是由于这里的this.调用的并非Spring的代理对象代理
@Service public class ClassA{ @Transactional(propagation = Propagation.REQUIRES_NEW) public void methodA(){ } /** * 这里调用methodA() 的事务将会失效 */ public void methodB(){ this.methodA(); } }
最简单的解决方法为:(代理模式为JDK 的状况下(根据接口代理))code
@Service public class ClassA extends BaseClass{ @Transactional(propagation = Propagation.REQUIRES_NEW) @Override public void methodA(){ } /** * 这里调用methodA() 的事务将会失效 */ public void methodB(){ //使用getBean ((BaseClass)SpringUtil.getBean("classA")).methodA(); } }
解决第一步: 必须对象
SpringBoot:注解开启cglib代理,开启 exposeProxy = true,暴露代理对象 (不然AopContext.currentProxy()) 会抛出异常blog
@EnableAspectJAutoProxy(exposeProxy = true) public class Application{ public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
配置方式:配置方式下,我用的是SpringBoot 1.5.4没有找到exposeProxy的选项,因此建议使用注解式.接口
传统Spring配置文件
XML
<aop:aspectj-autoproxy expose-proxy="true"/>
第二步(须要保证Spring对这个bean建立了代理对象,基本上涉及到Aop的方法的类,都会建立代理对象) 能够用如下代码判断
/** * Created by laizhenwei on 19:37 2017-10-14 */ @Service("classImplProxy") @Scope(proxyMode = ScopedProxyMode.INTERFACES) public class ClassImplProxy implements IClass { @Override @Transactional public void sysout() { } //是否代理对象 @Override public boolean isAopProxy() { return AopUtils.isAopProxy(AopContext.currentProxy()); } //是否cglib 代理对象 @Override public boolean isCglibProxy() { return AopUtils.isCglibProxy(AopContext.currentProxy()); } //是否jdk动态代理 @Override public boolean isJdkDynamicProxy() { return AopUtils.isJdkDynamicProxy(AopContext.currentProxy()); } }
获取代理对象
@Service public class ClassA{ @Transactional(propagation = Propagation.REQUIRES_NEW) public void methodA(){ } public void methodB(){ //手动获取此对象Spring的代理类 ((ClassA)AopContext.currentProxy()).methodA(); } }
直接在当前类@Autowire 或者@Resource 注入本身,而后用注入的bean 调用方法