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);
// 剩余源码省略 ...
}
}
}
|
从上面源码中可以看到,分别注册了 TransactionAttributeSource
、MethodInterceptor(也是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中具体有哪些方法,执行了哪些行为,在声明式事务执行流程源码分析中会详细列出。