概要
过度
我们前面介绍了事务的一些特点、使用原因,并介绍了它的基本API的使用方法。
我们本节从上文的 Spring 使用事务的 demo 入手,大概介绍一下Spring-tx框架的实现流程,以加深对Spring的熟悉。
内容简介
开始具体介绍Spring-tx框架的实现原理,我们本文主要介绍事务相关的注册逻辑,后面会继续介绍在正常工作时的事务工作逻辑。
所属环节
事务具体介绍——扫描及相关注册
上下环节
上文: 事务引入
下文: 事务具体工作逻辑
源码解析
入口
我们上文介绍了demo,其实核心就是两个xml配置,一个是对自定义标签<tx:annotation-driven />
的解析,一个是对特殊类型bean的注册。具体代码如下:
<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
我们从自定义标签解析开始,一般这里就是对应框架的实现入口。之前讲过好多这种自定义标签的解读方法了,无非是
- 通过 META-INF/spring.handlers 确定定制包的命名空间解析处理器【此处为
TxNamespaceHandler
】 - 通过标签解析处理器找到处理对应标签的类【此处为
AnnotationDrivenBeanDefinitionParser
】
接下来就看解析逻辑就行了。
AnnotationDrivenBeanDefinitionParser
解析逻辑
整体逻辑
我们先看他的整体解析逻辑吧:
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;
}
先是registerTransactionalEventListenerFactory
注册事务相关事件的监听组件,然后将事务相关注册进行委托。
根据上一篇文章的推测,事务的处理是通过切面实现的,所以注定要用到切面相关的东西,这里也提供了不同的切面集成方式:aspectj 和 AOP 。AOP 我们之前介绍过,优先选这种,毕竟这样读起代码比较轻松点。而且我们在日常使用事务时也没有配置过 aspectj ,因此猜测我们平时都是用的 AOP 实现策略。
我们大概看一下事件监听组件的代码即可:
private void registerTransactionalEventListenerFactory(ParserContext parserContext) {
RootBeanDefinition def = new RootBeanDefinition();
def.setBeanClass(TransactionalEventListenerFactory.class);
parserContext.registerBeanComponent(new BeanComponentDefinition(def,
TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME));
}
后面把主要精力放到事务相关的代码上。
基于AOP的事务注册
/**
* Inner class to just introduce an AOP framework dependency when actually in proxy mode.
*/
private static class AopAutoProxyConfigurer {
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
// 此处注册支持AOP的基础类
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
// 如果没有手动注册或者扫描 TRANSACTION_ADVISOR_BEAN_NAME ,就在这里进行注册
// TODO 这里是进行对应元素解析时进行调用,后面可能会有 TRANSACTION_ADVISOR_BEAN_NAME 的声明
// 这里猜测应该对覆盖式声明有兼容,根据之前看的框架的东西,同id同类,应该没问题
// TODO 正常我们就不会对这个BD进行注册,基本就靠这里了
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);
}
}
}
整体思路如下:
注册支持AOP的基础类以此启动AOP的相关功能
注册
transactionAttributeSource
的bean,用来存储代码类、方法和打的@Transactional
注解的属性的映射关系-
注册
TransactionInterceptor
,此方法中包含了对事物的实现逻辑,它实现了MethodInterceptor
接口,由下面专门注册的Advisor
进行封装和调用此处专门抽离出来感觉有两个原因:
- 避免将事物的实现逻辑和AOP紧耦合,增加通用性【就比如还有用
aspectj
类型的】 - 方便子类依赖事物控制逻辑进行进一步定制
- 避免将事物的实现逻辑和AOP紧耦合,增加通用性【就比如还有用
-
注册
BeanFactoryTransactionAttributeSourceAdvisor
,它是一个实现了Advisor
接口的类,用来通过AOP实现对事物的相关控制。角色:
它引用了
transactionAttributeSource
和TransactionInterceptor
,可以看作是两个功能的汇总功能:
它实现了
- 判断是否进行增强
- 解析、记录类、方法坐标和注解配置的对应关系
- 根据解析处的配置进行事物逻辑的调用
感觉更像是把前面的东西都串起来了。
接下来我们从BeanFactoryTransactionAttributeSourceAdvisor
入手。
我们先回顾一下AOP中的大概逻辑:
- 先找出
BeanFactory
中所有实现了Advisor
接口的类,然后实例化 - 判断增强器是否适用当前要处理的类
- 如果适用,就进行增强,然后返回
- 如果不适用,就结束
我们按照这个逻辑来看,就比较清楚了。
判断是否需要事物增强
在BeanFactoryTransactionAttributeSourceAdvisor
中,我们根据前面对AOP的介绍,发现在判断Advisor
类型是Pointcut
之后,我们会拿到Pointcut
,然后调用里面的match方法进行判断。
在BeanFactoryTransactionAttributeSourceAdvisor
中,很容易找到:
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
它创建了一个TransactionAttributeSourcePointcut
并在getPointcut()
中返回了它,我们继续深入。
@Override
public boolean matches(Method method, @Nullable Class<?> targetClass) {
if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
return false;
}
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
如果目标类继承了TransactionalProxy
,表示该类是事物功能的基础配置类,就不进行增强,此处的逻辑和之前AOP的思路很像。
当然,如果是普通的类的话就尝试获得它方法上事物注解的配置属性,如果有就表示打了@Transactional
,就要进行增强,如果没有就不用增强了。【此处在判断时顺手将注解的配置属性进行了存储,一句两得】
其中getTransactionAttributeSource()
正是BeanFactoryTransactionAttributeSourceAdvisor
中创建匿名类覆盖的方法——返回的是我们整合的transactionAttributeSource
,即AnnotationTransactionAttributeSource
类型的实例。
我们继续看getTransactionAttribute()
:
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// 只是个Object基础类,不会有注解
if (method.getDeclaringClass() == Object.class) {
return null;
}
// First, see if we have a cached value.
// 计算方法对应的唯一key,看之前是否做过解析、缓存
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// 有之前的缓存
// Value will either be canonical value indicating there is no transaction attribute,
// or an actual transaction attribute.
if (cached == NULL_TRANSACTION_ATTRIBUTE) { // 之前的标记是没有
return null;
} else {
return cached;
}
} else {
// 之前没有缓存过,我们需要现场进行解析、缓存、返回
// We need to work it out.
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// 缓存并返回
// Put it in the cache.
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
} else {
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isDebugEnabled()) {
logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
总体来说还是将提取逻辑委托给了computeTransactionAttribute()
,方法本身只维护一层缓存。
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// Don't allow no-public methods as required.
// 如果配置了只允许公共方法,那么对非公共方法直接快速失败
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
// 传入的方法可能是接口的或者父类的,我们要拿到最下层实现类的方法【先找那个上面的打标,找不到再往上找】
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.
// 找到最下层实现类的方法上的 @Transactional 注解属性
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) { // 拿到,直接返回
return txAttr;
}
// Second try is the transaction attribute on the target class.
// 最下层实现类的方法上没拿到,就看最下层实现类上是否有注解【最终调用的都是一个套路,只是这里给封装成不同的入参而已】
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
// 在具体方法、具体类都没找到,就往上层找,如果具体化之后的方法和传入方法不一样就说明可以向上追溯
if (specificMethod != method) {
// Fallback is to look at the original method.
// 找上层方法的注解
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// Last fallback is the class of the original method.
// 找上层类的注解
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
return null;
}
注意:此处的注解提取逻辑比较重要,因为很多时候我们在使用@Transactional
时或多或少可能遇到坑;而且,自定义注解和相关实现逻辑时也可借用此处的api
此处介绍一下Spring封装的获得指定元素上注解信息的API:AnnotatedElementUtils.findMergedAnnotationAttributes()
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
// 这里虽然提供配置多个 annotationParser 的选项,我们只关注 Spring 的
for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
TransactionAttribute attr = annotationParser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
// 调用 utils 方法,拿到注解中所有的配置属性
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
element, Transactional.class, false, false);
// 将配置属性拼装成对应的domain并返回
if (attributes != null) {
return parseTransactionAnnotation(attributes);
} else {
return null;
}
}
我们上面的获得注解属性操作都是对AnnotatedElementUtils
的封装、使用。对于其具体使用方法不再深追。有需要再看。
其实到此,我们就完成了事物相关操作中在进行AOP增强时对类是否进行增强增强的判断。剩下的增强逻辑AOP会帮我们做。