Spring事务处理流程
这里讲述的是以@Transactional注解方式配置Spring事务的原理。
我们启用事务注解的时候,往往配置如下:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
在Spring中,annotation-driven是用来开启注解支持的,前面添加名字空间,如tx:或者mvc:之类的,后面可以选填一些属性,这是我们需要了解的,具体属性值情况如下:
1、transaction-manager:指定到现有的PlatformTransactionManager bean的引用,通知会使用该引用。默认值为"transactionManager"
2、mode:指定Spring事务管理框架创建通知bean的方式。可用的值有proxy和aspectj。默认值为proxy,表示通知对象是个JDK代理;后者表示Spring AOP会使用AspectJ创建代理。
3、order:指定创建的切面的顺序。只要目标对象有多个通知就可以使用该属性。
4、proxy-target-class:该属性如果为true就表示你想要代理目标类而不是bean所实现的所有接口。默认值为"false" 。
先来看看下面的Spring是如何处理<tx:annotation-driven transaction-manager="txManager" />标签的,先是org.springframework.beans.factory.xml.BeanDefinitionParserDelegate来处理标签,通过parseCustomElement()方法找到对应名字空间处理器,也即org.springframework.transaction.config.TxNamespaceHandler这个类来处理tx名字空间的标签的:
public class TxNamespaceHandler extends NamespaceHandlerSupport {
static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";
static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
static String getTransactionManagerName(Element element) {
return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
}
@Override
public void init() {
registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}
}
真正处理的类型是org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser,具体的方法如下:
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
registerTransactionalEventListenerFactory(parserContext);
String mode = element.getAttribute("mode");
if ("aspectj".equals(mode)) {
// mode="aspectj"
registerTransactionAspect(element, parserContext);
}
else {
// mode="proxy"
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
}
return null;
}
这里我们使用的是默认mode="proxy",也就是使用jdk提供的代理方式,这个函数始终返回null这点要注意。那么现在就要看看AnnotationDrivenBeanDefinitionParser中的静态内部类中的configureAutoProxyCreator()方法做了什么,这里也可以借鉴下使用静态内部类的情景,这个静态内部类只有一个静态方法,显然作者这里更多的体现的是封装思想以及面向对象编程思想。
private static class AopAutoProxyConfigurer {
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
Object eleSource = parserContext.extractSource(element);
// 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);
// Create the TransactionInterceptor definition.
RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
interceptorDef.setSource(eleSource);
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registerTransactionManager(element, interceptorDef);
interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
// 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);
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
parserContext.registerComponent(compositeDef);
}
}
}
这里看到通过硬编码的方式实例化了几个类到IOC容器中。
推荐阅读
-
Spring5源码解析5-ConfigurationClassPostProcessor (上)
-
spring5 源码深度解析----- AOP代理的生成
-
Spring5源码解析4-refresh方法之invokeBeanFactoryPostProcessors
-
Spring Boot Security OAuth2 实现支持JWT令牌的授权服务器
-
spring boot2.0.4集成druid,用jmeter并发测试工具调用接口,druid查看监控的结果
-
JavaScript实现审核流程状态的动态显示进度条
-
网站建设的完整流程和步骤,新手必看
-
流程控制(if、while、for)
-
linux下日志定时轮询的流程详解
-
使用Spring boot + jQuery上传文件(kotlin)功能实例详解