1

Spring Cloud源码分析之Eureka篇第三章:EnableDiscoveryClient与EnableEurekaClient...

 1 year ago
source link: https://blog.51cto.com/zq2599/5447117
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

欢迎访问我的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. 一点遗留问题待确定;

问题的起源

  • 在使用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
@EnableDiscoveryClient
public 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,内容如下图:

    Spring Cloud源码分析之Eureka篇第三章:EnableDiscoveryClient与EnableEurekaClient的区别(Edgware版本)_spring
  • 我的理解:注册发现服务有三种实现方式: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源码分析之Eureka篇第三章:EnableDiscoveryClient与EnableEurekaClient的区别(Edgware版本)_spring_02
  • 因此,如果您使用的Spring Cloud版本是Edgware或者更新的版本,您在考虑EnableDiscoveryClient和EnableEurekaClient的区别时,Spencer Gibb在StackOverflow上的那个解释就未必准确了,因为您的版本距离他当时的版本已经有了两年以上的间隔;

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

  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
@EnableDiscoveryClient
public @interface EnableEurekaClient {

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

Edgware版本中EnableEurekaClient的变化

  • 来看看Edgware版本中,EnableEurekaClient.java的内容:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface EnableEurekaClient {

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

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

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

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

    Spring Cloud源码分析之Eureka篇第三章:EnableDiscoveryClient与EnableEurekaClient的区别(Edgware版本)_spring_04
  • 我对以上内容的理解:

  1. EnableDiscoveryClient注解现在是可选项了(你用不用这个注解,是不会影响服务注册发现功能的);
  2. 只要依赖了以spring-cloud-starter-netflix为前缀的库(例如spring-cloud-starter-netflix-eureka-client),就启用了服务注册发现功能;
  3. 使用配置项**spring.cloud.service-registry.auto-registration.enabled=false即可禁止服务注册发现功能</blue>;
  • 从官方博客上看来EnableDiscoveryClient注解已经不会影响服务注册发现功能了;

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

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

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

    Spring Cloud源码分析之Eureka篇第三章:EnableDiscoveryClient与EnableEurekaClient的区别(Edgware版本)_java_05
  • 上图是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源码分析之Eureka篇第三章:EnableDiscoveryClient与EnableEurekaClient的区别(Edgware版本)_spring cloud_06
  • 只依赖以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,如下图:

Spring Cloud源码分析之Eureka篇第三章:EnableDiscoveryClient与EnableEurekaClient的区别(Edgware版本)_java_07
  • EurekaDiscoveryClientConfiguration负责启动实现服务注册发现功能,实现机制相对复杂,在此不展开细说了,看看部分源码如下:
Spring Cloud源码分析之Eureka篇第三章:EnableDiscoveryClient与EnableEurekaClient的区别(Edgware版本)_spring cloud_08
  • 真相大白:服务注册发现功能是否启动,是由配置类EurekaDiscoveryClientConfiguration控制的,在Edgware版本中,如果开启了springboot的自动配置,那么EurekaDiscoveryClientConfiguration就会生效,因此不是靠EnableDiscoveryClient注解来控制了;

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

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

Spring Cloud源码分析之Eureka篇第三章:EnableDiscoveryClient与EnableEurekaClient的区别(Edgware版本)_spring_09
  • 真相大白:在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间接依赖了:
Spring Cloud源码分析之Eureka篇第三章:EnableDiscoveryClient与EnableEurekaClient的区别(Edgware版本)_spring cloud_10
  • 之前的疑惑已解开,分析如下:
  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已经没用了;

欢迎关注51CTO博客:程序员欣宸

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK