从spring xml ,spring JavaConfig,spring boot ,spring cloud。原理从始到终都是没有任何变化的,只要我们掌握了最核心的只不过是表现方式不同了。所以有了
技术万变不离其中
tars一样的,如果玩转它。
从前面两篇,分析而言。要改成springboot的方式,无非就是使用它的方式改变了,核心是不会变的。
使用方式有哪几个变化呢?
- 启动方式,springboot starter方式,注解启动。
- 注解服务。
围绕这两个变化。
我们知道了tars服务启动需要启动哪些类,初始化哪些类,同理starter无非是jar包中配置了引入启动类,监听器org.springframework.context.ApplicationListener。然后注解@EnableTarsServer引入初始化某个类而已。
非常熟悉spring与springboot生命周期的,那更加清楚,不仅仅是这两种方式,还有很多种,可以使用。
服务解析方式发生改变,以前是读取xml,读取javaConfig文件,现在变成注解而已。跟我练习,如何使用注解呢?
- 定义注解
- 标记类
- springboot生命周期中扫描这些类,判断有没有TarsServant注解标记了,有那么就取出,放入服务中即可。
- 客户端使用,TarsClient,无非就是一个生命周期中的类,来初始化扫描这些标记了的类。怎么处理呢?客户端启动服务,从注解中心拿去服务,然后通过tarsClient的服务名称去连接(没连接当然细节很多,比如说负载均衡,如果连接上了那么就不需要连接,心跳检测,服务心跳检测,等等),标记的类,然后通过动态代理成新的类,来处理就可以。
是不是很简单,只要知道了原理,springboot只是改变了启动方式而已。
讲了那么多来再来分析tars是怎么使用springboot的吧,通过总结前面两篇和springboot来对比。
我相信,以后出现了一个新的,你也能写一个starter,写一个注解来实现,没什么问题。
这里我从tars xml启动方式,自己设想如何改造成springboot,以及tars写好的springboot 来对比实现。
1. tars服务端启动
1.1 xml方式
- 初始化Server。加载config(服务器节点配置文件),初始化协调器,以及服务器与注册中心管理(心跳,服务器状态,上报埋点信息)。
private Server() {
System.out.println("[TARS] start server construction");
loadServerConfig();
initCommunicator();
startManagerService();
}
- 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 ,所以整个流程是。
- 加入了starter包。
- 启动springboot,执行了ApplicationListener,执行Server的初始化
- 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更加深入的,管理阶段。
来源:CSDN
作者:Small leaf
链接:https://blog.csdn.net/u010399009/article/details/104236429