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方法我们下篇文章去写

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jackson陈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值