声明式事务的注册入口

警告
本文最后更新于 2020-12-03,文中内容可能已过时。

spring源码系列文章,示例代码的中文注释,均是 copy 自 https://gitee.com/wlizhi/spring-framework

链接中源码是作者从 github 下载,并以自身理解对核心流程及主要节点做了详细的中文注释。


事务以xml配置方式使用时,xml是怎么解析,并将事务功能注册到容器中的?注解方式启动时,是怎么扫描注解将事务功能注册到容器中的?本文给出了详细的解析。

1 Xml方式

xml方式开启事务注解,是使用 <tx:annotation-driven/> 标签。根据 SPI 加载的规律,找到 spring-tx 包下的 spring.handlers 文件。

内容如下:

1
http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler

在 TxNamespaceHandler.init() 中,注册了事务相关标签的解析支持。

init() 源码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class TxNamespaceHandler extends NamespaceHandlerSupport {
    public void init() {
		// advice通知方法有关的,<tx:advice /> <tx:attributes /> <tx:method /> 标签支持在这里。
		registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
		// <tx:annotation-driven /> 解析支持
		registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
		// 可以不看。
		registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
	}
}

着重看 <tx:annotation-driven /> 标签的解析类,<tx:advice /> 解析支持原理类似。

直接来到方法 parse():

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
   public BeanDefinition parse(Element element, ParserContext parserContext) {
   		// 当前方法注册了InfrastructureAdvisorAutoProxyCreator  Infrastructure-->基础设施,优先级最低。
   		// 注意:区分@Aspect以及<aop:aspectj-autoproxy/>:两者注册的是AnnotationAwareAspectJAutoProxyCreator,最终按照优先级来确定使用哪个的。
   		
   		// 注册事务事件监听器,@TransactionalEventListener注解的支持。可以不看。
   		registerTransactionalEventListenerFactory(parserContext);
   		String mode = element.getAttribute("mode");
   		// 根据mode的值,来确定注册哪种类型的事务支持。这个不常用,可以不看。着重看else里面的内容。
   		if ("aspectj".equals(mode)) {
   			// mode="aspectj"
   			registerTransactionAspect(element, parserContext);
   			if (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader())) {
   				registerJtaTransactionAspect(element, parserContext);
   			}
   		}
   		else {
   			// TODO 默认值是proxy,主要看这个。
   			// mode="proxy"
   			AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
   		}
   		return null;
   	}
}

代码第一行注册了事务的事件监听,可以不看。

实际开发中,mode 属性基本不会配置,直接略过。默认值是 proxy。也就是说,会走到else代码块中。重点看 configureAutoProxyCreator()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
private static class AopAutoProxyConfigurer {

		public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
			// TODO 注册Advisor
			AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
			// 这里是一个常量,事务Advisor,等后面实例化时,如果匹配到方法,Advisor会封装到代理对象的执行链里面。
			String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
			if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
				Object eleSource = parserContext.extractSource(element);

				// 创建AnnotationTransactionAttributeSource的BeanDefinition,这是一个策略接口的实现。用于获取事务注解的属性值。
				// Create the TransactionAttributeSource definition.
				RootBeanDefinition sourceDef = new RootBeanDefinition(
						"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
				sourceDef.setSource(eleSource);
				sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

				// 创建对应的MethodInterceptor,这是事务的方法拦截器,最终在生成代理的时候,会缓存到AdvisedSupport中,第一次调用执行生成执行链的时候,
				// 如果匹配对应的方法,就会将方法名-MethodInterceptor的映射关系存储到执行链。同样是缓存到AdvisedSupport中。
				// Create the TransactionInterceptor definition.
				RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
				interceptorDef.setSource(eleSource);
				interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				// 注意,这里只注入了一个名字,PlatformTransactionManager需要我们手动注入到容器,在创建TransactionInterceptor时,会通过getBean()来获取
				registerTransactionManager(element, interceptorDef);
				interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
				String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

				// 创建BeanFactoryTransactionAttributeSourceAdvisor的BeanDefinition,并注册到registry中。当bean在实例化,
				// 查找容器中所有的增强方法时,会对所有的@Aspect封装成Advisor并实例化,以及直接注入进来的Advisor提前实例化,缓存到AdvisedSupport中。
				// 从接口层面说,这里创建一个Advisor。
				// Create the TransactionAttributeSourceAdvisor definition.
				RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
				advisorDef.setSource(eleSource);
				advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
				advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
				if (element.hasAttribute("order")) {
					advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
				}
				parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
                // 剩余源码省略 ...
			}
		}
	}

从上面源码中可以看到,分别注册了 TransactionAttributeSourceMethodInterceptor(也是Advice)Advisor的BeanDefinition对象,其中后面两个是利用AOP模块功能生成动态代理的关键接口。 而 TransactionAttributeSource 是对事务属性解析的支持。

