文章目录
一. 问题背景
想要对spring应用做扩展,达到spring应用可以SpringBoot应用那样自动注册服务到nacos的功能。
参考自: 【java进阶课程】玩转spring cloud alibaba易如反掌,从入门到精通nacos
二. 前言
-
nacos官方文档可以去nacos.io或者spring.io中的alibaba模块学习。视频中的讲师推荐去spring.io官网参考(因为nacos.io有小小的毛病),但是由于国内无法访问github.io域名的页面,只能去nacos.io参考了。
-
本文从源码级别讲解,因此需要使用idea启动nacos,笔者启动的时候遇到了挺多坑,如何使用idea单机启动nacos请看源码启动单机运行nacos
-
本文旨在讲原理,不必过分在某些细节纠结,对原理了解个大概就好了。后面还会再写更细致更深入的博客,一切细节根据自己所用的springboot版本等。
三. 资源准备
- nacos源码:前往nacos的github页面下载,用来启动nacos的
- springboot工程:前往gitee页面下载,用来研究nacos自动服务注册的源码
四. 原理
4.1 快速开始构建spring应用的nacos步骤
前往nacos-spring官方手册,可见如下:
解释: 从上面可以大概看到,spring应用将服务注册到nacos中,大概就是发一个请求,某个controller会处理该请求,然后controller中会调用某些service方法做处理,然后注册服务。
4.2 问题分析
从上面也可以看到,spring应用是不能自动注册服务到nacos中的,需要手动发一个请求去注册,因此我们要对spring做扩展,把spring应用自动注册到nacos里面。
那么到底如何实现?我们可以参考spring cloud alibaba nacos是怎么做自动注册的。
4.3 Spring Cloud Alibaba Nacos的自动服务注册大概原理
如下图所示:
4.4 源码分析Spring Cloud Commons模块的服务注册原理
4.4.1 引入依赖
新建一个SpringBoot应用并引入以下nacos-discovery依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
在加了@SpringBootApplication
的主类上加@EnableDiscoveryClient
,就可以在SpringBoot应用程序启动的时候进行自动服务注册到nacos。
4.4.2 服务注册的核心方法
切入点是位于org.springframework.cloud.client
包下的ServiceRegistry
接口的register()
方法,如下:
package org.springframework.cloud.client.serviceregistry;
public interface ServiceRegistry<R extends Registration> {
void register(R registration);
//...此处省略其他代码
}
Nacos对该接口方法的实现是com.alibaba.cloud.nacos.registry
包下的NacosServiceRegistry
的register()
方法。 方法如下:
@Override
public void register(Registration registration) {
if (StringUtils.isEmpty(registration.getServiceId())) {
log.warn("No service to register for nacos client...");
return;
}
NamingService namingService = namingService();
String serviceId = registration.getServiceId();
String group = nacosDiscoveryProperties.getGroup();
Instance instance = getNacosInstanceFromRegistration(registration);
try {
namingService.registerInstance(serviceId, group, instance);
log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,
instance.getIp(), instance.getPort());
}
catch (Exception e) {
log.error("nacos registry, {} register failed...{},", serviceId,
registration.toString(), e);
// rethrow a RuntimeException if the registration is failed.
// issue : https://github.com/alibaba/spring-cloud-alibaba/issues/1132
rethrowRuntimeException(e);
}
}
解释:以上这个代码块就是nacos做自动服务注册的核心代码。
结合前面nacos.io官方手册看到的注册服务的步骤,可以大概知道如下:
4.4.3 服务注册的调用关系
逆向 查找调用关系(用idea的find usage找找,但是我的不行)
NacosServiceRegistry#register()
<-ServiceRegistry#register()
<-AbstractAutoServiceRegistration()#register()
<-AbstractAutoServiceRegistration#start()
<-AbstractAutoServiceRegistration#bind()
<-AbstractAutoServiceRegistration#onApplicationEvent()
解释:最终的核心方法register()
是被ServiceRegistry
中的register()
调用的;而ServiceRegistry
的register()
方法是被AbstractAutoServiceRegistration
的register()
方法调用的,以此类推
总结:由此可知,客户端能完成自动服务注册的功能是因为一启动的时候调用了AbstractAutoServiceRegistration#onApplicationEvent()
4.4.4 更底层的原理
是用了Spring的 事件监听机制(观察者模型,事件编程模型)。(Spring用了很多模式,比如有代理设计模式)
4.5 利用事件监听机制完成自动服务注册的原理(重要)
五. 课外知识
5.1 Spring应用重构成微服务的方案
- 先将spring应用拆分成各个模块,比如订单模块,登录模块,权限模块等。
- 然后再将spring cloud等组件添加进去。切忌直接spring应用重构成spring cloud 微服务,因为spring cloud组件太多,不容易调bug
5.2 WebServerInitializerEvent事件在哪里发布的?
根据SpringBoot版本的不同,发布的地方也可能不同。
六. 总结
- 首先必须要知道spring cloud做了服务注册的接口标准,而nacos作为产品,是对spring cloud做的接口进行整合实现的。一个是做标准,另一个是做实现。必须要理清这点。
- spring cloud项目的commons模块定义了服务注册的接口标准
- nacos的自动服务注册就是按着spring cloud commons的服务注册的接口标准来实现的