tars源码解析3-springboot启动

Posted Small leaf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了tars源码解析3-springboot启动相关的知识,希望对你有一定的参考价值。

从spring xml ,spring JavaConfig,spring boot ,spring cloud。原理从始到终都是没有任何变化的,只要我们掌握了最核心的只不过是表现方式不同了。所以有了
技术万变不离其中

tars一样的,如果玩转它。
从前面两篇,分析而言。要改成springboot的方式,无非就是使用它的方式改变了,核心是不会变的。

使用方式有哪几个变化呢?

  1. 启动方式,springboot starter方式,注解启动。
  2. 注解服务。

围绕这两个变化。
我们知道了tars服务启动需要启动哪些类,初始化哪些类,同理starter无非是jar包中配置了引入启动类,监听器org.springframework.context.ApplicationListener。然后注解@EnableTarsServer引入初始化某个类而已。

非常熟悉spring与springboot生命周期的,那更加清楚,不仅仅是这两种方式,还有很多种,可以使用。

服务解析方式发生改变,以前是读取xml,读取javaConfig文件,现在变成注解而已。跟我练习,如何使用注解呢?

  1. 定义注解
  2. 标记类
  3. springboot生命周期中扫描这些类,判断有没有TarsServant注解标记了,有那么就取出,放入服务中即可。
  4. 客户端使用,TarsClient,无非就是一个生命周期中的类,来初始化扫描这些标记了的类。怎么处理呢?客户端启动服务,从注解中心拿去服务,然后通过tarsClient的服务名称去连接(没连接当然细节很多,比如说负载均衡,如果连接上了那么就不需要连接,心跳检测,服务心跳检测,等等),标记的类,然后通过动态代理成新的类,来处理就可以。

是不是很简单,只要知道了原理,springboot只是改变了启动方式而已。
讲了那么多来再来分析tars是怎么使用springboot的吧,通过总结前面两篇和springboot来对比。

我相信,以后出现了一个新的,你也能写一个starter,写一个注解来实现,没什么问题。

这里我从tars xml启动方式,自己设想如何改造成springboot,以及tars写好的springboot 来对比实现。

1. tars服务端启动

1.1 xml方式

  1. 初始化Server。加载config(服务器节点配置文件),初始化协调器,以及服务器与注册中心管理(心跳,服务器状态,上报埋点信息)。
    private Server() 
       System.out.println("[TARS] start server construction");
       loadServerConfig();
       initCommunicator();
       startManagerService();
   
  1. startUp。启动服务,包含读取servants,进行服务连接。启动web容器等等。
   public void startUp(AppContext appContext) 
        try 
            startAppContext(appContext);
            startSessionManager();
            registerServerHook();
            System.out.println("[SERVER] server is ready...");
         catch (Throwable ex) 
            System.out.println("[SERVER] failed to start server...");
            ex.printStackTrace();
            System.out.close();
            System.err.close();
            System.exit(-1);
        
    

整个xml 核心就是这里,结束,完成。然后改造成springboot方式太多太多了。

1.2 自己想的springboot方式

首先明白一点,Server启动,加载,与web容器初始化的顺序。

new Server();只是初始化server与注解中心的连接,此时与spring容器是无关的,因此它可以最先初始化。

startUp();这里面需要接寻找被注解标志的服务类,因此这个必须要在spring容器启动时。

那么新建一个注解,EnableTarsSever。
这个注解是用来实现这个Server的。Import(TarsServerAutoConfiguration.class)
TarsServerAutoConfiguration就是用来配置Server的。也就是new Server()。

那么startUp什么时候调用呢? 我们要明白一点,tars服务就这是一个服务,服务里面会调用其他spring容器的bean。所以我们一定是要等spring容器初始化完成之后再来调用startUp();

SmartLifecycle 是一个接口。当Spring容器加载所有bean并完成初始化之后,会接着回调实现该接口的类中对应的方法(start()方法)

所以新建一个类,SpringSmartLifecycle实现了SmartLifecycle,然后springbean初始化调用start,也就是startUp。

然后@TarsServer 标记哪些类时服务ok。

