seata 客户端启动
Seata Client 启动
Seata Server 启动了解了, 现在来看一下Seata Client的启动, 需要对SpringBoot 有一些了解
因为Seata Server 解析的是1.5.1, 那么Seata Client 也解析1.5.1
引入Seata
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
因为引入了seata 的starter, 所以会自动引入一些Jar包如下

因为SpringBoot 自动装配的时候会加载Jar 下的spring.factories 中实现EnableAutoConfiguration的类, 这也是我们分析一些框架源码的入口
spring-cloud-starter-alibaba-seata-2.2.8.RELEASE.jar

在spring-cloud-starter-alibaba-seata 中的spring.factories总共有4个类实现了EnableAutoConfiguration 接口: restTemplate,handlerInteceptor,feignClient,Hystrix相关的
SeataRestTemplateAutoConfiguration

从上述的代码中可以看出来,在SeataRestTemplateAutoConfiguration 生成Bean 的时候会调用init方法,在init方法中,会将一个interceptor增加到restTemplate中, restTemplate 发起请求的时候,会优先调用这个interceptor, 而SeataRestTemplateInterceptor 是在一个配置类中生成的,可以注入到SeataRestTemplateAutoConfiguration中
SeataRestTemplateInterceptor

可以看到在SeataRestTemplateInterceptor并没有进行很复杂的操作,而是从seata的全局上下文中获取到当前事务的全局事务Id, 然后添加到Header中,这样就可以让全局事务ID 在各个微服务之间进行流转
SeataHandlerInterceptorConfiguration

在SeataHandlerInterceptorConfiguration 也是添加了一个拦截器, 不过是对SpringMVC进行拦截,拦截器是SeataHandlerInterceptor
SeataHandlerInterceptor

SeataFeignClientAutoConfiguration

SeataFeignClientAutoConfiguration 是利用构造器模式生成SeataFeignClient,同时支持hystrix, sentinel和普通模式


SeataFeignClient

我们来看一下execute方法,在方法中会从上下文中获取到全局事务Xid,然后将xid放到请求头中
SeataHystrixAutoConfiguration

Hystrix 会将请求包装成Command,然后将Command由线程交给请求框架执行

seata-spring-autoconfigure-client-1.5.1.jar
下面来看一下seata-spring-autoconfigure-client-1.5.1.jar的spring.factories

在client自动装配存在两个类,一个是SeataTCCFenceAutoConfiguration,一个是SeataClientEnvironmentPostProcessor,SeataClientEnvironmentPostProcessor 主要是装配seataClient 的一些配置, SeataTCCFenceAutoConfiguration主要是装配TCC模式的一些配置
SeataTCCFenceAutoConfiguration

SeataClientEnvironmentPostProcessor

seata-spring-autoconfigure-core-1.5.1.jar
下面来看一下seata-spring-autoconfigure-core-1.5.1.jar的spring.factories

seata 核心类中也存在两个自动装配类
SeataCoreAutoConfiguration

SpringApplicationContextProvider 实现了ApplicationContextAware, 如果对spring 生命周期有些了解的话,会知道ApplicationContextAware主要是用于方便获取到springApplicationContext上下文
SeataCoreEnvironmentPostProcessor

SeataCoreEnvironmentPostProcessor 在init初始化的时候会将seata的配置,注册等信息全部保存到一个Map中,为了保证线程安全,这里用CAS的模式进行添加
seata-spring-boot-starter-1.5.1.jar

seata-spring-boot-starter的spring.factory中的自动装配类就比较多了,包括seata数据库代理,seata, http请求, seataSaga模式这4中自动装配
SeataDataSourceAutoConfiguration

