Spring Cloud 源码分析之 Eureka 篇第八章:服务注册名称的来历
欢迎访问我的 GitHub
这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos
关于服务注册名称
服务注册名称,是指 Eureka client 注册到 Eureka server 时,用于标记自己身份的标志,举例说明,以下是个简单的 Eureka client 配置:
这样配置的应用,启动后如果在 Eureka server 注册成功,那么 Eureka server 的 home 页面信息如下,红框中就是注册名称:
本文目标是通过分析 Eureka client 源码来找出这个名称是如何创建的;
关于源码版本
本次分析的 Spring Cloud 版本为 Edgware.RELEASE,对应的 eureka-client 版本为 1.7.0;
从启动说起
在 spring-cloud-commons 库的 META-INF 目录下有 spring.factories 文件,这是 spring 扩展规范的实现,这里面配置的类会被实例化,其中就包含了 HostInfoEnvironmentPostProcessor 这个类,如下图红框所示:
HostInfoEnvironmentPostProcessor 实现了 EnvironmentPostProcessor 接口,来看看官方文档对 EnvironmentPostProcessor 的描述:
上图红框中说明开发者可以自定义环境变量;
上图绿框中说明 EnvironmentPostProcessor 的实现类必须在 spring.factories 文件中定义;
因此 HostInfoEnvironmentPostProcessor 类的作用已经清楚了:自定义环境变量;
HostInfoEnvironmentPostProcessor 源码如下:
上述代码有两处需要注意:
第一,设置了两个环境变量:spring.cloud.client.hostname 和 spring.cloud.client.ipAddress;
第二,getFirstNonLoopbackHostInfo 方法返回的对象中,127.0.0.1 这样的 IP 地址是会被过滤掉的,过滤逻辑很简单,源码在 Inet4Address 类的 isLoopbackAddress 方法:
小结:HostInfoEnvironmentPostProcessor 的作用是把本机的 hostname 和 IP 地址设置到环境变量中;
在配置类中保存服务名称
接下来看看配置类 EurekaClientAutoConfiguration,这里面主要是和 Eureka 相关的配置信息的数据和逻辑;
请看方法 eurekaInstanceConfigBean,该方法向 Spring 容器环境提供 EurekaInstanceConfigBean 实例,注意 instance.setInstanceId(getDefaultInstanceId(propertyResolver)) 这一行:
顺藤摸瓜,展开方法 getDefaultInstanceId:
如上述代码所示,真相大白,服务注册名称一共有三部分:hostname、应用名称、自定义实例 ID,如果自定义实例 ID 没有配置就用监听端口代替;
此时再来回顾之前在 Eureka server 的 home 页面上看到的服务注册名:localhost:springcloud-deep-provider:8082,果然与源码一致;
源码读到此处,禁不住手痒,按照上面的逻辑,在应用的 aplication.yml 中增加配置项 spring.application.instance_id,看看能否生效,改过的 aplication.yml 内容如下图所示,红框中是新增的自定义实例 ID 配置:
重启应用,重新注册到 Eureka server,此时再看 home 页面如下图红框,服务注册名称果然已经更新:
使用配置类中的服务名称
现在我们知道了 EurekaInstanceConfigBean 实例的 instanceId 字段被设置为"hostname:应用名称:自定义实例 ID",接下来看该字段如何被提交到 Eureka server;
在 EurekaClientAutoConfiguration 类中有个 eurekaApplicationInfoManager 方法,为 spring 容器提供了 ApplicationInfoManager 实例:
如上所示,spring 容器中有了 ApplicationInfoManager 实例,就可以通过该实例获得服务注册名称;
Eureka client 向 Eureka server 发起服务注册的操作是在 DiscoveryClient 类中进行的,该类的构造方法如下:
如上图所示,红框中 ApplicationInfoManager 实例被注入,蓝框中表明 DiscoveryClient 的成员变量 instanceInfo 获得了 InstanceInfo 实例;
具体的注册逻辑在 DiscoveryClient 的 register 方法中,可见成员变量 instanceInfo 被当作入参传入了注册逻辑的 API:
上述代码中的 eurekaTransport.registrationClient.register(instanceInfo) 方法,经过层层调用,最终调用了 AbstractJerseyEurekaHttpClient 类的 register 方法,如下图所示:
上图的红框表明,POST 请求时 InstanceInfo 实例被作为请求参数提交到了 Eureka server;
Wireshark 抓包验证
至此,代码分析已经结束了,最后我们用 Wireshark 抓包来验证之前的分析结果,在 Eureka client 所在电脑上用 Wireshark2.6.3 来分析注册请求:
如上图所示,红框中就是注册请求,绿框中是请求包头的全部内容,也就是前面看到的 InstanceInfo 实例的内容,蓝框中的内容,就是服务注册名称的键值对,值就是 Eureka server 收到的注册名称;
最后来小结一下,服务注册名称从诞生到提交至 Eureka server 的过程:
HostInfoEnvironmentPostProcessor 将本机的 hostname 和 IP 地址设置到应用环境变量中;
配置类 EurekaClientAutoConfiguration 中,创建一个 EurekaInstanceConfigBean 类型的 bean,其 instanceId 字段就是即将上报到 Eureka server 的自身名称,instanceId 字段的内容由 hostname、应用名称、自定义实例 ID 拼接而成,其中自定义实例 ID 来自配置项"spring.application.instance_id",如果不存在就用服务监听端口代替;
ApplicationInfoManager 类型的 bean 在创建时被注入 EurekaInstanceConfigBean 实例,用于创建 ApplicationInfoManager 的成员变量 instanceInfo;
DiscoveryClient 的构造方法中注入了 ApplicationInfoManager,于是 DiscoveryClient 的成员变量 instanceInfo 就被赋值为 ApplicationInfoManager 的成员变量 instanceInfo;
DiscoveryClient 的 register 方法负责注册到 Eureka server 的逻辑,用到的参数就是成员变量 instanceInfo;
发起注册网络请求的操作最终由 AbstractJerseyEurekaHttpClient 类的 register 方法完成,POST 的内容就是 instanceInfo 实例;
欢迎关注 InfoQ:程序员欣宸
版权声明: 本文为 InfoQ 作者【程序员欣宸】的原创文章。
原文链接:【http://xie.infoq.cn/article/0138ad74ff5f9b20d7cd0785a】。文章转载请联系作者。
评论