Spring实现事务管理的机制
Spring事务管理是基于AOP编程思想实现,Spring框架被广泛使用的原因之一,就是提供了强大的事务管理机制。
AOP是什么?我们常说的AOP并不是指一种开发技术,而是一种编程思想,AOP的核心概念就是面向切面编程,实现可插拔,降低程序之前的耦合性,提高重用性。
Spring AOP 基于动态代理实现,一种是JDK动态代理,另一种是CGLIB动态代理。
spring2.5之前声明式事务可以这样实现:
pointcut="execution(* com.junlong.demo.service.DemoService.*(..))"/>
在spring2.5之后声明式事务,增加了事务注解驱动,这样可以更灵活的控制在哪声明事务,并且Spring2.5之后的一个核心主题就是全面的支持注解方式
几个核心的注意事项
一、Spring事务管理基于动态代理的两种方式(JDKProxy、CGLIBProxy)
1.如果代理对象实现了接口则采用JDK动态代理实现,JDK动态代理基于接口进行代理的,它是通过在运行时创建一个接口的实现类来完成对目标对象的代理,所以使用@Transactional 注解的类想要基于JDK动态代理进行事务控制必须实现一个接口。
Spring默认会在JDK动态代理和CGLIB动态代理之间进行切换,如果被代理的类实现了接口则会使用JDK动态代理,否则会使用CGLIB动态代理。
如果想强制使用基于类的代理,可以设置proxy-target-class=true,这样Spring会使用CGLIB代理,在使用CGLIB代理时@Transactional必须写在具体的实现类上或者实现方法上,因为CGLIB动态代理是在运行时对代理对象进行继承扩展子类,所以声明final的类是无法使用CGLIB代理的。
Are class-based (CGLIB) proxies to be created? By default, standard
Java interface-based proxies are created.
Note: Class-based proxies require the @Transactional annotation to be
defined on the concrete class. Annotations in interfaces will not work
in that case (they will rather only work with interface-based proxies)!
]]>
2.官方文档介绍@Transactional 注解只有在public的方法上生效,这是因为Spring事务注解驱动是基于Spring AOP(也就是默认的方式是基于动态代理实现)实现的。
3.同一个java类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰,这也是因为Spring实现事务代理是默认是基于Spring AOP(也就是默认的方式是基于动态代理实现)实现的。
二、Spring事务管理实现的两种方式(动态代理、静态编织)
Should annotated beans be proxied using Spring's AOP framework,
or should they rather be weaved with an AspectJ transaction aspect?
AspectJ weaving requires spring-aspects.jar on the classpath,
as well as load-time weaving (or compile-time weaving) enabled.
Note: The weaving-based aspect requires the @Transactional annotation to be
defined on the concrete class. Annotations in interfaces will not work
in that case (they will rather only work with interface-based proxies)!
]]>
mode模式默认采用代理模式(mode="proxy"),在proxy模式中采用AOP的动态代理来进行事务管理,是在运行期间基于JDK动态代理或者GCLIB动态代理来实现,在代理模式中(mode="proxy")只有A类中方法调用另外一个B类声明@Transactional的方法才会被代理截获进行事务控制,在A类本类中调用本类的其他带有@Transactional的方法不会经过动态代理。
然而mode="aspectj"则采用静态编织的方式(aspectj是一种编译技术)其需要spring-aspects.jar,是在编译期间或者载入期间对代理对象进行修改字节码织入事务实现,所以不管你的方法的可见度(public、private)是什么都可以实现事务管理,这跟proxy动态代理是完全不同的。
,其实是