到底是Nacos先进行服务注册,还是Tomcat先启动

公众号:Hoeller,有精品面试题(不是很多,150道,但很经典)

答案还是比较简单,肯定是Tomcat先得启动,不然如果先进行服务注册,那么可能在Tomcat还没启动完成的情况下就有服务消费者拿到服务地址进行服务调用了,从而导致调用失败。结论得出来了,但是具体是怎么实现的呢,让我来带大家一探究竟。

Spring Cloud中想要使用Nacos进行服务注册,就需要引入以下starter:

而这个starter中会引入一个叫做NacosServiceRegistryAutoConfiguration的自动配置类,而这个自动配置类中则定义了一个NacosAutoServiceRegistration类型的Bean,这个Bean看名字(翻译过来就是Nacos自动服务注册)就能知道是用来进行服务注册的,NacosAutoServiceRegistration的父类是AbstractAutoServiceRegistration,该类不是Nacos实现的,而是Spring Cloud实现的,该类的定义为:

从定义可以看出,该类实现了Spring的ApplicationListener接口,所以,NacosAutoServiceRegistration会监听WebServerInitializedEvent事件,一旦接收到该事件就会进行服务注册。

AbstractAutoServiceRegistration中的调用流程依次是:

NacosAutoServiceRegistration中重写了register()方法,所以最终服务注册的核心逻辑是由Nacos来具体实现的,具体细节本文就不展开了(关注我,后续文章会详细分析),从以上流程我们就能知道:当Nacos接收到WebServerInitializedEvent事件时就会进行服务注册

从以上过程可以看出,服务注册的时间点其实是由AbstractAutoServiceRegistration定义的,也就是由Spring Cloud定义的,Nacos只是负责实现具体的注册逻辑。

那么WebServerInitializedEvent事件又是什么时候发布的呢?

通过debug调用栈,我发现WebServerInitializedEvent事件是由一个叫WebServerStartStopLifecycle的对象中的start()方法发布出来的:

上述代码中会先调用webServer的start()方法,而WebServer在Spring Boot中是一个接口,本质上就是代表Tomcat或Jetty或Undertow,而在当前场景中webServer就是Tomcat,所以从上述代码就可以得出结论:Tomcat会先启动,启动完成后发布WebServerInitializedEvent事件,从而触发Nacos的服务注册。

那么Tomcat又是在Spring Boot启动过程的什么时间节点启动的呢?

通过debug,发现WebServerStartStopLifecycle的start()方法是通过AbstractApplicationContext中的finishRefresh()方法调过来的,我们知道Spring Boot启动过程中会创建并启动Spring 容器,而一个Spring容器启动完成后会发布ContextRefreshedEvent事件,而发布事件的代码也是在finishRefresh()中实现的,源码为:

上述代码中的getLifecycleProcessor().onRefresh()就会调用WebServerStartStopLifecycle中的start()方法,而getLifecycleProcessor().onRefresh()的下一行代码就是发布ContextRefreshedEvent事件。

所以我们可以知道在Spring容器启动的最后,发布ContextRefreshedEvent事件的前一步就会启动Tomcat。

不过Spring容器启动过程中,在调用finishRefresh()之前其实会先调用onRefresh()方法,而Spring Boot中重写了onRefresh()方法,并且在该方法中也会做和Tomcat相关的事情,那就是初始化Tomcat,比如生成出Tomcat对象、配置端口等,但没有真正进行启动Tomcat。

所以,结合我们常见的一些知识点,我最后得出结论,整个过程是这样的:

  1. 启动Spring Boot
  2. 执行ApplicationContextInitializer等
  3. 启动Spring容器
  4. 解析配置类(扫描、解析自动配置类)
  5. 调用onRefresh(),初始化Tomcat
  6. 实例化非懒加载的单例Bean
  7. 调用finishRefresh()
  8. 调用WebServerStartStopLifecycle中的start()
  9. 启动Tomcat
  10. 发布ServletWebServerInitializedEvent,从而触发Nacoo进行服务注册
  11. 发布ContextRefreshedEvent事件

我是爱读源码的大都督周瑜,欢迎关注我的公众号:Hoeller。公众号里有更多高质量干货系列文章和精品面试题。

记得点赞、分享哦!!!

展开阅读全文

页面更新:2024-03-12

标签:初始化   容器   源码   结论   公众   定义   过程   事件   代码   方法

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top