TX-LCN分佈式事務框架源碼解析(服務端-1-@EnableTransactionManagerServer執行流程)

 

前面的代理都是爲了寫源碼做鋪墊的,因爲LCN模式就是用的靜態代理,採用對數據庫連接的代理來完成分佈式事務的。

首先看我們的服務端,前面在例子中已經把服務端和客戶端的代碼都貼出來了,服務端很簡單,只需要一個註解就能開啓分佈式事務服務端功能。

註解@EnableTransactionManagerServer

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(value = {TMAutoConfiguration.class})
public @interface EnableTransactionManagerServer {
}

引入了TMAutoConfiguration類,所有的功能都在TMAutoConfiguration類中,從名稱上看是自動配置類

@Configuration
@ComponentScan
@Import({TxLoggerConfiguration.class, MessageConfiguration.class})
@EnableJpaRepositories("com.codingapi.txlcn.tm.support.db.jpa")
@EntityScan("com.codingapi.txlcn.tm.support.db.domain")
public class TMAutoConfiguration {

    @Bean(destroyMethod = "shutdown")
    public ExecutorService executorService() {
        int coreSize = Runtime.getRuntime().availableProcessors() * 2;
        return new ThreadPoolExecutor(coreSize, coreSize, 0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>()) {
            @Override
            public void shutdown() {
                super.shutdown();
                try {
                    this.awaitTermination(10, TimeUnit.MINUTES);
                } catch (InterruptedException ignored) {
                }
            }
        };
    }

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
        return restTemplateBuilder.build();
    }

    @Bean
    @ConditionalOnMissingBean
    public FastStorageProvider fastStorageProvider(RedisTemplate<String, Object> redisTemplate,
                                                   StringRedisTemplate stringRedisTemplate, TxManagerConfig managerConfig) {
        return () -> new RedisStorage(redisTemplate, stringRedisTemplate, managerConfig);
    }

    @Bean
    public FastStorage fastStorage(FastStorageProvider fastStorageProvider) {
        return fastStorageProvider.provide();
    }

    @Bean
    public TxLcnApplicationRunner txLcnApplicationRunner(ApplicationContext applicationContext) {
        return new TxLcnApplicationRunner(applicationContext);
    }

    @Bean
    @ConditionalOnMissingBean
    public ModIdProvider modIdProvider(ConfigurableEnvironment environment, ServerProperties serverProperties) {
        return () -> ApplicationInformation.modId(environment, serverProperties);
    }
}

這裏算是所有的配置都在這了,

1、引入日誌配置(日誌就不細說了)

2、引入消息配置MessageConfiguration類,配置了一些客戶端與服務端通信的類

3、開啓了jpa支持把一些事物信息寫入數據庫(不細說)

4、自定義線程池

5、構建了restTemplate   Bean

6、構建FastStorageProvider  Bean 此類用來提供快速存儲類,需要三個參數,這裏默認構建RedisStorage

7、根據FastStorageProvider 構建RedisStorage

8、構建TxLcnApplicationRunner  Bean 用於spring boot啓動後做些事情

9、構建ModIdProvider Bean 返回模塊標識。

MessageConfiguration

public class MessageConfiguration {


    @Bean
    @ConditionalOnMissingBean
    @ConfigurationProperties("tx-lcn.message.netty")
    //rpc的配置如心跳,重試,緩存鎖數量
    public RpcConfig rpcConfig() {
        return new RpcConfig();
    }

    @Bean
    @ConditionalOnMissingBean
    //rpc應答類,只是打印了消息
    public RpcAnswer rpcClientAnswer() {
        return rpcCmd -> log.info("cmd->{}", rpcCmd);
    }

    @Bean
    @ConditionalOnMissingBean
    //rpc負載均衡策略,採用RandomLoadBalance類
    public RpcLoadBalance rpcLoadBalance() {
        return new RandomLoadBalance();
    }


    @Bean
    @ConditionalOnMissingBean
    //客戶端初始化回調類,只打印日誌
    public ClientInitCallBack clientInitCallBack() {
        return new DefaultClientInitCallback();
    }

    @Bean
    @ConditionalOnMissingBean
    //rpc連接監聽器,默認實現
    public RpcConnectionListener rpcConnectionListener(){
        return new DefaultRpcConnectionListener();
    }

    @Bean
    @ConditionalOnMissingBean
    //心跳監聽器,默認空實現
    public HeartbeatListener heartbeatListener(){
        return new DefaultHeartbeatListener();
    }
}

 

FastStorageProvider  快速存儲生成接口

FastStorageProvider  這實際是個接口,只有一個方法provide,用來生成快速存儲類

public interface FastStorageProvider {

    /**
     * TM FastStorage's implementation.
     *
     * @return fast storage's implementation
     */
    FastStorage provide();
}

RedisStorage 快速存儲類

FastStorage的唯一實現,用於操作redis完成事物的操作,內部封裝了RedisTemplate與StringRedisTemplate。

其功能比如:事物組相關操作;事物狀態相關操作;分佈式鎖的操作;TM的機器列表操作;token操作等。

TxLcnApplicationRunner  

TxLcnApplicationRunner類實現了ApplicationRunner接口,並實現了run方法,springboot在啓動後會自動調用實現了ApplicationRunner接口類的run方法,代碼如下

public class TxLcnApplicationRunner implements ApplicationRunner, DisposableBean {
    
    private final ApplicationContext applicationContext;
    
    private List<TxLcnInitializer> initializers;
    
    @Autowired
    public TxLcnApplicationRunner(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
    
    @Override
    public void run(ApplicationArguments args) throws Exception {
        //獲取容器中實現了TxLcnInitializer接口的類,並排序
        Map<String, TxLcnInitializer> runnerMap = applicationContext.getBeansOfType(TxLcnInitializer.class);
        initializers = runnerMap.values().stream().sorted(Comparator.comparing(TxLcnInitializer::order))
                .collect(Collectors.toList());
        //循環調用txLcnInitializer的init()方法
        for (TxLcnInitializer txLcnInitializer : initializers) {
            txLcnInitializer.init();
        }
    }
    
    @Override
    public void destroy() throws Exception {
        for (TxLcnInitializer txLcnInitializer : initializers) {
            txLcnInitializer.destroy();
        }
    }
    
}

重點是run方法,找到容器中的所有的TxLcnInitializer並調用其init方法

ModIdProvider  模塊標識

這個類的作用是生成當前模塊的標識,標識生成策略在ApplicationInformation類的modId方法中

public static String modId(ConfigurableEnvironment environment, ServerProperties serverProperties) {

        String applicationName = environment.getProperty("spring.application.name");
        applicationName = StringUtils.hasText(applicationName) ? applicationName : "application";
        return applicationName + ":" + serverPort(serverProperties);
    }
 public static int serverPort(ServerProperties serverProperties) {
        return Objects.isNull(serverProperties) ? 0 : (Objects.isNull(serverProperties.getPort()) ? 8080 :
                serverProperties.getPort());
    }

標識生成規則是

1、如果配置了spring.application.name 與server.port 則,則模塊標識爲spring.application.name :server.port

2、如果沒有則是application:8080

大概的代碼流程就是這些,重要的工作在於執行所有TxLcnInitializer的init方法我們下篇文章去寫

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章