Spring Cloud——Eureka底层源代码解析
基础概念
Spring Cloud Eureka 是 Spring Cloud Netflix 微服务套件中的一部分,它基于 Netflix Eureka 做了二次封装,主要负责完成微服务架构中的服务治理功能。
主要模块
- 构建服务注册中心
- 服务注册与发现
- Eureka的基础架构
- Eureka的服务治理机制
- Eureka的配置
源码解析
1、属性加载过程
准备工作,搭建起一个基础架构,通过引入依赖,文件配置,开启启动类注解这三步的类似操作,进行服务注册中心,服务提供者,服务消费者的搭建,这里贴出一张图片,解释上面三者的关系与作用:
1)当启动应用时,会开启注解@EnableDiscoveryClient。
2)在application.yml文件中使用 eureka.client.serviceUrl.defaultZone 参数指定了服务注册中心的位置。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({EnableDiscoveryClientImportSelector.class})
public @interface EnableDiscoveryClient {
boolean autoRegister() default true;
}
通过这段代码和查找一些相关类,可以得出下面的 UML 类图:
来说说各个类和接口的作用:
- 接口 DiscoveryClient 用来发现服务的常用抽象方法,通过该接口可以有效地屏蔽服务治理的实现细节。
- 类 EurekaDiscoveryClient 是对上面接口的实现,同时也实现了对 Eureka 发现服务的封装,该类有又依赖了 EurekaClient 接口。
- 接口 EurekaClient、LookupService 二者都是 Netflix 开源包中的内容,定义了针对 Eureka 的发现服务的抽象方法。
- 类 DiscoveryClient 真正实现发现服务的类。
在了解 Eureka Client 负责完成任务之前,先看看在哪里对其 URL 列表进行配置。我们找到了 com.netflix.discovery.endpoint.EndpointsUtils 类,这个类中的下面这个函数解决了通过 serviceUrl 找到相关属性的加载属性。
public static Map<String, List<String>> getServiceUrlsMapFromConfig(EurekaClientConfig clientConfig, String instanceZone, boolean preferSameZone) {
//定义一个map集合,用来存放对应的zone和serviceUrl
Map<String, List<String>> orderedUrls = new LinkedHashMap();
String region = getRegion(clientConfig);
String[] availZones = clientConfig.getAvailabilityZones(clientConfig.getRegion());
if (availZones == null || availZones.length == 0) {
availZones = new String[]{"default"};
}
……
int myZoneOffset = getZoneOffset(instanceZone, preferSameZone, availZones);
String zone = availZones[myZoneOffset];
List<String> serviceUrls = clientConfig.getEurekaServerServiceUrls(zone);
if (serviceUrls != null) {
orderedUrls.put(zone, serviceUrls);
}
……
return orderedUrls;
- region:可以简单理解为地理上的分区,比如亚洲地区,或者华北地区,再或者北京等等,没有具体大小的限制。根据项目具体的情况,可以自行合理划分region。
- zone:可以简单理解为region内的具体机房,比如说region划分为北京,然后北京有两个机房,就可以在此region之下划分出zone1,zone2两个zone。
- 二者是一对多的关系,一个 region 可以对应多个不同的 zone。
- 默认情况下,会按照指定的region找到第一个zone。
上面的函数获取到了region和zone的信息之后,才开始真正加载Eureka Server 的具体地址:
//确定zone的offset
int myZoneOffset = getZoneOffset(instanceZone, preferSameZone, availZones);
//从availZones数组中获取到zone
String zone = availZones[myZoneOffset];
//从服务注册列表中获取到当前zone对应的serviceUrls
List<String> serviceUrls = clientConfig.getEurekaServerServiceUrls(zone);
关于获取 serviceUrls 的具体实现,可以查看以下源代码:
public List<String> getEurekaServerServiceUrls(String myZone) {
String serviceUrls = (String)this.serviceUrl.get(myZone);
if (serviceUrls == null || serviceUrls.isEmpty()) {
serviceUrls = (String)this.serviceUrl.get("defaultZone");
}
if (!StringUtils.isEmpty(serviceUrls)) {
String[] serviceUrlsSplit = StringUtils.commaDelimitedListToStringArray(serviceUrls);
List<String> eurekaServiceUrls = new ArrayList(serviceUrlsSplit.length);
String[] var5 = serviceUrlsSplit;
int var6 = serviceUrlsSplit.length;
for(int var7 = 0; var7 < var6; ++var7) {
String eurekaServiceUrl = var5[var7];
if (!this.endsWithSlash(eurekaServiceUrl)) {
eurekaServiceUrl = eurekaServiceUrl + "/";
}
eurekaServiceUrls.add(eurekaServiceUrl);
}
return eurekaServiceUrls;
} else {
return new ArrayList();
}
}