1,原理
Spring通过代理实现事务管理;
Java中代理分为静态代理和动态代理两种;
静态代理主要是aspectJ,在编译阶段将增强代码加入到字节码中;
动态代理有jdk动态代理和cglib两种;
Jdk动态代理是在运行过程中生成被代理类的子类,并将增强代码加入到方法中;
Cglib动态代理是在运行过程中实现被代理接口的实例,并将增强代码加入到方法中;
Spring采用的是动态代理而不是静态代理;
实际的事务方法注册流程:
容器启动时,创建bean;在AbstractBeanFactory的createBean方法中,会调用resolveBeforeInstantiation[Bean处理器],看是否需要产生代理对象;
resolveBeforeInstantiation中,调用applyBeanPostProcessorsAfterInitialization方法处理,会循环调用所有bean的后置处理器的postProcessAfterInitialization方法;
处理事务注解的后置处理器是AbstractAdvisingBeanPostProcessor,在该类的postProcessAfterInitialization中,我们直接看isEligible(bean, beanName)方法,继续调用AopUtils.canApply方法,看是否是由pointcut驱动的advisor,如果是,那么会调用MethodMatcher的matches方法;对于@Transactional注解来说,会由TransactionAttributeSourcePointcut这个实现类来做match的工作,最终会找到AbstractFallbackTransactionAttributeSource这个类中的getTransactionAttribute
方法来看是否使用到该注解,这里的核心方法是computeTransactionAttribute;
computeTransactionAttribute逻辑:首先检查该方法是否是public修饰的,然后看该注解是在方法上使用的还是在类上使用的;
2,使用
在需要事务的方法上或者类上加上@Transacional注解即可;
3,事务失效场景
首先定义接口 I1,I2;
定义I1的普通方法I1m1,事务方法I1t1;
定义I2的普通方法I2m1,事务方法I2t1;
1)I1m1调用I1t1时,I1m1不属于事务;
2)I1m1调用I1t1时,如果是直接this调用I1t1,那么I1t1也没有事务,因为spring需要注入接口才能管理事务
3)I1t1或者I2t1不是public修饰的,那么事务失效;
4)I1t1调用I2t1,并且try了I2t1的异常;如果I2t1抛异常了,并且I2t1没有catch异常,那么程序会抛出Transaction rolled back because it has been marked as rollback-only
异常;因为I2t1抛异常时候,spring会将其标记为回滚,然后I1t1提交commit的时候,发现I2t1有异常,所以导致不能正提交事务,随即抛出该异常。