SeataDataSourceAutoConfiguration中比较简单就是创建一个SeataAutoDataSourceProxyCreator的bean,SeataAutoDataSourceProxyCreator是AbstractAutoProxyCreator的子类,主要是实现SeataAT模式数据库代理的切面
SeataAutoDataSourceProxyCreator
public class SeataAutoDataSourceProxyCreator extends AbstractAutoProxyCreator {
private static final Logger LOGGER = LoggerFactory.getLogger(SeataAutoDataSourceProxyCreator.class);
private final Set<String> excludes;
private final String dataSourceProxyMode;
private final Object[] advisors;
public SeataAutoDataSourceProxyCreator(boolean useJdkProxy, String[] excludes, String dataSourceProxyMode) {
setProxyTargetClass(!useJdkProxy);
this.excludes = new HashSet<>(Arrays.asList(excludes));
this.dataSourceProxyMode = dataSourceProxyMode;
this.advisors = buildAdvisors(dataSourceProxyMode);
}
// 将需要代理的对象方法注解构建Advice调用链,如果执行到方法有被指定注解修饰,那么最终会调用advice 链条中的invoke 方法
private Object[] buildAdvisors(String dataSourceProxyMode) {
Advice advice = new SeataAutoDataSourceProxyAdvice(dataSourceProxyMode);
return new Object[]{new DefaultIntroductionAdvisor(advice)};
}
@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource customTargetSource) {
return advisors;
}
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
if (excludes.contains(beanClass.getName())) {
return true;
}
return SeataProxy.class.isAssignableFrom(beanClass);
}
@Override
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// we only care DataSource bean
if (!(bean instanceof DataSource)) {
return bean;
}
// when this bean is just a simple DataSource, not SeataDataSourceProxy
if (!(bean instanceof SeataDataSourceProxy)) {
Object enhancer = super.wrapIfNecessary(bean, beanName, cacheKey);
if (bean == enhancer) {
return bean;
}
// 构建数据库代理,将代理对象储存在map中
DataSource origin = (DataSource) bean;
SeataDataSourceProxy proxy = buildProxy(origin, dataSourceProxyMode);
DataSourceProxyHolder.put(origin, proxy);
return enhancer;
}
LOGGER.warn("Manually register SeataDataSourceProxy(or its subclass) bean is discouraged! bean name: {}", beanName);
SeataDataSourceProxy proxy = (SeataDataSourceProxy) bean;
DataSource origin = proxy.getTargetDataSource();
Object originEnhancer = super.wrapIfNecessary(origin, beanName, cacheKey);
// this mean origin is either excluded by user or had been proxy before
if (origin == originEnhancer) {
return origin;
}
// else, put <origin, proxy> to holder and return originEnhancer
DataSourceProxyHolder.put(origin, proxy);
return originEnhancer;
}
SeataDataSourceProxy buildProxy(DataSource origin, String proxyMode) {
// AT模式
if (BranchType.AT.name().equalsIgnoreCase(proxyMode)) {
return new DataSourceProxy(origin);
}
// XA 模式
if (BranchType.XA.name().equalsIgnoreCase(proxyMode)) {
return new DataSourceProxyXA(origin);
}
throw new IllegalArgumentException("Unknown dataSourceProxyMode: " + proxyMode);
}
}
SeataAutoConfiguration

SeataAutoConfiguration主要是生成了2个bean, 一个是FailureHandler,这个是事务处理的类, 一个是GlobalTransactionScanner,这个类是一个相当重要的类,TMClient, RMClient 对象都在GlobalTransactionScanner 进行初始化
FailureHandler
DefaultFailureHandlerImpl 是FailureHandler的默认实现类,主要包括commit失败,rollback失败和重试策略,DefaultFailureHandlerImpl 这里的处理的逻辑比较简单,就是单纯打印日志,一般需要重新实现FailureHandler实现一些自定义的逻辑
GlobalTransactionScanner
public class GlobalTransactionScanner extends AbstractAutoProxyCreator
implements ConfigurationChangeListener, InitializingBean, ApplicationContextAware, DisposableBean {
我们来看一下GlobalTransactionScanner 实现了InitializingBean, 那么在加入到Spring中的时候会调用afterPropertiesSet 方法,然后在方法中调用initClient会实例化TmClient,RmClient
public void afterPropertiesSet() {
if (disableGlobalTransaction) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Global transaction is disabled.");
}
ConfigurationCache.addConfigListener(ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION,
(ConfigurationChangeListener)this);
return;
}
// 初始化seata client, 为了线程安全使用了CAS
if (initialized.compareAndSet(false, true)) {
initClient();
}
}
private void initClient() {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Initializing Global Transaction Clients ... ");
}
if (DEFAULT_TX_GROUP_OLD.equals(txServiceGroup)) {
...
}
if (StringUtils.isNullOrEmpty(applicationId) || StringUtils.isNullOrEmpty(txServiceGroup)) {
throw new IllegalArgumentException(String.format("applicationId: %s, txServiceGroup: %s", applicationId, txServiceGroup));
}
//init TM
TMClient.init(applicationId, txServiceGroup, accessKey, secretKey);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Transaction Manager Client is initialized. applicationId[{}] txServiceGroup[{}]", applicationId, txServiceGroup);
}
//init RM
RMClient.init(applicationId, txServiceGroup);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Resource Manager is initialized. applicationId[{}] txServiceGroup[{}]", applicationId, txServiceGroup);
}
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Global Transaction Clients are initialized. ");
}
registerSpringShutdownHook();
}
TMClient.init

在init方法中会生成一个netty的远程连接对象
TmNettyRemotingClient#init

AbstractNettyRemotingClient#init

clientBootstrap.start启动netty client
RMClient#init

RMClient 同样使用NettyClient进行连接
RmNettyRemotingClient#init

RmNettyRemotingClient 和 TmNettyRemotingClient 都是AbstractNettyRemotingClient的子类,super.init() 方法是相同的,都是利用启动netty客户端
HttpAutoConfiguration

HttpAutoConfiguration就是在springMVC注入一个拦截器,这个拦截器会往事务全局上下文添加Xid 和清楚Xid
TransactionPropagationInterceptor

SeataSagaAutoConfiguration
SeataSagaAutoConfiguration主要是实现Saga模式,因为平常基本使用AT,TCC模式居多,这里暂时不做分析
浙公网安备 33010602011771号