写点什么

Spring Cloud 源码分析之 Eureka 篇第三章:EnableDiscoveryClient 与 EnableEurekaClient 的区别 (Edgware 版本)

作者:程序员欣宸
  • 2022 年 7 月 06 日
  • 本文字数:5424 字

    阅读完需:约 18 分钟

Spring Cloud源码分析之Eureka篇第三章:EnableDiscoveryClient与EnableEurekaClient的区别(Edgware版本)

欢迎访问我的 GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos


  • 在基于 SpringCloud 做开发的时候,EnableDiscoveryClient 和 EnableEurekaClient 这两个注解我们并不陌生,今天就来聊聊它们的区别,和网上更早期的类似文章不同的是:本文会聊到 Dalston 之后的版本中,这两个注解的区别;

Spring Cloud 版本说明

  • 大致发展情况如下:Angle -> Brixton -> Camden -> Dalston -> Edgware -> Finchley

文章概览

  • 全文由以下几部分组成,注意 Dalston 版本是个很重要的时间点,这之后的版本中 EnableDiscoveryClient、EnableEurekaClient 的作用发生了很大的变化,因此我们接下来的讨论都要先分清楚是 Dalston 版本之前还是之后:


  1. 问题的起源;

  2. 来自作者的权威答案(Dalston 或更早期的版本);

  3. 官方文档(Dalston 或更早期的版本);

  4. 看源码(Dalston 或更早期的版本);

  5. Edgware 版本中 EnableEurekaClient 的变化;

  6. Edgware 版本官方文档对 EnableDiscoveryClient 的解释;

  7. 源码揭示 EnableDiscoveryClient 的变化;

  8. 一点遗留问题待确定;

  9. 小结;

问题的起源

  • 在使用 Spring Cloud 的 Dalston 版本或更早期的版本中,为了将应用发布到 Eureka 注册中心,我们会在配置类中增加 @EnableDiscoveryClient 或者 @EnableEurekaClient 注解,例如以下代码:


package com.bolingcavalry.springclouddeepprovider;
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication@EnableDiscoveryClientpublic class SpringclouddeepproviderApplication {
public static void main(String[] args) { SpringApplication.run(SpringclouddeepproviderApplication.class, args); }}
复制代码


  • 于是就有了疑问:EnableDiscoveryClient 和 EnableEurekaClient 的区别和关系。

来自作者的权威答案(Dalston 或更早期的版本)

  • 请注意,下面这段内容的背景是 Spring Cloud 的 Dalston 版本,或更早期的版本,这一点很重要!

  • EnableDiscoveryClient 和 EnableEurekaClient 的区别在网上有不少文章分析,但最权威的答案应该来自这两个类的作者 Spencer Gibb,他在 StackOverflow 上有回复,地址是:https://stackoverflow.com/questions/31976236/whats-the-difference-between-enableeurekaclient-and-enablediscoveryclient,内容如下图:


  • 我的理解:注册发现服务有三种实现方式:eureka、consul、zookeeper,EnableDiscoveryClient 注解在 common 包中,通过项目的 classpath 来决定使用哪种实现,而 EnableEurekaClient 注解在 netflix 包中,只会使用 eureka 这种实现方式;

  • 有两个时间点需要注意:


  1. Spencer Gibb 的这段话发表于 2015 年 8 月 13 日;

  2. Spencer Gibb 于 2017 年 10 月 25 日,在 Spring 官方博客宣布Edgware.RC1版本发布,如下图,此时距离他在 StackOverflow 上那个回答已经过去了两年:


  • 因此,如果您使用的 Spring Cloud 版本是 Edgware 或者更新的版本,您在考虑 EnableDiscoveryClient 和 EnableEurekaClient 的区别时,Spencer Gibb 在 StackOverflow 上的那个解释就未必准确了,因为您的版本距离他当时的版本已经有了两年以上的间隔;

官方文档(Dalston 或更早期的版本)

  • 在 Spring 官方博客,于 2014 年 12 月 9 日宣布 Spring Cloud 1.0.0.RC1 发布,地址是:https://spring.io/blog/2014/12/19/spring-cloud-1-0-0-rc1-available-now,里面有段描述如下图红框所示:


  • 我对以上描述的理解:


  1. 服务注册发现功能被抽象后放入 spring-cloud-commons 库,该库的 EnableDiscoveryClient 可以取代旧的 EnableEurekaClient,使用注解 EnableDiscoveryClient 就能启用服务注册发现功能;

  2. 同理,EnableHystrix 也被 EnableCircuitBreaker 取代了;


  • 可见,从 Spring Cloud 1.0.0.RC1 版本开始,就已经不推荐使用 EnableEurekaClient 和 EnableHystrix 了;

