该说些什么呢?一连几天,我都沉溺在孤芳自赏的思维中无法自拔。不知道自己为什么会有这种令人不齿的表现,更不知道这颗定时炸弹何时会将人炸的粉身碎骨。好在儒派宗师曾老夫子“吾日三省吾身”的名言警醒了我。遂潜心自省,溯源头以解迷思:一开始,我的目标就是梳理知识。但最近博君一笑的怪异思维让我每日如跳梁小丑般为博君一笑而胡乱行文,后又因觉背离宗旨而主动删除。虽尚未因此遭受处罚,但这种背离宗旨的行径,着实令人不齿。为回归本心,我决定继续前一篇博文所述主题。
上一篇博客我们梳理了与事务相关的基本概念及Spring事务的基本用法,本篇博客我们将探究其基本原理。有心人可能已经发现了,其实Spring事务的实现方式与前面梳理的AOP的实现方式类似:将事务增强方法与目标方法组成一个执行链,然后由调度者依次调度执行链中的相关方法,从而达到事务控制的目标。下面就让我们从注解@ EnableTransactionManagement开始,然后一步一步向下探索吧。
该注解上面有这样一句@Import(TransactionManagementConfigurationSelector.class),其中的TransactionManagementConfigurationSelector类继承了AdviceModeImportSelector类。该类会通过selectImports(AdviceMode)方法导入两个组件ProxyTransactionManagementConfiguration和AutoProxyRegistrar。其中后者向Spring容器中注册一个InfrastructureAdvisorAutoProxyCreator 组件,该组件会通过后置处理器在对象创建以后,包装对象,然后返回一个代理对象(包含增强器)——一个包含所有拦截器链的代理对象,执行该代理对象,本质上就是执行这个拦截器链;前者向容器注册一个ProxyTransactionManagementConfiguration类型的配置对象,该对象会继续向容器中注入一个事务增强器,即BeanFactoryTransactionAttributeSourceAdvisor对象(该对象会包含一个TransactionAttributeSource类型的属性,该属性的作用是用于解析事务注解,即@Transactional,故其实际类型为AnnotationTransactionAttributeSource;另外该对象还会包含一个事务拦截器,即TransactionInterceptor,它保存了事务属性信息,比如事务管理器——TransactionManager和TransactionAttributeSource等)。
下面一起来看一下InfrastructureAdvisorAutoProxyCreator类。看到这个类是不是觉得很熟悉?是的,在《Spring AOP总结二》这篇博文中,我们梳理过一个相似类型的类——AnnotationAwareAspectJAutoProxyCreator(它也继承成了ProxyProcessorSupport类,同时实现了BeanFactoryAware、SmartInstantiationAwareBeanPostProcessor接口)。下面这幅图展示的是InfrastructureAdvisorAutoProxyCreator类的结构图:
通过这幅图我们不难发现InfrastructureAdvisorAutoProxyCreator类是BeanPostProcessor接口的一个实现类,所以其必定实现了BeanPostProcessor接口中定义的两个方法:
不过需要注意的是这两个方法的真正实现体位于AbstractAutoProxyCreator类中,关于这两个方法的具体执行逻辑,这里就不再详细描述了,想了解详情可以参见前面关于AOP的系列文章。梳理这个类的目的只有一个,希望自己能够弄清楚这个类在Spring整个事务处理中的作用:通过后置处理器在需要事务的目标对象创建以后,对该对象进行包装,然后返回一个包含增强器的代理对象。
下面我们一起看一下ProxyTransactionManagementConfiguration类。这个类的源码如下面所示:
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ImportRuntimeHints(TransactionRuntimeHints.class)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.getNumber("order"));
}
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
// Accept protected @Transactional methods on CGLIB proxies, as of 6.0.
return new AnnotationTransactionAttributeSource(false);
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
通过源码可以发现,该类如前面所说的那样,是一个配置类。在这个类里面我们主要关注其第一个方法,该方法的主要作用是创建一个BeanFactoryTransactionAttributeSourceAdvisor对象,并将其注册到Spring容器中。该类的继承结构如下所示:
下面拿BeanFactoryTransactionAttributeSourceAdvisor这个类与前面AOP系列文章中的InstantiationModelAwarePointcutAdvisorImpl类进行对比。不难看出它们都实现了Advisor接口。因此,理论上讲,这两个类的作用是一样的。根据前面对AOP的跟踪个人理解InstantiationModelAwarePointcutAdvisorImpl类的主要作用是保存关键数据(比如持有一个AspectJExpressionPointcut对象),并依据持有的关键数据创建对应的Advice,比如AspectJAroundAdvice、AspectJMethodBeforeAdvice、AspectJAfterAdvice、AspectJAfterReturningAdvice、AspectJAfterThrowingAdvice,等等。而这里要讲的Advisor的实现类BeanFactoryTransactionAttributeSourceAdvisor的作用也类似——整合Pointcut及Advise以方便后期使用(其持有的Advice和Pointcut对象,均是显式创建的,即new方式,具体见ProxyTransactionManagementConfiguration及BeanFactoryTransactionAttributeSourceAdvisor的源码)。该对象在容器中有两个调用入口,一个调用点位于AbstractAutoProxyCreator类的postProcessBeforeInitialization()方法中,另一个调用点位于本类的postProcessAfterInitialization()方法中。上篇文章中的示例,在获取容器中的TransferService对象时,触发了BeanFactoryTransactionAttributeSourceAdvisor对象的使用,详细参见下面图片:
图中最上面箭头所指的代码就是执行的入口,通过这个方法系统可以找到适用于当前对象的Advisor对象,比如这里的一直梳理的BeanFactoryTransactionAttributeSourceAdvisor对象。接下来就是创建代理对象了(这里的操作比较复杂,这里就不再赘述,如果有兴趣的可以翻阅一下《Spring AOP总结四》这篇文章)。
接下来,让我们一起继续看看BeanFactoryTransactionAttributeSourceAdvisor源码中的TransactionAttributeSourcePointcut类型的对象。TransactionAttributeSourcePointcut类的继承体系如下图所示:
为了加深理解,我们将其与Spring AOP中的AspectJExpressionPointcut的类结构图做个对比,下面这幅图就是AspectJExpressionPointcut的类结构图(注意下面这幅图中的IntroductionAwareMethodMatcher类继承了MethodMatcher接口,BeanFactoryAware接口则继承了Aware接口):
从这两幅图可以看出:TransactionAttributeSourcePointcut和AspectJExpressionPointcut都实现了Pointcut和MethodMatcher接口。因此它们是一个方法匹配器,其中定义了方法匹配规则,也是过滤器的一种实现,其主要用于判断哪些方法需要使用当前的增强业务。这里有个问题AspectJExpressionPointcut类继承了ClassFilter,但是TransactionAttributeSourcePointcut没有,那它只通过实现MethodMatcher接口就可以完成所有过滤功能吗?不是这样的 TransactionAttributeSourcePointcut类的构造方法中有这样一行代码,如下图所示:
通过这行代码TransactionAttributeSourcePointcut对象会持有一个类型TransactionAttributeSourceClassFilter的过滤器。TransactionAttributeSourceClassFilter类的继承体系如下图所示:
所以这里很清楚了TransactionAttributeSourcePointcut会通过持有一个外部ClassFilter的方式来引入一个限制切入点或引入点与给定目标类集的匹配的筛选器,目的是用于筛选那些类需要被处理,哪些类不需要被处理。因此TransactionAttributeSourceClassFilter是过滤器,其主要作用就是筛选出合适的类,而过滤掉不合适的类。
再回到ProxyTransactionManagementConfiguration源码的第一个方法中,在创建完BeanFactoryTransactionAttributeSourceAdvisor对象后,其后面紧跟了两行属性赋值代码,具体如下图所示:
这两行代码的主要作用是为BeanFactoryTransactionAttributeSourceAdvisor对象的advice及transactionAttributeSource两个属性进行初始化。其中adevice属性的的实际类型为TransactionInterceptor,transactionAttributeSource的实际类型为AnnotationTransactionAttributeSource。注意setTransactionAttributeSource()方法的本质是将AnnotationTransactionAttributeSource对象赋值给BeanFactoryTransactionAttributeSourceAdvisor对象所持有的TransactionAttributeSourcePointcut对象。下面我们就来看一下这两个类的结构图:
梳理到这里我不禁想到了Spring AOP中常见的五个通知,详情可以浏览一下《Spring AOP总结二》这篇文章。这五个通知中有三个直接实现了MethodInterceptor接口,这三个接口分别为:AspectJAfterAdvice、AspectJAroundAdvice、AspectJAfterThrowingAdvice。另外两个虽然没有直接实现这个接口,但在Spring容器启动过程中会对他们进行包装,最终包装为两个实现了MethodInterceptor接口的对象,它们分别为:MethodBeforeAdviceInterceptor和AfterReturningAdviceInterceptor。具体可以看一下《Spring AOP总结四》这篇文章。通过实现MethodInterceptor接口,最终TransactionInterceptor类有了被调用的机会(因为该类实现了MethodInterceptor接口中的invoke(MethodInvocation)方法,该方法会被最终创建的代理对象持有的链中的DynamicAdvisedInterceptor对象通过CglibMethodInvocation对象中的proceed()进行调用,进而完成对事务的控制。这部分执行逻辑同样可以在《Spring AOP总结四》这篇文章中看到)。
下面我们看一下这个类的isCandidateClass(Class>)方法,该方法会对传递进来的目标class进行判断,通过调用TransactionAnnotationParser类的isCandidateClass()进行判断,其实际调用点如下图所示:
图中的Pointcut的实际类型为TransactionAttributeSourcePointcut,这里的pc.getClassFilter()会获得TransactionAttributeSourcePointcut$TransactionAttributeSourceClassFilter类型的对象,然后调用该对象的matches(Class>)方法,具体如下图所示:
紧接着上图所示的代码进行判断后,会直接调用TransactionAttributeSource对象上的isCandidateClass(Class>)方法(实际走的是AnnotationTransactionAttributeSource),注意这个TransactionAttributeSource属性的初始化是在ProxyTransactionManagementConfiguration类创建BeanFactoryTransactionAttributeSourceAdvisor对象时完成的。具体如下图所示:
AnnotationTransactionAttributeSource#isCandidateClass(Class>)方法会遍历本类持有的TransactionAnnotationParser集合,然后调用其上的isCandidateClass(Class>)方法,注意这里的TransactionAnnotationParser集合只有一个数据,即SpringTransactionAnnotationParser,下面看一下这个类的结构图:
继续看SpringTransactionAnnotationParser类中的isCandidateClass(Class>)方法,其源码如下所示:
public boolean isCandidateClass(Class> targetClass) {
return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
}
从这段代码可以看出,其主要作用就是判断目标类上是否有Transactional注解。具体如下图所示:
从这幅图可以看到前一节案例中TransferServiceImpl类(添加了@Transactional注解)在这里执行返回了true,因此这段代码的主要作用就是判断类上是否有@Transactional注解。接下来,我们继续看后面的逻辑,这就要回到下图所示的代码处了:
根据前面梳理的TransactionAttributeSourcePointcut的结构图可知,其继承了StaticMethodMatcherPointcut类,同时也继承了该类上的getMethodMatcher()方法,其最终会返回TransactionAttributeSourcePointcut对象本身。下面就不再梳理AopUtils#canApply(Pointcut pc, Class> targetClass, boolean hasIntroductions)中的代码了,其主要目的就是遍历目标类中的所有方法,即TransferServiceImpl中的所有方法(包括继承过来的),然后调用MethodMatcher接口的matches()方法,这里调的是TransactionAttributeSourcePointcut类中的matches()方法。注意:这里只会判断当前类及其中是否有方法适合TransactionAttributeSourcePointcut指定的规则,如果适合就会直接返回true。这个方法的最终调用者,即AbstractAutoProxyCreator#wrapIfNecessary(Object bean, String beanName, Object cacheKey)方法,该方法会将得到的Advisor集合继续向下传递给createProxy()方法,以完成最终的代理的创建。(跟踪过程中隐约看到,会遍历所有方法为所有方法生成链?暂不确定后续会继续跟踪)
至此,配置了事务的类的代理对象就创建完成了。接下来我们主要看一下其执行过程中必须用到的Interceptor的实现类TransactionInterceptor。该类中的invoke(MethodInvocation)方法是关键,其源码如下所示:
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
@Override
@Nullable
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
@Override
public Object getTarget() {
return invocation.getThis();
}
@Override
public Object[] getArguments() {
return invocation.getArguments();
}
});
}
该类会继续调用父类TransactionAspectSupport中的invokeWithinTransaction()方法。在该方法中可以看到这样几个对象:TransactionAttributeSource、TransactionAttribute、TransactionManager等。执行详情参见下图:
这里的TransactionAttributeSource的实际类型为AnnotationTransactionAttributeSrouce,接着会调用本类的determineTransactionManager()方法获取目标类上配置的与事务相关的属性,并将其包装为TransactionAttribute对象,实际类型为RuleBasedTransactionAttribute。接着获取其中配置的事务管理器(TransactionManager),其实际类型为JdbcTransactionManager。
送君千里终须一别,虽然还想继续,但终究还是想停一下!通过这篇文章我们再次回顾了AOP创建过程中寻找适当Advisor的流程,同时也了解了Spring事务创建过程中的一些重要类及其结构,最重要的是我们找到了Spring事务控制的核心代码。下篇文章我们将继续跟踪这个核心代码,以了解清楚Spring事务控制的核心原理。