在SpringCloud组件:Eureka服务注册是采用主机名仍是IP地址?文章中咱们讲到了服务注册
的几种注册方式
,那么这几种注册方式
的源码是怎么实现的呢?咱们带着这一个疑问来阅读本章内容可以让你更深刻了解这块的知识点!!!git
分析每一种服务注册方式
源码执行流程。github
本章以分析源码为主,因此不去新建立项目来说解相关内容,咱们使用SpringCloud组件:Eureka服务注册是采用主机名仍是IP地址?源码做为注册服务
,SpringCloud组件:搭建Eureka服务注册中心源码做为服务注册中心
,仍是按照以前的运行流程:spring
- 启动服务注册中心
- 启动本章服务项目
- 查看服务列表,服务注册方式
在开始讲解本章注册方式
以前,咱们须要了解总体的配置信息
获取的流程信息,这样才能够分析指定的注册方式
执行流程。数据库
EurekaInstanceConfigBean
配置实体在项目启动时因为依赖spring-cloud-starter-netflix-eureka-client
内经过配置spring.factories
文件来让项目启动时自动加载并实例化org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration
配置类,EurekaClientAutoConfiguration
内会自动实例化EurekaInstanceConfigBean
而且自动绑定eureka.instance
开头的配置信息(具体为何会自动映射能够去了解下@ConfigurationProperties
注解做用),部分源码以下所示:bash
......
public class EurekaClientAutoConfiguration {
//省略部分源码
@Bean
@ConditionalOnMissingBean(value = EurekaInstanceConfig.class, search = SearchStrategy.CURRENT)
public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils, ManagementMetadataProvider managementMetadataProvider) {
//省略部分源码
// 传递
EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils);
// 省略部分源码
}
//省略部分源码
}
复制代码
EurekaClientAutoConfiguration#eurekaInstanceConfigBean
方法只有知足@ConditionalOnMissingBean(value = EurekaInstanceConfig.class, search = SearchStrategy.CURRENT)
表达式后才会去实例化,而且把实例化对象放入到IOC
容器内容,BeanId
为eurekaInstanceConfigBean
,也就是方法的名称。 在EurekaClientAutoConfiguration#eurekaInstanceConfigBean
方法中有这么一行代码咱们能够进行下一步的分析微信
// 经过有参构造函数实例化EurekaInstanceConfigBean配置实体
EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils);
复制代码
经过调用EurekaInstanceConfigBean(InetUtils inetUtils)
构造函数来进行实例化EurekaInstanceConfigBean
对象,在这个构造函数内也有一些实例化的工做,源码以下:网络
public EurekaInstanceConfigBean(InetUtils inetUtils) {
this.inetUtils = inetUtils;
this.hostInfo = this.inetUtils.findFirstNonLoopbackHostInfo();
this.ipAddress = this.hostInfo.getIpAddress();
this.hostname = this.hostInfo.getHostname();
}
复制代码
InetUtils#findFirstNonLoopbackHostInfo
获取主机基本信息在构造函数EurekaInstanceConfigBean(InetUtils inetUtils)
源码实现内hostInfo
主机信息经过了InetUtils#findFirstNonLoopbackHostInfo
方法来进行实例化,咱们来看看这个方法的具体实现逻辑,它会自动读取系统网卡列表
然再进行循环遍历
查询正在UP
状态的网卡信息,若是没有查询到网卡信息,则使用默认的HostName
、IpAddress
配置信息,源码以下所示:mybatis
public HostInfo findFirstNonLoopbackHostInfo() {
InetAddress address = findFirstNonLoopbackAddress();
if (address != null) {
return convertAddress(address);
}
HostInfo hostInfo = new HostInfo();
hostInfo.setHostname(this.properties.getDefaultHostname());
hostInfo.setIpAddress(this.properties.getDefaultIpAddress());
return hostInfo;
}
public InetAddress findFirstNonLoopbackAddress() {
InetAddress result = null;
try {
int lowest = Integer.MAX_VALUE;
for (Enumeration<NetworkInterface> nics = NetworkInterface
.getNetworkInterfaces(); nics.hasMoreElements();) {
NetworkInterface ifc = nics.nextElement();
if (ifc.isUp()) {
log.trace("Testing interface: " + ifc.getDisplayName());
if (ifc.getIndex() < lowest || result == null) {
lowest = ifc.getIndex();
}
else if (result != null) {
continue;
}
// @formatter:off
if (!ignoreInterface(ifc.getDisplayName())) {
for (Enumeration<InetAddress> addrs = ifc
.getInetAddresses(); addrs.hasMoreElements();) {
InetAddress address = addrs.nextElement();
if (address instanceof Inet4Address
&& !address.isLoopbackAddress()
&& isPreferredAddress(address)) {
log.trace("Found non-loopback interface: "
+ ifc.getDisplayName());
result = address;
}
}
}
// @formatter:on
}
}
}
catch (IOException ex) {
log.error("Cannot get first non-loopback address", ex);
}
if (result != null) {
return result;
}
try {
return InetAddress.getLocalHost();
}
catch (UnknownHostException e) {
log.warn("Unable to retrieve localhost");
}
return null;
}
复制代码
默认的HostName
、IpAddress
属性配置信息在InetUtilsProperties
配置实体类内,若是不进行设置则直接使用默认值,若是你想更换默认值
,那么你能够在application.yml
配置文件内经过设置spring.cloud.inetutils.defaultHostname
、spring.cloud.inetutils.defaultIpAddress
进行修改默认值,源码以下所示:app
public class InetUtilsProperties {
public static final String PREFIX = "spring.cloud.inetutils";
/**
* The default hostname. Used in case of errors.
*/
private String defaultHostname = "localhost";
/**
* The default ipaddress. Used in case of errors.
*/
private String defaultIpAddress = "127.0.0.1";
}
复制代码
EurekaInstanceConfigBean#getHostName
方法实现getHostName
是一个Override
的方法,继承于com.netflix.appinfo.EurekaInstanceConfig
接口,该方法有个boolean
类型的参数refresh
来判断是否须要刷新从新获取主机网络基本信息,当传递refresh=false
而且在application.yml
配置文件内并无进行手动设置eureka.instance.hostname
以及eureka.instance.ip-address
参数则会根据eureka.instance.prefer-ip-address
设置的值进行返回信息,源码以下所示:框架
@Override
public String getHostName(boolean refresh) {
if (refresh && !this.hostInfo.override) {
this.ipAddress = this.hostInfo.getIpAddress();
this.hostname = this.hostInfo.getHostname();
}
return this.preferIpAddress ? this.ipAddress : this.hostname;
}
复制代码
因为在实例化EurekaInstanceConfigBean
配置实体类时,构造函数进行了获取第一个非回环主机信息
,默认的hostName
以及ipAddress
参数则是会直接使用InetUtils#findFirstNonLoopbackHostInfo
方法返回的相对应的值。
EurekaInstanceConfigBean#getHostName
方法直接调用本类重载方法getHostName(boolean refresh)
而且传递参数为false
,根据第三步源码咱们就能够看到:
return this.preferIpAddress ? this.ipAddress : this.hostname;
复制代码
若是eureka.instance.prefer-ip-address
参数设置了true
就会返回eureka.instance.ip-address
的值,这样咱们就能够从中明白为何主动设置eureka.instance.ip-address
参数后须要同时设置eureka.instance.prefer-ip-address
参数才能够生效。
咱们经过application.yml
配置文件进行设置eureka.instance.hostname
以及eureka.instance.ip-address
后会直接替换原默认值,在EurekaInstanceConfigBean#getHostName
中也是返回的this.hostname
、this.ipAddress
因此在这里设置后会直接生效做为返回的配置值。
咱们经过源码进行分析服务注册方式
执行流程,这样在之后进行配置eureka.instance.hostname
、eureka.instance.prefer.ip-address
、eureka.instance.ip-address
三个配置信息时就能够根据优先级顺序达到预期的效果,避免没有必要的错误出现。
本章源码在这
):访问码云查看源码若是你有技术相关的问题想要咨询
恒宇少年
,请去博客首页左侧导航栏,点击知识星球
微信扫码加入个人星球。
若是你喜欢
恒宇少年
的相关文章,那么就去微信公众号(恒宇少年
)关注我吧!!! 固然你也能够去 SpringCloud码云源码 项目底部扫描微信公众号二维码关注我,感谢阅读!!!
这段时间一直在编写开源的相关框架,致力于公司使用的框架升级以及开源计划,将公司使用到的工具
以及插件
进行升级重构而且开源。
code-builder
代码生成器根据你提供的模板文件(目前支持freemarker
)自动生成实体类,能够很大颇有效的提升开发效率。 Gitee地址
:gitee.com/hengboy/cod… Github地址
:github.com/hengyuboy/c…mybatis-enhance
是一个对mybatis
框架的加强封装,提供一系列的内部方法来完成单表数据的操做,多表数据提供DSL
方式进行操做。 Gitee地址
:gitee.com/hengboy/myb… Github地址
:github.com/hengyuboy/m…MyBatis-Pageable
是一款自动化分页的插件,基于MyBatis
内部的插件Interceptor
拦截器编写完成,拦截Executor.query
的两个重载方法计算出分页的信息以及根据配置的数据库Dialect
自动执行不一样的查询语句完成总数量的统计。 Gitee地址
:gitee.com/hengboy/myb…