从spring xml ,spring JavaConfig,spring boot ,spring cloud。原理从始到终都是没有任何变化的,只要我们掌握了最核心的只不过是表现方式不同了。所以有了
技术万变不离其中
tars一样的,如果玩转它。
从前面两篇,分析而言。要改成springboot的方式,无非就是使用它的方式改变了,核心是不会变的。
使用方式有哪几个变化呢?
围绕这两个变化。
我们知道了tars服务启动需要启动哪些类,初始化哪些类,同理starter无非是jar包中配置了引入启动类,监听器org.springframework.context.ApplicationListener。然后注解@EnableTarsServer引入初始化某个类而已。
非常熟悉spring与springboot生命周期的,那更加清楚,不仅仅是这两种方式,还有很多种,可以使用。
服务解析方式发生改变,以前是读取xml,读取javaConfig文件,现在变成注解而已。跟我练习,如何使用注解呢?
是不是很简单,只要知道了原理,springboot只是改变了启动方式而已。
讲了那么多来再来分析tars是怎么使用springboot的吧,通过总结前面两篇和springboot来对比。
我相信,以后出现了一个新的,你也能写一个starter,写一个注解来实现,没什么问题。
这里我从tars xml启动方式,自己设想如何改造成springboot,以及tars写好的springboot 来对比实现。
private Server() {
System.out.println("[TARS] start server construction");
loadServerConfig();
initCommunicator();
startManagerService();
}
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方式太多太多了。
首先明白一点,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就可以了。
@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 {
@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 ,所以整个流程是。
这是客户端调用方式,
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更加深入的,管理阶段。