看源码(Dalston 或更早期的版本)

  • 看一下 Dalston 版本的 EnableEurekaClient 源码:


@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@EnableDiscoveryClientpublic @interface EnableEurekaClient {
}
复制代码


  • 上述代码显示,EnableEurekaClient 中使用了 EnableDiscoveryClient,因此,从使用者角度来看两者确实已经没有什么区别了,按照官方的建议使用 EnableDiscoveryClient 其实是个不错的选择;

Edgware 版本中 EnableEurekaClient 的变化

  • 来看看 Edgware 版本中,EnableEurekaClient.java 的内容:


@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inheritedpublic @interface EnableEurekaClient {
}
复制代码


  • 如上所示,之前版本中的 @EnableDiscoveryClient 注解已经不存在了,而且也没有用到任何 @Import 注解,因此,EnableEurekaClient 这个注解已经没什么用处了,在代码中用不用它,是没什么差别的;

Edgware 版本官方文档对 EnableDiscoveryClient 的解释

  • Dalston 之后的第一个版本为 Edgware,Spring 官方博客在 2017 年 10 月 25 日宣布发布,一起来看看此版本的 EnableEurekaClient 和 EnableDiscoveryClient 的区别;

  • 首先还是看官方博客,关键信息如下图:


  • 我对以上内容的理解:


  1. EnableDiscoveryClient 注解现在是可选项了(你用不用这个注解,是不会影响服务注册发现功能的);

  2. 只要依赖了以 spring-cloud-starter-netflix 为前缀的库(例如 spring-cloud-starter-netflix-eureka-client),就启用了服务注册发现功能;

  3. 使用配置项 spring.cloud.service-registry.auto-registration.enabled=false 即可禁止服务注册发现功能


  • 从官方博客上看来 EnableDiscoveryClient 注解已经不会影响服务注册发现功能了;

如何理解“@EnableDiscoveryClient is now optional”?

  • 既然注解 @EnableDiscoveryClient 用或者不用都不影响服务注册发现功能,那为什么官方文档将其描述为"is now optional"(可选项),为什么不直接废弃这个注解呢?

  • 从官方文档对 EnableDiscoveryClient 的描述,我们可以看个明白,如下图:


  • 上图是 Edgware 版本的开发文档,地址:http://cloud.spring.io/spring-cloud-static/Edgware.SR4/multi/multi__spring_cloud_commons_common_abstractions.html#__enablediscoveryclient

  • 从上图描述可以看出,spring 容器在查询 spring.factories 的过程中,如果找到了 EnableDiscoveryClient 的配置,就会实例化该配置对应的服务注册发现:例如 eureka、consul、zookeeper 等;

  • 红框中提到,EnableDiscoveryClient 不是必须的,只要 classpath 中存在 DiscoveryClient 的实现就可以保证将应用注册到注册中心了,这个功能是如何实现的,后面我们会分析到(和 spring.factories 有关);

源码揭示 EnableDiscoveryClient 的变化

  • 通过源码来确认官方文档的信息,这种方式可以加深对 Spring Cloud 的理解;

  • 寻找突破点:

  • 面对浩瀚的源码,如何下手呢?前面官方文档的那句话给了我们一个线索,如下图红框所示:



  • 只依赖以 spring-cloud-starter-netflix 为前缀的库(例如 spring-cloud-starter-netflix-eureka-client),就启用了服务注册发现功能,这个特性让我想起了 spring 容器通过 META-INF/spring.factories 文件加载配置的能力;

  • 于是打开工程 spring-cloud-netflix-eureka-client(Edgware 版对应的该工程版本号为 1.4.0.RELEASE),去看 src\main\resources\META-INF 目录下的 spring.factories 文件,发现在 springboot 的自动配置项中,出现了一个关键配置 EurekaDiscoveryClientConfiguration,如下图:



  • EurekaDiscoveryClientConfiguration 负责启动实现服务注册发现功能,实现机制相对复杂,在此不展开细说了,看看部分源码如下:



  • 真相大白:服务注册发现功能是否启动,是由配置类 EurekaDiscoveryClientConfiguration 控制的,在 Edgware 版本中,如果开启了 springboot 的自动配置,那么 EurekaDiscoveryClientConfiguration 就会生效,因此不是靠 EnableDiscoveryClient 注解来控制了;

  • 现在我们对 Edgware 版本的服务注册发现已经有所了解,再去看看 Dalston 版本下的 spring.factories,应该能有不少收获;

  • Dalston 版的 Spring Cloud,其 spring-cloud-netflix-eureka-client 工程的版本号为 1.3.6.RELEASE,打开该工程下面的 spring.factories 文件,内容如下:



  • 真相大白:在 Dalston 版本下,使用注解 EnableDiscoveryClient 才会使配置类 EurekaDiscoveryClientConfiguration 生效;