这些动作是在解析标签的时候做的,然后经历 BeanFactoryPostProcessor 的后置方法执行、以及 BeanPostProcessor 的注册之后,最终执行到将BeanDefinition中封装的类信息实例化时,会创建上面源码中注册的三个实例。 而在创建实例、依赖注入、执行完bean的初始化方法后,最终会执行到 BeanPostProcessor.postProcessAfterInitialization(),而 AbstractAutoProxyCreator(也是一个BeanPostProcessor) 的子类(激活了自动代理功能), 会搜集beanDefinitions中所有的Advisor类型的beanDefinition,对其实例化,封装到AdvisedSupport中,如果对象需要被代理,则会将AdvisedSupport封装到代理对象中。最终在调用代理对象方法的时候,会生成代理方法的执行链。

由于 TransactionInterceptor 实现了 InitializingBean。在bean实例化完成后,会调用 afterPropertiesSet(),来看一下这个方法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
   @Override
   	public void afterPropertiesSet() {
   		// 开启事务支持,那么PlatformTransactionManager和TransactionAttributeSource这两个实例是必须有的,否则启动就会抛出异常。
   		if (getTransactionManager() == null && this.beanFactory == null) {
   			throw new IllegalStateException(
   					"Set the 'transactionManager' property or make sure to run within a BeanFactory " +
   					"containing a PlatformTransactionManager bean!");
   		}
   		if (getTransactionAttributeSource() == null) {
   			throw new IllegalStateException(
   					"Either 'transactionAttributeSource' or 'transactionAttributes' is required: " +
   					"If there are no transactional methods, then don't use a transaction aspect.");
   		}
   	}
}

从源码中可以看到,如果开启了事务功能,PlatformTransactionManager、TransactionAttributeSource是必不可少的,否则容器启动就会抛出异常。

而在上面源码中,TransactionAttributeSource已经设置了,而PlatformTransactionManager只注册了一个beanName, 这需要我们指定注入到ioc容器中。例如传统spring项目中使用的 DataSourceTransactionManager 就是使用bean标签注入的。

题外话:之所以 springboot 中我们不用创建 PlatformTransactionManager,是因为 auto-configuration 模块,使用 SPI 的方式,导入了 DataSourceTransactionManagerAutoConfiguration。

从下面代码就可以看出,TransactionInterceptor中仅仅注册了一个PlatformTransactionManager的beanName:

1
2
3
4
5
6
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
    private static void registerTransactionManager(Element element, BeanDefinition def) {
		def.getPropertyValues().add("transactionManagerBeanName",
				TxNamespaceHandler.getTransactionManagerName(element));
	}
}

2 注解方式

在使用注解方式激活@Transaction支持时,使用的是@EnableTransactionManagement,在这个注解声明中可以看到,使用了@Import导入TransactionManagementConfigurationSelector。

源码如下:

1
2
3
4
5
6
7
8
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// TODO 重点:事务注册入口类
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
// 省略...
}

在spring容器启动时,就会加载TransactionManagementConfigurationSelector,调用 selectImports(),在这个方法中,就添加了两个类的支持。

selectImports() 源码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				return new String[] {AutoProxyRegistrar.class.getName(),
						ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {determineTransactionAspectClass()};
			default:
				return null;
		}
	}
}

从上面源码中可以看到,共添加了两个类,主要看 ProxyTransactionManagementConfiguration 这个类。

在这个类中,定义了三个方法,使用@Bean,向容器中注入了BeanFactoryTransactionAttributeSourceAdvisor、TransactionInterceptor、AnnotationTransactionAttributeSource。这三个分别是Advisor、Advice(MethodInterceptor)、TransactionAttributeSource的实现类。

源码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
		// 事务切面类
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource());
		advisor.setAdvice(transactionInterceptor());
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		// TODO 事务属性解析类
		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;
	}

}

xml方式注入中,也是像容器中注入了这几个类。同样创建的流程也都是一样的。

接着看一下 AnnotationTransactionAttributeSource,在创建实例的时候,封装了对@Transactional的支持。

来到构造方法源码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
		implements Serializable {
	// 步骤一
	public AnnotationTransactionAttributeSource() {
		this(true);
	}

	// 步骤二
	public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
		// 这里注入了注解解析类。 SpringTransactionAnnotationParser,解析时就用到的这个类中的方法
		this.publicMethodsOnly = publicMethodsOnly;
		if (jta12Present || ejb3Present) {
			this.annotationParsers = new LinkedHashSet<>(4);
            // TODO 重点看这里
			this.annotationParsers.add(new SpringTransactionAnnotationParser());
			if (jta12Present) {
				this.annotationParsers.add(new JtaTransactionAnnotationParser());
			}
			if (ejb3Present) {
				this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
			}
		}
		else {
			this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
		}
	}
}

在构造方法中,封装了SpringTransactionAnnotationParser对象。

这个类是对@Transactional注解的支持,在bean实例化完成之后,调用代理方法执行时,首先会生成执行链,然后按照索引顺序递归调用执行链。 在调用到事务的节点时,会获取事务属性对象,通过事务属性来被代理方法中@Transactional注解中配置的属性值。以此来判断是否开启事务、以及设置事务隔离级别、传播行为等属性值。

SpringTransactionAnnotationParser中具体有哪些方法,执行了哪些行为,在声明式事务执行流程源码分析中会详细列出。