本文参考:《Spring源码深度解析》及源码走读.培养源码阅读思想
文章目录
先放图,du害一下大家,
1.必须懂的几个类
试想一下,如果Connection支持事务提交回滚(底层支持),那么你如何来设计你的事务处理框架?
我相信很多人的想法都是
- 先读取 @Transation注解的属性.生成一个对象(存放事务相关)
- 根据得到的该对象进行事务的commit,失败回滚,最终事务清除.
Spring框架对事务的支持大概也是这样的步骤,Spring支持嵌入事务,即方法中嵌套方法,如果都支持事务,则在里面的事务结束或者失败之后,外面的事务继续执行.
我们刚才提到 @Transation注解的属性提取,那么必定需要这样一个类去做提取的操作,提取的对象存储也需要一个相应类,用什么方式执行事务,这些都是我们后面需要讨论的内容,但是,在此之前,我们先看几个类,我们已经知道了实现事务的大概步骤,那么我们需要来看一下,Spring怎么去实现这些步骤的.
2.1 提取器驱动(装载)的advisor:BeanFactoryTransactionAttributeSourceAdvisor
我们知道Spring框架大量的使用了接口,可以想象,对于 @Transation注解的提取,Spring必定也是通过接口的实现类来定义提取方法(下一个会讲到),所以我们可以想象,我们需要一个类来承接这些接口和其他的属性.我们这里要讲的就是这个类。
我们看一下类上的注解:
- Advisor driven by a TransactionAttributeSource, used to include a transaction advice bean for methods that are transactional.
包含一个 TransactionAttributeSource,用于事务通知。我们暂且不管 TransactionAttributeSource类的作用,目前我们可以知道的就是BeanFactoryTransactionAttributeSourceAdvisor他会装载和提供一个 TransactionAttributeSource类。
我们看他是怎么实现 TransactionAttributeSource的。
@SuppressWarnings("serial")
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
//这个就是我们念念不忘的TransactionAttributeSource
private TransactionAttributeSource transactionAttributeSource;
//因为BeanFactoryTransactionAttributeSourceAdvisor 继承了PointCut接口,所以需要实现getPointCut方法
//而获取到的PointCut类会返回我们需要的TransactionAttributeSource。
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
很容易我们看到了TransactionAttributeSource 这个类,并且因为BeanFactoryTransactionAttributeSourceAdvisor继承了Pointcut接口,需要实现getPointcut方法,相当于是
通过得到PointCut实现类,再获取TransactionAttributeSource
2.2 @Transation注解元数据提取器:TransactionAttributeSource
@Transation的提取需要一定的规则,而不同的方式可能对应不同的规则,所以Spring利用接口的方式,制定提取的抽象。通过继承实现不同的提取规则。
首先你要知道 TransactionAttributeSource是一个接口,我们看一下类的描述
- Strategy interface used by TransactionInterceptor for metadata retrieval.
Implementations know how to source transaction attributes, whether from configuration, metadata attributes at source level (such as Java 5 annotations), or anywhere else.
提供给TransactionInterceptor拦截器用于事务元数据提取的接口.
但是接口需要实现类,因为是注解解析,这边的具体实现类是 AnnotationTransactionAttributeSource
作为一个注解提取器, AnnotationTransactionAttributeSource如何实现提取呢?
3.1 真实注解处理器:TransactionAnnotationParser
这边就给你答案,那就是TransactionAnnotationParser,看到该类的构造方法.必定会注入SpringTransactionAnnotationParser,这个类,这也是我们后面处理注解需要注意的。
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
this.publicMethodsOnly = publicMethodsOnly;
this.annotationParsers = new LinkedHashSet<TransactionAnnotationParser>(2);
this.annotationParsers.add(new SpringTransactionAnnotationParser());
if (jta12Present) {
this.annotationParsers.add(new JtaTransactionAnnotationParser());
}
if (ejb3Present) {
this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
}
}
2.3 事务执行器\拦截器:TransactionInterceptor
首先知道一点就是 ****实现了 MethodInterceptor接口,需要实现这个类的 invoke方法,事务处理的具体逻辑就在这里,而 MethodInterceptor又会在代理创建的时候被调用,所以我们基本知道该拦截器实现事务管理是通过invoke方法在代理的时候实现。
我们在后面的描述中会讲到具体实现,别着急
关注一下类上的注释:
- AOP Alliance MethodInterceptor for declarative transaction management using the common Spring transaction infrastructure (PlatformTransactionManager)
- TransactionInterceptors are thread-safe.
事务管理和线程安全
2. 事务管理入口
2.1 注解式
还记得开启事务的注解式什么吗?我错,我知道你不记得了。
开启事务的注解是 EnableTransactionManagement,我们可以查看一下这个注解的使用,
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
//实现事务的方式(proxy或者aspectj)
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
很好,我们看到这个注解有一个mode,能够配置事务管理实现的方式,默认是PROXY.
在注解上面有一个 @Import注解,如果你告诉我不懂,我就是一巴掌过去. @Import注解引入一个Selector类,我们要看一下他是做什么幺蛾子的。
3.1 事务管理选择器:TransactionManagementConfigurationSelector
这个注解继承了AdviceModeImportSelector,实现selectImport方法,朔本回源,在Mvc启动的时候会调用Selector,也就是这样启动的.这边我们不细究,知道一个大概:
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[] {
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
这里看到了AdviceMode 的选择,我们只分析PROXY的方式,不要问为什么,问就是我菜.
PROXY的方式会返回两个类:AutoProxyRegistrar和ProxyTransactionManagementConfiguration
幺蛾子就出在这里面.
4.1 注册代理构造器:AutoProxyRegistrar
这个类只有一个方法,这个方法会去注册一些BeanDefinition.
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
for (String annoType : annoTypes) {
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
if (mode == AdviceMode.PROXY) {
//重要的地方我只看到这里
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
}
虽然这个类叽里呱啦的说了一堆,但是重要的是这一行代码,这个方法会为我们注册一个很重要的类:InfrastructureAdvisorAutoProxyCreator,自动代理构造器,我们对于advisor的查找和代理的实现都在这个类中实现,后面我们会说道。
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAutoProxyCreatorIfNecessary(registry, null);
}
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
4.2 事务注解驱动配置:ProxyTransactionManagementConfiguration
这个类,会为我们注册几个Bean,就是我们一开头说的,事务注解元数据提取器、事务处理拦截器、提取器承载类
@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());
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) {
//事务管理器:PlatformTransactionManager
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
2.2 XML式
3.1 事务命名空间处理器:TxNamespaceHandler
这个类实现了NameSpaceHandler,Spring框架会实现NamespaceHandler接口实现类的调用,这个我们暂时不管他。
可以想象到,和注解处理的方式应该类似,这边也应该注入,我们刚才讲的三个类.所以我们来看一下代码实现
@Override
public void init() {
registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}
这边注册了三个BeanDefinitionParser的类,用屁股想象都知道,他大概想要去做什么事情,但是我们还是一个一个来看一下.
4.1 TxAdviceBeanDefinitionParser:注册事务注解提取器(或直接读取事务配置)
看到这边会去提取xml的元素,然后判断是否手动在XML中写入了事务相关属性,parseAttributeSource这个方法会去解析相关的属性(只读、超时时间…)
如果不是xml方式去注入的话,就需要去注册一个AnnotationTransactionAttributeSource,让这个类去提取**@Transational**上的属性,然后生成对应类.
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
builder.addPropertyReference("transactionManager", TxNamespaceHandler.getTransactionManagerName(element));
List<Element> txAttributes = DomUtils.getChildElementsByTagName(element, ATTRIBUTES_ELEMENT);
if (txAttributes.size() > 1) {
parserContext.getReaderContext().error(
"Element <attributes> is allowed at most once inside element <advice>", element);
}
else if (txAttributes.size() == 1) {
// Using attributes source.
Element attributeSourceElement = txAttributes.get(0);
RootBeanDefinition attributeSourceDefinition = parseAttributeSource(attributeSourceElement, parserContext);
builder.addPropertyValue("transactionAttributeSource", attributeSourceDefinition);
}
else {
// Assume annotations source.
builder.addPropertyValue("transactionAttributeSource",
new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"));
}
}
4.2 注册事务基础Bean配置
等下我们看代码的时候你会发现,他实现了和事务注解驱动配置:ProxyTransactionManagementConfiguration类似的功能:
@Override
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;
}
这边我们依然只看PROXY的方式,我们可以看到下面的代码基本可以分成四步:
- AopNamespaceUtils.registerAutoProxyCreatorIfNecessary:注册InfrastructureAdvisorAutoProxyCreator以及xml配置的解析,不具体看了
- 注入AnnotationTransactionAttributeSource
- 注入TransactionInterceptor
- 注入BeanFactoryTransactionAttributeSourceAdvisor
- 注册上述的组件到context
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
//注册InfrastructureAdvisorAutoProxyCreator类和解析XML属性
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
Object eleSource = parserContext.extractSource(element);
//注入AnnotationTransactionAttributeSource
RootBeanDefinition sourceDef = new RootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.