有趣味的能够下载源码调试 spring-cloud-alibaba 源码地址 版本 2021.1
本篇文章次要目标是阐明流程,所以除了办法名是源码以外,其余代码有简写或 重写 ,可看作 伪代码,只为了表白逻辑和展现流程。
一个代码块中调用办法的内容根本能够本代码块或上面一个代码块中找到。
服务注册
nacos 服务器就是一个 web 我的项目,对 nacos 的所有操作都就是发送一个 http 申请,所以只须要找到 spring-cloud-alibaba-nacos 在什么中央发送了这个申请。
-
spring boot 启动时,会调用 spring 的 refresh 办法实现 spring 的启动,在启动的最初,调用
finishRefresh
办法。这个办法的最终目标是调用 spring 容器中所有SmartLifecycle
实现类的start
办法@Override public void refresh() throws BeansException, IllegalStateException { //... finishRefresh(); //... }
protected void finishRefresh() { //... // 初始化生命周期处理器, 默认为 DefaultLifecycleProcessor initLifecycleProcessor(); // 调用生命周期处理器的 onRefresh getLifecycleProcessor().onRefresh(); //... }
public class DefaultLifecycleProcessor{ @Override public void onRefresh() {startBeans(true); } private void startBeans(boolean autoStartupOnly) { // 获取 spring 容器中 SmartLifecycle 的实现类的 bean SmartLifecycle beans=getSmartLifecycleBeans(); for(SmartLifecycle bean:beans){ //SmartLifecycle 实现了 Phased 接口,能够返回一个 int 值,示意调用程序 // 数字越小的越先调用 int phase=beans.getPhase(); // 把 bean 放入 LifecycleGroup 中,phase 雷同的放到同一个 LifecycleGroup // 目标在于能够对立调用 phase 雷同的 bean 的办法 LifecycleGroup lifecycleGroups=new LifecycleGroup(phase,bean)); } // 依据 phase 的值排序 sort(lifecycleGroups); // 依据顺序调用 LifecycleGroup 的 start lifecycleGroups.start();} // 这是一个外部类 private class LifecycleGroup {public void start() {doStart(bean); } private void doStart(){bean.start() } } }
-
spring boot 提供了一个
SmartLifecycle
的实现类WebServerStartStopLifecycle
,并且重写了start
办法// 这个是 servlet 包下的,反应式的在 reactive 包下,同样也是公布事件 package org.springframework.boot.web.servlet.context; public void start() { // 在 start 办法中公布了个事件,示意 Servlet web 服务器已初始化实现 applicationContext.publishEvent(new ServletWebServerInitializedEvent()); }
// 这个事件的继承关系 public class ServletWebServerInitializedEvent extends WebServerInitializedEvent
-
spring-cloud 提供了个抽象类监听了
WebServerInitializedEvent
事件public abstract class AbstractAutoServiceRegistration<R extends Registration> implements ApplicationListener<WebServerInitializedEvent> { // 这里应用了装璜器模式,须要从子类中传入数据 protected AbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry, AutoServiceRegistrationProperties properties) { this.serviceRegistry = serviceRegistry; this.properties = properties; } public void onApplicationEvent(WebServerInitializedEvent event) {this.bind(event); } public void bind(WebServerInitializedEvent event) {this.start(); } // 这里调用的是 nacos 实现类再调用 super,但子类中并没有什么重要逻辑,所以省略 public void start() {this.register(); } // 上方一顿调用,调到这里,这里就是 spring-cloud 提供的主动注册逻辑 protected void register() { // 从子类获取 Registration 并应用子类传入的 serviceRegistry 进行注册 this.serviceRegistry.register(this.getRegistration()); } protected abstract R getRegistration();}
简略看一下
Registration
和ServiceRegistry
两个接口-
public interface ServiceInstance {String getServiceId(); String getHost(); int getPort();} //Registration 的子类须要返回注册所需的根本信息 public interface Registration extends ServiceInstance {}
-
// 把 Registration 传入 register 办法,在子类中实现注册逻辑 public interface ServiceRegistry<R extends Registration> {void register(R registration); }
-
-
spring-cloud-alibaba-nacos 提供了
AbstractAutoServiceRegistration
的实现类,从继承关系来看,实质是一个监听了WebServerInitializedEvent
的监听器public class NacosAutoServiceRegistration extends AbstractAutoServiceRegistration<Registration>{ // 传入注册器和注册所需根本信息 public NacosAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry, AutoServiceRegistrationProperties properties, NacosRegistration registration) { // 把 serviceRegistry 传入父类 super(serviceRegistry, autoServiceRegistrationProperties); this.registration = registration; } @Override // 返回 registration protected NacosRegistration getRegistration() {return this.registration;} }
NacosAutoServiceRegistration 对象是在主动配置类中创立的,springboot 主动配置的大抵逻辑
springboot 启动时会获取 classpath*:META-INF/spring.factories 中的键值对
再应用 spring 的通用解析逻辑去解析 value 所示意的类,实现解析的办法是:
org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass
#spring-cloud-starter-alibaba-nacos-discovery 包中的 spring.factories 文件,这只是其中一个 value org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration
public class NacosServiceRegistryAutoConfiguration { @Bean public NacosServiceRegistry nacosServiceRegistry() {return new NacosServiceRegistry(); } @Bean public NacosRegistration nacosRegistration() {return new NacosRegistration(); } @Bean public NacosAutoServiceRegistration nacosAutoServiceRegistration( NacosServiceRegistry registry, NacosRegistration registration) {return new NacosAutoServiceRegistration(registry, registration); } }
-
nacos 的注册逻辑
public class NacosServiceRegistry implements ServiceRegistry<Registration>{ @Override public void register(Registration registration) { // 这个 NamingService 是 nacos-api 包中的类,是在主动配置类中 HealthIndicator // 创立的过程中被创立,这里是通过一个管理器去获取 //NamingService 中蕴含了服务的获取、注册、删除等办法 NacosNamingService namingService = namingService(); // 应用 registration 创立一个服务实例 Instance instance = createNacosInstance(registration); // 注册服务 namingService.registerInstance(serviceId, group, instance); }
public class NacosNamingService implements NamingService{ @Override public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException { // 结构心跳信息 BeatInfo beatInfo = beatReactor.buildBeatInfo(groupedServiceName, instance); // 发送心跳信息,也就是每隔一段时间就向 nacos 服务器发一个申请,// 服务器收到后解析申请就能晓得该服务没有下线 //beatReactor 在结构器中被创立 beatReactor.addBeatInfo(groupedServiceName, beatInfo); // 发送注册申请 //serverProxy 在结构器中被创立 serverProxy.registerService(groupedServiceName, groupName, instance); } }
// 这个代码块是发送心跳逻辑 public class BeatReactor{public void addBeatInfo(String serviceName, BeatInfo beatInfo) { // 这是一个定时线程池,默认为虚拟机最大可用处理器数量的一半 // 具体调用的是 Runtime.getRuntime().availableProcessors()数量包含超线程,但不是肯定精确。// 第一个参数是要执行的工作,第二个是延迟时间,默认 5 秒,第三个是工夫单位 executorService.schedule(new BeatTask(beatInfo), beatInfo.getPeriod(), TimeUnit); } } class BeatTask implements Runnable { @Override public void run() { // 发送心跳信息 serverProxy.sendBeat(beatInfo); // 这里又调用了本人,造成了递归,所以会每 5 秒就向 nacos 服务器发送信息 executorService.schedule(new BeatTask(beatInfo), beatInfo.getPeriod(), TimeUnit); } }
这是 nacos 官网提供的注册申请实例,所以只须要构建出这个申请发给 nacos 服务器就行了
curl -X POST ‘http://127.0.0.1:8848/nacos/v…
// 发送注册逻辑 public class NamingProxy {public void registerService(String serviceName, String groupName, Instance instance) throws NacosException { //instance 中蕴含了注册服务所需的信息,信息起源为 NacosDiscoveryProperties 和其余中央 // 应用传入的三个参数构建 params // 构建 header // 构建 uri // 应用 NacosRestTemplate 发送申请,外面应用了 JdkHttpClientRequest,// 再外面应用了 sun.net.www.protocol.http.HttpURLConnection // 申请往 nacos 服务器一发,完事。// 在这个 http 申请有返回值,nacos 也创立了一个 ResponseHandler 去把返回值解析为 HttpRestResult // 但在这个流程中最终没有应用返回值。// 心跳的发送也是 http 申请,所以与注册的逻辑是差不多的。reqApi(UtilAndComs.nacosUrlInstance, params, HttpMethod.POST); } }
总结
一. spring,启动实现后调用 SmartLifecycle
的start
办法
二. spring-boot,提供了 SmartLifecycle
的实现类 WebServerStartStopLifecycle
,在start
中公布了ServletWebServerInitializedEvent
三. spring-cloud,应用一个抽象类 AbstractAutoServiceRegistration
监听了 ServletWebServerInitializedEvent
,通过调用子类的ServiceRegistry
和Registration
注册服务
四. spring-cloud-alibaba-nacos,提供了 AbstractAutoServiceRegistration
的实现类NacosServiceRegistryAutoConfiguration
,并在主动配置类中初始化。
五. nacos,在 NacosServiceRegistryAutoConfiguration
中实现具体的 http 申请的构建与发送