当前位置: 首页 > news >正文

Seata源码学习(二)-源码入口

Seata源码剖析-源码入口

Seata客户端启动

首先一个Seata的客户端启动一般分为几个流程:

  1. 自动加载各种Bean及配置信息
  2. 初始化TM
  3. 初始化RM(具体服务)
  4. 初始化分布式事务客户端完成,代理数据源
  5. 连接TC(Seata服务端),注册RM,注册TM
  6. 开启全局事务

在这个其中,就会涉及到几个核心的类型,首先我们需要来看配置类型GlobalTransactionAutoConfiguration

所以我们直接通过官方案例引入的Seata包,找到SpringBoot项目在启动的时候自动扫描加载类型的spring.factories,然后找到GlobalTransactionAutoConfiguration(Seata自动配置类)

全局事务扫描类源码

这个类型的核心点,就是加载配置,注入相关的Bean

/*** seata自动配置类*/
@Configuration
@EnableConfigurationProperties(SeataProperties.class)
public class GlobalTransactionAutoConfiguration {private final ApplicationContext applicationContext;private final SeataProperties seataProperties;public GlobalTransactionAutoConfiguration(ApplicationContext applicationContext,SeataProperties seataProperties) {this.applicationContext = applicationContext;this.seataProperties = seataProperties;}// 注入全局事务扫描器@Beanpublic GlobalTransactionScanner globalTransactionScanner() {String applicationName = applicationContext.getEnvironment().getProperty("spring.application.name");String txServiceGroup = seataProperties.getTxServiceGroup();if (StringUtils.isEmpty(txServiceGroup)) {txServiceGroup = applicationName + "-fescar-service-group";seataProperties.setTxServiceGroup(txServiceGroup);}// 构建全局扫描器,传入参数:应用名、事务分组名,失败处理器return new GlobalTransactionScanner(applicationName, txServiceGroup);}
}

GlobalTransactionScanner全局事务扫描器

在这其中我们要关心的是GlobalTransactionScanner这个类型,这个类型扫描@GlobalTransactional注解,并对代理方法进行拦截增强事务的功能。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UqM1hMcB-1676379765831)(image-20220221231318290.png)]

这里给大家展示了当前GlobalTransactionScanner的类关系图,其中我们现在继承了Aop的AbstractAutoProxyCreator类型,在这其中有一个重点方法,其实这个方法就是判断Bean对象是否需要代理,是否需要增强

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (beanName != null && this.targetSourcedBeans.contains(beanName)) {return bean;}if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}// Create proxy if we have advice.Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;
}

当然这是父类提供的方法,那子类继承之后重写此方法,完成了定制化的效果,定义不同的代理对象

@Override
protected Object wrapIfNecessary(奈色色瑞)(Object bean, String beanName, Object cacheKey) {try {// 加锁防止并发synchronized (PROXYED_SET) {if (PROXYED_SET.contains(beanName)) {return bean;}interceptor = null;//check TCC proxy// 检查是否是TCC模式if (TCCBeanParserUtils.isTccAutoProxy(bean, beanName, applicationContext)) {//TCC interceptor, proxy bean of sofa:reference/dubbo:reference, and LocalTCC// 如果是:添加TCC拦截器interceptor = new TccActionInterceptor(TCCBeanParserUtils.getRemotingDesc(beanName));ConfigurationCache.addConfigListener(ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION,(ConfigurationChangeListener)interceptor);} else {// 不是TCC模式Class<?> serviceInterface = SpringProxyUtils.findTargetClass(bean);Class<?>[] interfacesIfJdk = SpringProxyUtils.findInterfaces(bean);// 判断是否有相关事务注解,如果没有就不代理if (!existsAnnotation(new Class[]{serviceInterface})&& !existsAnnotation(interfacesIfJdk)) {return bean;}// 当发现存在全局事务注解标注的Bean,添加拦截器if (globalTransactionalInterceptor == null) {// 添加拦截器globalTransactionalInterceptor = new GlobalTransactionalInterceptor(failureHandlerHook);ConfigurationCache.addConfigListener(ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION,(ConfigurationChangeListener)globalTransactionalInterceptor);}interceptor = globalTransactionalInterceptor;}LOGGER.info("Bean[{}] with name [{}] would use interceptor [{}]", bean.getClass().getName(), beanName, interceptor.getClass().getName());// 检查是否是代理对象if (!AopUtils.isAopProxy(bean)) {// 不是调用Spring代理(父级)bean = super.wrapIfNecessary(bean, beanName, cacheKey);} else {// 已经是代理对象,反射获取代理类中的已经存在的拦截器组合,然后添加到该集合当中AdvisedSupport advised = SpringProxyUtils.getAdvisedSupport(bean);Advisor[] advisor = buildAdvisors(beanName, getAdvicesAndAdvisorsForBean(null, null, null));for (Advisor avr : advisor) {advised.addAdvisor(0, avr);}}// 将Bean添加到Set中PROXYED_SET.add(beanName);return bean;}} catch (Exception exx) {throw new RuntimeException(exx);}
}
http://www.lryc.cn/news/6804.html

相关文章:

  • 2023如何选购适合游戏设计的电脑硬件
  • springboot maven项目集成阿里p3c-pmd插件使用
  • PowerJob的server启动都经历了哪些?代码不多也很简单,咱们来逐一理解。
  • 分享好玩的h5小游戏制作步骤_怎么做h5微信小游戏
  • 代理模式--设计模式
  • 【RSTP的原理和配置】
  • Doom流量回放工具导致的测试环境服务接口无响应的排查过程
  • 2023年留学基金委(CSC)西部/地方合作项目选派办法及解读
  • ILSSI国际研讨会将为您呈现六西格玛技术的未来与前景
  • KDJ日周月金叉共振指标
  • 线程私有变量ThreadLocal详解
  • 如何保证数据库和缓存双写一致性
  • 一文搞懂:JS严格模式“use strict”
  • Linux的ACL(扩展权限)规划:setfacl、getfacl
  • HTML预格式化文本pre标签
  • 基于机器学习的心脏病预测方法(11)——梯度提升机(GBM)
  • Linux多版本python切换以及多版本pip对应 (cloud studio Ubuntu16.04)
  • 【并发编程】LockSupport源码详解
  • 元宇宙之声:新鸿基公司
  • Linux中定时监控Tomcat服务器进程并在进程结束时重启Tomcat服务器
  • 快速部署私有云笔记,免费享受多端同步
  • python生成 2048位随机质数 Miller-Rabin质数测试算法
  • ♡ — MySQL 查询缓存
  • 死锁检测组件 -- 使用hook检测死锁
  • 第2集丨Java中的数据类型汇总
  • 【基础篇】7 # 队列:队列在线程池等有限资源池中的应用
  • matlab进行双目标定获取双目参数并打印教程
  • JVM类加载机制
  • 8.1 优化概述
  • 从0到1一步一步玩转openEuler--14 openEuler DNF(YUM)配置管理