前言
之前我们过了一遍独立服务:事务协调者(TC)的部分源码,光看源码还是比较难深入理解的。后面我们直接从一个事务的流程来讲,把整个流程中用到的源码都过一遍。
整个事务开始之前,肯定就要从事务注解@GlobalTransactional
开始了。
在讲注解的时候,我们会过一遍Spring AOP实现原理。
关系总览
和GlobalTransactional相关的有GlobalTransactionScanner、GlobalTransactionalInterceptor两个类
GlobalTransactionScanner
从名字就能看出用于扫描所有有事务注解的方法。
GlobalTransactionalInterceptor
是对应的Advices/Advisors
GlobalTransactionScanner
中使用了GlobalTransactionalInterceptor
GlobalTransactionScanner继承的接口和抽象类
我们先看GlobalTransactionScanner
public class GlobalTransactionScanner extends AbstractAutoProxyCreator
implements InitializingBean, ApplicationContextAware, DisposableBean
GlobalTransactionScanner
继承了AbstractAutoProxyCreator
、InitializingBean
、ApplicationContextAware
、DisposableBean
。
这几个接口有什么用呢?看到这里,如果没有学习过Spring,可能会一脸懵逼,我们一个个来看:
继承了ApplicationContextAware
这个接口的bean,需要实现一个方法:
void setApplicationContext(ApplicationContext applicationContext) throws BeansException
当spring启动完成后,会自动调用这个接口,把ApplicationContext
给bean。也就是说,GlobalTransactionScanner
天然能拿到Spring的上下文。
继承了InitializingBean接口,需要实现一个方法:
void afterPropertiesSet() throws Exception;
凡是继承该接口的类,在初始化bean的时候,当所有properties都设置完成后,会执行该方法。我们后面再统一看看这里面做了什么。
继承DisposableBean,需要实现一个方法:
void destroy() throws Exception;
和InitializingBean接口相反,这个是在销毁的时候会调用这个方法。
AbstractAutoProxyCreator
就比较复杂了,它Spring实现AOP的一种方式。本质上是一个BeanPostProcessor,他在bean初始化之前,调用内部的createProxy方法,创建一个bean的AOP代理bean并返回。
但是它不是把所有的bean都增强,选取哪些bean做增强呢?选取的策略是根据getAdvicesAndAdvisorsForBean
方法返回的Advices/Advisors来确定的。
看到这里,其实总体的逻辑基本就清晰了,GlobalTransactionScanner扫描有注解的bean,做AOP增强。
GlobalTransactionScanner
然后,我们来看看GlobalTransactionScannerd,它的构造方法中有几个参数,这些参数都是在xml配置文件里传的
public GlobalTransactionScanner(String applicationId, String txServiceGroup, int mode,
FailureHandler failureHandlerHook) {
setOrder(ORDER_NUM);
setProxyTargetClass(true);
this.applicationId = applicationId;
this.txServiceGroup = txServiceGroup;
this.mode = mode;
this.failureHandlerHook = failureHandlerHook;
}
配置文件示例:
<bean class="io.seata.spring.annotation.GlobalTransactionScanner">
<constructor-arg value="tcc-sample"/>
<constructor-arg value="my_test_tx_group"/>
</bean>
默认的模式是AT+MT,默认的失败处理handler是DefaultFailureHandlerImpl
我们看其他的方法前,先回顾一下Spring中Bean的关键初始化过程:
实例化 -> 属性注入 -> postProcessBeforeInitialization -> afterPropertiesSet/init方法 -> postProcessAfterInitialization
实例化:
singletonFactory.getObject()实例化Bean的时候,最终调用getEarlyBeanReference
来实例化Bean,它的逻辑很简单,从缓存里取Bean,没有就初始化一个,然后调用wrapIfNecessary
。这个方法看名字就知道,会判断是否需要包装这个Bean。GlobalTransactionScanner里就重写了这个方法,后面重点关注。
属性注入:
这一步和我们讲事务没关系,忽略。
后面三步postProcessBeforeInitialization、afterPropertiesSet、postProcessAfterInitialization:
每一步GlobalTransactionScanner都有重写,我们重点关注。
下面,我们开始按照顺序,讲解上面说的,GlobalTransactionScanner里重写的方法
wrapIfNecessary:
这里面做了两个事情,
1)根据配置判断,到底用的是TCC模式,还是其他模式,会放置不同的interceptor。这些interceptor会在getAdvicesAndAdvisorsForBean中返回。
2)如果Bean不是代理类,则走Spring默认的AOP的Wrap;否则调用getAdvicesAndAdvisorsForBean获取要使用的Advices/Advisors,其实就是用第一步中配置的interceptor。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (disableGlobalTransaction) {
return bean;
}
try {
synchronized (PROXYED_SET) {
if (PROXYED_SET.contains(beanName)) {
return bean;
}
interceptor = null;
//是否TCC
if (TCCBeanParserUtils.isTccAutoProxy(bean, beanName, applicationContext)) {
//TCC代理的Bean有 sofa:reference/dubbo:reference/本地TCC
//使用TccActionInterceptor作为Advices/Advisors
interceptor = new TccActionInterceptor(TCCBeanParserUtils.getRemotingDesc(beanName));
} else {
Class<?> serviceInterface = SpringProxyUtils.findTargetClass(bean);
Class<?>[] interfacesIfJdk = SpringProxyUtils.findInterfaces(bean);
if (!