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

news2024/11/26 6:12:18

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;
	}
	// 注入全局事务扫描器
	@Bean
	public 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.coloradmin.cn/o/345647.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第三部分:(主从)复合句——第二章:定语从句

若多件事不一样重要&#xff0c;连接到一块就构成了主从复合句&#xff0c;主要的事情写成主句&#xff0c;次要的事情写成从句&#xff0c;从句虽然不是主要描述的事情&#xff0c;但从句是考试常考的地方&#xff0c;从句有很多复杂的变化&#xff0c;前面需要加上一些连接词…

118.(leaflet篇)leaflet空间判断-点与geojson面图层的空间关系(turf实现)

听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <!DOCTYPE html> <html>

【算法自由之路】 贪心算法

贪心算法 局部最右得到全局最右难点在于如何证明局部最优可以得到全局最优堆 和 排序 是贪心算法最常用的实现算法 贪心算法作为最符合自然智慧的算法&#xff0c;思路是从小部分取最优从而获得最终的最优&#xff0c;但是难得是怎样获取部分最优才能得到全局最优。 有时候我…

9个EXCEL舍入函数公式的用法和实例

用法和实例 1. ROUND ROUND函数可以将数字四舍五入到指定的小数位数。 语法&#xff1a;ROUND(number, num_digits) number&#xff1a;要四舍五入的数字。 num_digits&#xff1a;要保留的小数位数。 举例&#xff1a; ROUND(3.14159,2)&#xff0c;结果为3.14 ROUND(3.141…

如何在Excel中向下拉列表中添加条件

在Excel中向下拉列表中添加条件 创建矩阵型数据集创建下拉列表创建第一个下拉列表创建第二个下拉列表你可以使用Microsoft Excel下拉列表来显示一个简单的列表,尽管有时需要更多的控制。假设你的人员分散在四个地区:北部、南部、东部和西部。你希望按地区与人员合作,而不是与…

界面组件DevExpress Reporting v22.2 - 增强的Web报表组件UI

DevExpress Reporting是.NET Framework下功能完善的报表平台&#xff0c;它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集&#xff0c;包括数据透视表、图表&#xff0c;因此您可以构建无与伦比、信息清晰的报表。DevExpress Reporting v22.2版本已正式发布&…

【LeetCode】剑指 Offer 04. 二维数组中的查找 p44 -- Java Version

题目链接&#xff1a; https://leetcode.cn/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/ 1. 题目介绍&#xff08;04. 二维数组中的查找&#xff09; 在一个 n * m 的二维数组中&#xff0c;每一行都按照从左到右 非递减 的顺序排序&#xff0c;每一列都按照从上到下 非递…

为什么要有分布式锁?

Redis避坑指南&#xff1a;为什么要有分布式锁&#xff1f;作者&#xff1a;京东保险 张江涛1、为什么要有分布式锁&#xff1f;JUC提供的锁机制&#xff0c;可以保证在同一个JVM进程中同一时刻只有一个线程执行操作逻辑&#xff1b;多服务多节点的情况下&#xff0c;就意味着有…

2023最新Java面试手册(性能优化+微服务架构+并发编程+开源框架)

Java面试手册 一、性能优化面试专栏 1.1、 tomcat性能优化整理 1.2、JVM性能优化整理 1.3、Mysql性能优化整理 二、微服务架构面试专栏 2.1、SpringCloud面试整理 2.2、SpringBoot面试整理 2.3、Dubbo面试整理 三、并发编程高级面试专栏 四、开源框架面试题专栏 4.1、Sprin…

勒索软件、网络钓鱼、零信任和网络安全的新常态

当疫情来袭时&#xff0c;网络罪犯看到了他们的机会。随着公司办公、政府机构、学校和大学从以往的工作模式转向远程线上办公模式&#xff0c;甚至许多医疗保健设施都转向线上&#xff0c;这种快速的过渡性质导致了不可避免的网络安全漏洞。消费者宽带和个人设备破坏了企业安全…

name不能作为js的变量名

