SpringCloud之Eureka

荒凉一梦 提交于 2020-02-04 01:51:55

Eureka是什么

Spring Cloud Eureka是Spring Cloud Netflix微服务套件的一部分,它是基于Netflix Eureka的二次封装,主要负责完成微服务中各个的服务注册与发现。假设我们有两个服务A和B,其中A服务需要调用到B服务来完成某个业务操作,如果没有注册中心,我们可能会将B服务的地址和接口API以配置文件的形式注入到应用中,但随着业务的增长,单个的服务B可能没法抗住压力,需要进行扩容和高可用,这时就需要频繁的去调整服务A代码中关于B服务的配置,这是很笨的。
我们假设这样一种场景:我们有多个服务B的实例,有一个特殊的服务C可以帮我们列出B服务的所有实例,并给这些服务起一个服务名,我们在A服务中通过这个服务名调用服务B的某个实例。这样若是服务B的实例发生变化,服务A并不需要编码或配置上的修改,Eureka在微服务架构中也恰恰起到了这个作用。

Spring Cloud、Spring Boot的版本问题

根据前面我们举得服务A、服务B以及管理服务B的特殊服务C,我们可以发现Eureka是分为两部分的,第一部分是承担维护服列表的服务C,我们称之为Eureka服务端,第二部分是服务A、服务B之类了的普通服务,我们称之为Eureka客户端。Eureka客户端会被注册到Eureka服务端,被其他服务进行调用,Eureka在微服务架构中起到了微服务中服务治理的作用。
这里讲一下Spring Cloud版本与Spring Boot的对应关系,如果版本之间搭配的有问题,就可能引出各种奇怪的问题,开始之前还是应该把版本统一好。我们可以通过访问这个地址https://start.spring.io/actuator/info来获取Spring Cloud与Spring Boot的对应关系,确定一下自己选的Spring Cloud与Spring Boot是互相适配没有问题的。在这里插入图片描述
我们这里用的Spring Cloud版本是Finchley.M2,Spring Boot版本是2.0.0.M3。至于Spring Cloud与其他几大服务组件的关系,在Spring Cloud的依赖中已经指定声明了,不需要我们再去操心。我们看一个Eureaka服务端的POM文件:

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.0.M3</version>
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
		</dependency>
	</dependencies>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<spring-cloud.version>Finchley.M2</spring-cloud.version>
	</properties>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

能看出我们用的Spring Boot版本是2.0.0.M3,Spring Cloud版本是Finchley.M2,引入了一个eureka-server依赖,却没有指定版本。我们点到spring-cloud-dependencies这个依赖的pom中去,发现定义了spring-cloud-netflix的版本,而Eureka就是netflix套件中的一部分。因此我们不必再操心Spring Cloud与各个微服务组件搭配时的版本问题。
在这里插入图片描述

Eureka的服务端

Eureka的服务端很好实现,最少配置就两步:

  1. 引入Eureka的依赖
	<dependency>
   		<groupId>org.springframework.cloud</groupId>
   		<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
   	</dependency>
  1. 对Spring Boot的启动类增加@EnableEurekaServer注解

@EnableEurekaServer的深入探究


/**
 * Annotation to activate Eureka Server related configuration {@link EurekaServerAutoConfiguration}
 */

@EnableDiscoveryClient
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EurekaServerMarkerConfiguration.class)
public @interface EnableEurekaServer {

}

类注释的意思是:这个注解是用来激活Eeureka Server相关配置EurekaServerAutoConfiguration的。同时我们发现这个注解还用到了@EnableDiscoveryClient,这说明Eeureka服务端同时也是一个Eeureka客户端,这里的@Import起到的作用是导入配置bean(@Import的详细作用我会再写一篇),我们看一下EurekaServerMarkerConfiguration的源码:

/**
 * Responsible for adding in a marker bean to activate
 * {@link EurekaServerAutoConfiguration}
 */
@Configuration
public class EurekaServerMarkerConfiguration {

	@Bean
	public Marker eurekaServerMarkerBean() {
		return new Marker();
	}

	class Marker {
	}
}

就单纯是为了实例化一个Marker的bean,用来激活EurekaServerAutoConfiguration这个类,我们看一下这个类的一些代码:

// 说明这是一个配置类
@Configuration
@Import(EurekaServerInitializerConfiguration.class)
// 这里体现了@EnableEurekaServer注解要引入一个EurekaServerMarkerConfiguration.Marker对象的原因,
// 是用来激活EurekaServerAutoConfiguration这个配置类
@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)
// @ConfigurationProperties注解可谓是SpringBoot最常用的属性配置相关的注解,但如果你自己尝试可以发现,
// 单一个@ConfigurationPropertie是不够的(如果没有同时被@Compent修饰)是无法将Bean注入进来,必须要用@EnableConfigurationProperties开启
@EnableConfigurationProperties({ EurekaDashboardProperties.class,
		InstanceRegistryProperties.class })
// 用于加载指定配置文件
@PropertySource("classpath:/eureka/server.properties")
public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter {
}

可以看到上面我们还有一行没有介绍,就是通过@Import导入的EurekaServerInitializerConfiguration这个配置类,从名字可以看出这个与Eureka服务端配置初始化相关。我们看一下这个类的代码:

@Configuration
public class EurekaServerInitializerConfiguration
		implements ServletContextAware, SmartLifecycle, Ordered {
	private ServletContext servletContext;
	@Autowired
	private EurekaServerBootstrap eurekaServerBootstrap;
	@Override
	public void setServletContext(ServletContext servletContext) {
		this.servletContext = servletContext;
	}
	@Override
	public void start() {
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					//TODO: is this class even needed now?
					eurekaServerBootstrap.contextInitialized(EurekaServerInitializerConfiguration.this.servletContext);
					log.info("Started Eureka Server");

					publish(new EurekaRegistryAvailableEvent(getEurekaServerConfig()));
					EurekaServerInitializerConfiguration.this.running = true;
					publish(new EurekaServerStartedEvent(getEurekaServerConfig()));
				}
				catch (Exception ex) {
					// Help!
					log.error("Could not initialize Eureka servlet context", ex);
				}
			}
		}).start();
	}
}

由于篇幅原因,这里只粘贴了一部分源码。EurekaServerInitializerConfiguration实现了ServletContextAware和SmartLifecycle两个接口,第一个接口使用来获取Spring上下文ServletContext的,具体的实现可以看一下这篇http://www.pinhuba.com/spring/101051.htm
第二个接口是用来在Spring加载和初始化所有bean后,接着执行一些任务或者启动需要的异步服务。我们通过源码的start()方法可以看到确实是启动了一个新的线程去调用EurekaServerBootstrap.contextInitialized方法启动初始化Eureka环境并启动Eureka。
整个流程下来是这个样子的(图片摘自):
流程图

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!