• 分布式_事务_02_2PC框架raincat源码解析


    一、前言

    上一节已经将raincat demo工程运行起来了,这一节来分析下raincat的源码

    二、协调者启动过程

    主要就是在启动类中通过如下代码来启动 netty

    nettyService.start()

    三、参与者启动过程

    1.参与者启动时序图

    参与者在启动过程中,主要做了如下4件事:

    (1)保存SpringContext上下文

    (2)通过加载spi,来使用用户自定义配置

    (3)启动Netty客户端,与txManager进行连接,并且维持心跳。

    (4)启动事务补偿任务,建表,定时补偿。

    (5)启动事务事件发布器。

    如下图:

    2.保存Spring上下文

    源码见  SpringBeanUtils 类,设置Spring 上下文,并提供spring  bean 的注册与获取方法。

    /*
     * Licensed to the Apache Software Foundation (ASF) under one or more
     * contributor license agreements.  See the NOTICE file distributed with
     * this work for additional information regarding copyright ownership.
     * The ASF licenses this file to You under the Apache License, Version 2.0
     * (the "License"); you may not use this file except in compliance with
     * the License.  You may obtain a copy of the License at
     *
     *     http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package com.raincat.core.helper;
    
    import org.springframework.context.ConfigurableApplicationContext;
    
    /**
     * SpringBeanUtils.
     * @author xiaoyu
     */
    public final class SpringBeanUtils {
    
        private static final SpringBeanUtils INSTANCE = new SpringBeanUtils();
    
        private ConfigurableApplicationContext cfgContext;
    
        private SpringBeanUtils() {
            if (INSTANCE != null) {
                throw new Error("error");
            }
        }
    
        /**
         * get SpringBeanUtils.
         * @return SpringBeanUtils
         */
        public static SpringBeanUtils getInstance() {
            return INSTANCE;
        }
    
        /**
         * acquire spring bean.
         *
         * @param type type
         * @param <T>  class
         * @return bean
         */
        public <T> T getBean(final Class<T> type) {
            return cfgContext.getBean(type);
        }
    
        /**
         * register bean in spring ioc.
         * @param beanName bean name
         * @param obj bean
         */
        public void registerBean(final String beanName, final Object obj) {
            cfgContext.getBeanFactory().registerSingleton(beanName, obj);
        }
    
        /**
         * set application context.
         * @param cfgContext application context
         */
        public void setCfgContext(final ConfigurableApplicationContext cfgContext) {
            this.cfgContext = cfgContext;
        }
    }
    View Code

    3.加载spi

        /**
         * load spi.
         *
         * @param txConfig {@linkplain TxConfig}
         */
        private void loadSpi(final TxConfig txConfig) {
            //spi  serialize
            final SerializeProtocolEnum serializeProtocolEnum
                    = SerializeProtocolEnum.acquireSerializeProtocol(txConfig.getSerializer());
            final ServiceLoader<ObjectSerializer> objectSerializers
                    = ServiceBootstrap.loadAll(ObjectSerializer.class);
            final ObjectSerializer serializer =
                    StreamSupport.stream(objectSerializers.spliterator(), false)
                            .filter(s -> Objects.equals(s.getScheme(), serializeProtocolEnum.getSerializeProtocol()))
                            .findFirst().orElse(new KryoSerializer());
    
            //spi  RecoverRepository support
            final CompensationCacheTypeEnum compensationCacheTypeEnum
                    = CompensationCacheTypeEnum.acquireCompensationCacheType(txConfig.getCompensationCacheType());
    
            final ServiceLoader<TransactionRecoverRepository> recoverRepositories
                    = ServiceBootstrap.loadAll(TransactionRecoverRepository.class);
            final TransactionRecoverRepository repository =
                    StreamSupport.stream(recoverRepositories.spliterator(), false)
                            .filter(r -> Objects.equals(r.getScheme(), compensationCacheTypeEnum.getCompensationCacheType()))
                            .findFirst().orElse(new JdbcTransactionRecoverRepository());
            //将compensationCache实现注入到spring容器
            repository.setSerializer(serializer);
            SpringBeanUtils.getInstance().registerBean(TransactionRecoverRepository.class.getName(), repository);
        }
    View Code

    (1)作用

    SPI的全名为Service Provider Interface,该机制其实就是为接口寻找服务实现类

    (2)如何使用

    当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。
    该文件里就是实现该服务接口的具体实现类。
    而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。

    八、参考资料

    1.Java之SPI机制

  • 相关阅读:
    LPT算法--时间调度问题
    Java语法学习1
    用JS动态显示文本
    用JS动态创建一个有序表(根据输入添加子列表项)
    邻接表链式结构的实现和顺序结构的实现
    HDU 1242 特殊化带结构体BFS
    POJ 1562深搜判断连体油田个数
    Uva 8道比较水的数论 (练练英语阅读理解)
    HDU 2024 C语言合法标识符(笑)
    再做POJ2406 KMPnext数组的运用
  • 原文地址:https://www.cnblogs.com/shirui/p/9674428.html
Copyright © 2020-2023  润新知