一点遗留问题待确定

  • 前面我们在 Edgware 和 Dalston 版本下分别打开 spring-cloud-netflix-eureka-client 工程的 spring.factories,通过对比 spring.factories,弄清楚了服务注册发现功能是如何启动的;

  • 但是似乎有个问题:


  1. 在 Edgware 版本中,官方建议使用 spring-cloud-netflix-eureka-client 作为 starter;

  2. 在 Dalston 版本中,官方建议使用 spring-cloud-starter-eureka 作为 start,也就是所我们的 pom.xml 中并没有出现 spring-cloud-netflix-eureka-client;


  • 那么问题来了,如果 Dalston 版本中没有用到 spring-cloud-netflix-eureka-client 库,那么它的 spring.factories 自然也就不会生效,那我们刚才的分析岂不是无用了?

  • 除非是被 pom.xml 中的其他库间接依赖了,还是创建一个工程来验证一下吧;

  • 基于 maven 创建一个 springboot 工程,里面依赖了 Spring Cloud 的 Dalston 版本,pom.xml 内容如下:


<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  <modelVersion>4.0.0</modelVersion>
<groupId>com.bolingcavalry</groupId> <artifactId>springclouddeepprovider</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging>
<name>springclouddeepprovider</name> <description>Demo project for Spring Cloud service provider</description>
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR5</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>
复制代码


  • 注意 starter 用的是 spring 官方推荐的 spring-cloud-starter-eureka,现在工程目录下执行命令 mvn dependency:tree 看依赖关系,如下图红框所示,spring-cloud-netflix-eureka-client 被 spring-cloud-starter-eureka 间接依赖了:



  • 之前的疑惑已解开,分析如下:


  1. 由于 spring-cloud-starter-eureka 的间接依赖,spring-cloud-netflix-eureka-client 会出现在 classpath 中;

  2. 因此 spring 启动时会扫描到 spring-cloud-netflix-eureka-client.jar 包中的 spring.factories 文件;

  3. 如果当前工程使用了 EnableDiscoveryClient 注解,按照 spring.factories 中的配置,配置类 EurekaDiscoveryClientConfiguration 会生效,进而开启服务注册发现功能;

小结

  • 至此,EnableDiscoveryClient 与 EnableEurekaClient 的区别我们已经全部弄明白了,在这里小结一下吧:

  • 在 Spring Cloud 的 Dalston 及其之前的版本中:


  1. 从 2014 年的 Spring Cloud 1.0.0.RC1 版本开始,官方就推荐使用 EnableDiscoveryClient 来取代 EnableEurekaClient;

  2. EnableEurekaClient 源码中使用了注解 EnableDiscoveryClient,因此如果要使用 eureka 的注册发现服务,两者功能是一样的;

  3. EnableDiscoveryClient 注解在 spring.factories 配置中通过配置项 EurekaDiscoveryClientConfiguration 来开启服务注册发现功能;


  • 在 Dalston 之后的版本中(不含 Dalston):


  1. 在 spring.factories 配置中,配置类 EurekaDiscoveryClientConfiguration 被配置到 springboot 的自动配置注解中,与 EnableDiscoveryClient 注解没有关系了,也就是说只要开启了 springboot 的自动配置,服务注册发现功能就会启用;

  2. EnableEurekaClient 源码中没有使用注解 EnableDiscoveryClient,此时 EnableEurekaClient 已经没用了;

欢迎关注 InfoQ:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...

发布于: 刚刚阅读数: 3
用户头像

搜索"程序员欣宸",一起畅游Java宇宙 2018.04.19 加入

前腾讯、前阿里员工,从事Java后台工作,对Docker和Kubernetes充满热爱,所有文章均为作者原创,个人Github:https://github.com/zq2599/blog_demos

评论

发布
暂无评论
Spring Cloud源码分析之Eureka篇第三章:EnableDiscoveryClient与EnableEurekaClient的区别(Edgware版本)_Java_程序员欣宸_InfoQ写作社区