我们看下@EnableTransactionManagement注解的源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
// 忽略注释
boolean proxyTargetClass() default false;
// 忽略注释
AdviceMode mode() default AdviceMode.PROXY;
// 忽略注释
int order() default Ordered.LOWEST_PRECEDENCE;
}
其主要拥有三个方法,并且每个方法都有默认的值。通常情况下,我们使用@EnableTransactionManagement注解时,并不会额外的指定内部方法的返回值,用的都是默认值。那这三个方法的返回值具体有什么作用呢?请看下图:
具体什么时候会用到,我们后面会说到。
套路与@EnableAspectJAutoProxy
注解类似,都是向Spring导入了一个TransactionManagementConfigurationSelector组件,它是属于ImportSelector类型。我们来看下它的源码:
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
// 这个adviceMode就是我们在使用@EnableTransactionManagement注解时内部的model()方法的返回值
// 我们没有操作过@EnableTransactionManagement注解内部所有方法的返回值,因此,这里的adviceMode
// 的值为 “PROXY”
switch (adviceMode) {
case PROXY:
// 最终会执行这段代码,向Spring容器添加了两个bean,分别为:
// AutoProxyRegistrar和ProxyTransactionManagementConfiguration
// 要想了解Spring的底层原理,那现在就要看AutoProxyRegistrar和ProxyTransactionManagementConfiguration咯
return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
我们先来看看它是什么类型:
根据类的继承图可知,它属于ImportBeanDefinitionRegistrar类型,Spring最终会调用内部的registerBeanDefinitions方法,下述是源码中比较关键的代码:
if (mode == AdviceMode.PROXY) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
上文有说到,我们在使用@EnableTransactionManagement注解时,并没有特意去修改内部方法的返回值。因此,这里的mode就是AdviceMode.PROXY,proxyTargetClass为false。由源码逻辑可知:Spring最终会执行这段代码:AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
而这段代码的主要功能就是向Spring容器中添加这个bean:InfrastructureAdvisorAutoProxyCreator。那我们接下来该干嘛呢?是的,该看这个bean (InfrastructureAdvisorAutoProxyCreator)有什么样的作用了。
同理,咱们先来看下它的继承图:
我们着重看图中红框框中的类。然后我们再来看下在启用Spring AOP的注解@EnableAspectJAutoProxy内部导入的AnnotationAwareAspectJAutoProxyCreator bean的类继承图:
他们都实现了同一个公共抽象类:AbstractAutoProxyCreator。这说明什么?这说明了只要AnnotationAwareAspectJAutoProxyCreator和InfrastructureAdvisorAutoProxyCreator内部没有对AbstractAutoProxyCreator这个抽象父类做任何方法的重写的话,那他们就是拥有了AbstractAutoProxyCreator的功能。
实际上呢,他们确实是没有重写AbstractAutoProxyCreator内部的任何方法。在Spring AOP原理篇:我用上我的洪荒之力来帮你彻底了解aop注解@EnableAspectJAutoProxy的原理的文章中有提到,整个Spring AOP寻找切面、切面、通知的过程就是此方法InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation的功劳,而生成AOP代理对象就是BeanPostProcessor#postProcessAfterInitialization的功劳。而这些寻找切面、生成代理对象的功能其实是抽象父类AbstractAutoProxyCreator的功能。因此,我们的InfrastructureAdvisorAutoProxyCreator具备了寻找切面、切面、通知以及生成代理对象的功能了。
老规矩,先看类的继承图:
这个类倒比较简单了,它也使用到了Spring的一些扩展点,虽然父类也有构建一些Spring的组件,但最终要的是ProxyTransactionManagementConfiguration内部构建了一个叫BeanFactoryTransactionAttributeSourceAdvisor的bean。ProxyTransactionManagementConfiguration的源码如下所示:
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
// 主要是这个bean
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
// 内部维护了事务相关的属性源
advisor.setTransactionAttributeSource(transactionAttributeSource());
// 内部维护了执行事务时的拦截器,后续会依赖这个拦截器来开启、提交/回滚事务
// 当调用拥有事务的方法时,最终会调用到此拦截器内部的invoke方法
advisor.setAdvice(transactionInterceptor());
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
按照惯例,我们来看看这个bean:BeanFactoryTransactionAttributeSourceAdvisor的信息。
老规矩,我们来看它的类继承图:
可以发现,它属于Advisor类型。这个时候,我们回忆一下Spring AOP在查询切面、切点、通知的时候,是不是存在一个寻找Advisor的过程?如果你记不清了没关系,我们再来温故下。继续选用上篇文章使用过的图:
其中有一段寻找实现了Advisor接口的逻辑,其部分代码如下所示:
// 方法坐标:org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
public List<Advisor> findAdvisorBeans() {
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// 查找出spring容器中类型为advisor类型的bean
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}
//.... 省略 遍历所有bean,寻找带有@Aspectj注解的bean并解析bean的过程 逻辑。
}
还记得这个方法吗?这个方法就是找到我们所有的切面,并解析成一个个的Advisor。而在寻找事务切面的过程中,并没有遍历所有的bean,因为我们的@EnableTransactionManagement注解已经向spring容器中导入了一个Advisor了。因此,对于在寻找事务切面的过程而言,事务的性能更好一点。因为,它省去了遍历所有bean的过程,在使用@EnableTransactionManagement注解时已经自动为我们导入了一个类型为Advisor的bean。