然后springboot start使用。springboot 启动的时候会去自动加载配置文件,
springfactory 里面的org.springframework.boot.autoconfigure.EnableAutoConfiguration。
在start里面写上TarsServerAutoConfiguration,那么引用starter启动服务就可以了,无需任何其他的,如果不需要这个服务直接exclude就可以了。

1.3 tars自己的实现

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TarsServerConfiguration.class)
public @interface EnableTarsServer 

@Configuration
@Import(TarsManageServiceConfiguration.class)
public class TarsServerConfiguration 
    @Bean
    public Server server() 
        return new Server(ConfigurationManager.getInstance().getServerConfig());
    

    @Bean
    public TarsServerStartLifecycle applicationStartLifecycle(Server server) 
        return new TarsServerStartLifecycle(server);
    


public class TarsServerStartLifecycle implements SmartLifecycle

所有还是创建了一个EnableTarsServer来开启。

org.springframework.context.ApplicationListener=\\
com.qq.tars.spring.bean.ManageServiceListener,\\
com.qq.tars.spring.bean.PropertiesListener


public class ManageServiceListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> 
    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) 
        System.out.println("[TARS] init manage service");

        Server.loadServerConfig();
        Server.initCommunicator();
        Server.configLogger();
        Server.startManagerService();
    

springboot ApplicationListener spring容器启动的时候会先执行ApplicationListener ,所以整个流程是。

  1. 加入了starter包。
  2. 启动springboot,执行了ApplicationListener,执行Server的初始化
  3. EnableTarsSever。然后执行loadServants,执行initSevant。

2.tars客户端实现

这是客户端调用方式,

       CommunicatorConfig cfg = new CommunicatorConfig();
        // 从本地启动的Communcator
        Communicator communicator = CommunicatorFactory.getInstance().getCommunicator(cfg);
        //warn 若是部署在tars平台启动的, 只能使用下面的构造器获取communcator
        //Communicator communicator = CommunicatorFactory.getInstance().getCommunicator();
        HelloPrx proxy = communicator.stringToProxy(HelloPrx.class, "TestApp.HelloServer.HelloObj@tcp -h 127.0.0.1 -p 18601 -t 60000");
        //同步调用
        String ret = proxy.hello(1000, "Hello World");
        System.out.println(ret);

无非spring的实现方式,就是通过注解,然后代理注入成ObjectProxy。
原理和@autowire 一毛一样。

也就是再对象在初始化时,将类的成员变量,初始化依赖注入成想要的,那么。
就是实现BeanPostProcessor在类初始化时进行变量初始化,此时就可以进行依赖注入,通过判断是否有TarsClient,标志的服务。
有就去通过


            ServantProxyConfig config = new ServantProxyConfig(objName);
            CommunicatorConfig communicatorConfig = ConfigurationManager.getInstance().getServerConfig().getCommunicatorConfig();
            config.setModuleName(communicatorConfig.getModuleName(), communicatorConfig.isEnableSet(), communicatorConfig.getSetDivision());
            config.setEnableSet(annotation.enableSet());
            config.setSetDivision(annotation.setDivision());
            if (StringUtils.isNotEmpty(annotation.setDivision())) 
                config.setEnableSet(true);
                config.setSetDivision(annotation.setDivision());
            
            config.setConnections(annotation.connections());
            config.setConnectTimeout(annotation.connectTimeout());
            config.setSyncTimeout(annotation.syncTimeout());
            config.setAsyncTimeout(annotation.asyncTimeout());
            config.setTcpNoDelay(annotation.tcpNoDelay());
            config.setCharsetName(annotation.charsetName());

            Object proxy = communicator.stringToProxy(field.getType(), config);

            ReflectionUtils.makeAccessible(field);
            ReflectionUtils.setField(field, bean, proxy);

这样我们的类就被依赖注入成 TarsClient对象了,ok。

一切就是这样,一个套路。

接下来我要去了解tars更加深入的,管理阶段。

以上是关于tars源码解析3-springboot启动的主要内容,如果未能解决你的问题,请参考以下文章

tars源码解析1--服务端启动

tars源码解析1--服务端启动

tars源码解析2-客户端启动

tars源码解析2-客户端启动

>>>>> 附3 springboot源码解析 - 构建SpringApplication

Spring Boot 启动源码解析二