今天看红宝书的时候&#xff0c;看中到&#xff1a; null和undefined值没有toString()方法&#xff0c;而String()却能够将null和undefined转化成对应的字符串。 想着去尝试一下&#xff0c;用到了name作为变量值&#xff0c;发现让name为null或undefined的时候&#xff0c;就…

(C00102)基于Servlet的在线服装销售管理系统——有文档

基于Servlet的在线服装销售管理系统项目简介项目获取开发环境项目技术运行截图项目简介 本项目是基于J2EE的servlet的在线服装销售管理系统&#xff0c;衣服、裤子、上衣等等&#xff0c;本项目有三种权限&#xff1a;游客、用户、管理员 游客&#xff1a;服装浏览、加入购物车…

“鸡血驱动”为CS:GO、LOL注入“强心剂”!英特尔锐炫A750显卡实测

自推出锐炫系独显以来&#xff0c;英特尔一直在为自家的独显产品的市场竞争力添砖加瓦&#xff0c;其中就包括了驱动程序的持续更新优化和市场策略的调整。在驱动部分&#xff0c;在去年底31.0.101.3802版的小优化更新之后&#xff0c;今年2月初又陆续更新了31.0.101.4091 WHQL…

手把手教你二进制安装生产环境 K8s 多 master 节点高可用集群详细图文教程

目录 一、集群环境准备 1.1 kubeadm 和二进制安装 k8s 适用场景分析 1.2 多 master 节点高可用架构图 二、基础环境配置&#xff08;以下操作所有节点都得执⾏&#xff09; 2.1 初步的环境初始化 2.2 关闭交换分区 swap 提升性能 2.3 修改机器内核参数 2.4 配置阿里云…

深入理解 Handler(java 层 + native 层)

文章目录回顾线程消息队列时怎样实现的消息是怎么传递的&#xff1f;Handle 的延迟消息是怎么处理的&#xff1f;IdleHandler 的原理主线程进入了 Looper 循环为什么没有 ANR&#xff1f;消息屏障是什么&#xff1f;回顾 之前学习过Handler相关的基础知识&#xff0c;今天再学…

ESP-IDF + Vscode ESP32 开发环境搭建以及开发入门

ESP-IDF Vscode ESP32 开发环境搭建以及开发入门 文章目录ESP-IDF Vscode ESP32 开发环境搭建以及开发入门1. 前言2. 下载开发工具3. 配置工具4. 创建工程5. 解决vscode找不到头文件&#xff0c;波浪线警告6. 添加自己的组件6.1 组件说明6.2 添加项目组件6.3 添加扩展组件7. …

Python进阶篇(一)-- Django快速上手

1 Django概述 Web框架&#xff0c;就是用于开发Web服务器端应用的基础设施&#xff0c;说得通俗一点就是一系列封装好的模块和工具。事实上&#xff0c;即便没有Web框架&#xff0c;我们仍然可以通过socket或CGI来开发Web服务器端应用&#xff0c;但是这样做的成本和代价在商业…

Stable Diffusion 1 - 初始跑通 文字生成图片

文章目录关于 Stable DiffusionLexica代码实现安装依赖库登陆 huggingface查看 huggingface token下载模型计算生成设置宽高测试迭代次数生成多列图片关于 Stable Diffusion A latent text-to-image diffusion model Stable Diffusion 是一个文本到图像的潜在扩散模型&#xff…

撕开市场缺口,认养一头牛“犟心”能给谁?

随着疫情防控政策优化&#xff0c;2023年以来中国消费力和投资活动均迎来复苏。其中&#xff0c;乳制品赛道受益于国内消费者健康消费理念的加强&#xff0c;呈现出稳步增长的势头。一方面&#xff0c;乳制品消费需求旺盛&#xff0c;市场未来可期。据中商研究院预计&#xff0…

【Hello Linux】Linux环境下写的第一个程序 -- 进度条

作者&#xff1a;小萌新 专栏&#xff1a;Linux 作者简介&#xff1a;大二学生 希望能和大家一起进步&#xff01; 本篇博客简介&#xff1a;写出Linux中的第一个小程序 进度条 进度条小程序行缓冲区概念\r 和 \n进度条代码和演示行缓冲区概念 我们首先用两段代码来感受下行缓…