Spring Cloud微服务系列-Eureka Client源码解析(一)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/nihui123/article/details/102669342

导语
  Eureka Client 是为了简化开发人员的开发工作,将很多的Eureka Server交互的工作进行了封装,在使用的时候自动完成,在应用的不同阶段来完成不同的功能实现。下面就来了解一下关于Eureka Client所完成的功能。

应用启动阶段
  在应用启动阶段主要完成的工作有

  • 1、读取跟Server进行交互的配置信息,将这些信息封装成EurekaClientConfig
  • 2、读取吱声服务实例的配置信息,将其封装成EurekaInstanceConfig
  • 3、从Server中获取注册信息并将这些信息缓存到本地中
  • 4、服务注册
  • 5、初始化心跳、缓存刷新(拉取注册表信息更新本地缓存)、按照需求注册服务、进行定时任务。

应用执行阶段
  在应用的执行阶段,会完成如下的一些任务

  • 1、定时发送心跳信息到Server中,这样保证注册信息正确响应
  • 2、定时从Server中拉取注册信息、更新注册信息到本地缓存中
  • 3、监控应用自身的信息变化,如果发生变化,需要重新发起注册

应用销毁阶段
  在应用销毁阶段只完成一件事情

  • 1、从Server中注销自身的服务实例

Eureka Client源码分析

读取自动配置信息

  为了研究是如何运行的,可以在yml日志中做如下的配置。在使用IDEA启动的时候会在控制台打印出对应的DEBUG信息。

logging:
  level:
    org.springframework: debug

先来解决一个小问题

java.io.FileNotFoundException: class path resource [templates/] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/Users/nihui/Documents/Maven/env/java/apache-maven-3.3.9/repo/org/springframework/cloud/spring-cloud-netflix-eureka-server/2.0.0.RELEASE/spring-cloud-netflix-eureka-server-2.0.0.RELEASE.jar!/templates/
	at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:217) ~[spring-core-5.0.4.RELEASE.jar:5.0.4.RELEASE]
	at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:133) ~[spring-core-5.0.4.RELEASE.jar:5.0.4.RELEASE]
	at org.springframework.ui.freemarker.FreeMarkerConfigurationFactory.getTemplateLoaderForPath(FreeMarkerConfigurationFactory.java:346) [spring-context-support-5.0.4.RELEASE.jar:5.0.4.RELEASE]
	at org.springframework.ui.freemarker.FreeMarkerConfigurationFactory.createConfiguration(FreeMarkerConfigurationFactory.java:298) [spring-context-support-5.0.4.RELEASE.jar:5.0.4.RELEASE]
	at org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer.afterPropertiesSet(FreeMarkerConfigurer.java:120) [spring-webmvc-5.0.4.RELEASE.jar:5.0.4.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1769) [spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1706) [spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:583) [spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:502) [spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:312) [spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:310) [spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) [spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:760) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:868) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) ~[spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:388) ~[spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:327) ~[spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1246) ~[spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1234) ~[spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
	at com.springcloud.eureka.MainApplication.main(MainApplication.java:17) ~[classes/:na]

  在启动的时候居然报错了,怎么会报错呢,这问题是怎么来的呢?会发现在错误信息中有如下的一句代码
at org.springframework.ui.freemarker.FreeMarkerConfigurationFactory.getTemplateLoaderForPath(FreeMarkerConfigurationFactory.java:346) [spring-context-support-5.0.4.RELEASE.jar:5.0.4.RELEASE] 开始的时候想是不是在Resource路径下面没有对应的目录造成的,后来找到了如下的代码,在下面这个代码中,会看到当我们使用DEBUG模式运行的时候就会将异常信息打印出来。所以说这个出现在控制台是正常的。

	/**
	 * Determine a FreeMarker TemplateLoader for the given path.
	 * <p>Default implementation creates either a FileTemplateLoader or
	 * a SpringTemplateLoader.
	 * @param templateLoaderPath the path to load templates from
	 * @return an appropriate TemplateLoader
	 * @see freemarker.cache.FileTemplateLoader
	 * @see SpringTemplateLoader
	 */
	protected TemplateLoader getTemplateLoaderForPath(String templateLoaderPath) {
		if (isPreferFileSystemAccess()) {
			// Try to load via the file system, fall back to SpringTemplateLoader
			// (for hot detection of template changes, if possible).
			try {
				Resource path = getResourceLoader().getResource(templateLoaderPath);
				File file = path.getFile();  // will fail if not resolvable in the file system
				if (logger.isDebugEnabled()) {
					logger.debug(
							"Template loader path [" + path + "] resolved to file path [" + file.getAbsolutePath() + "]");
				}
				return new FileTemplateLoader(file);
			}
			catch (Exception ex) {
				if (logger.isDebugEnabled()) {
					logger.debug("Cannot resolve template loader path [" + templateLoaderPath +
							"] to [java.io.File]: using SpringTemplateLoader as fallback", ex);
				}
				return new SpringTemplateLoader(getResourceLoader(), templateLoaderPath);
			}
		}
		else {
			// Always load via SpringTemplateLoader (without hot detection of template changes).
			logger.debug("File system access not preferred: using SpringTemplateLoader");
			return new SpringTemplateLoader(getResourceLoader(), templateLoaderPath);
		}
	

  解决完小问题之后先来看看在SpringBoot启动的时候都往容器中自动注入了那些关于Eureka的东西,会看到在启动自动注入了一些类而其中比较重要的就是以下的几个

  • 1、EurekaClientAutoConfiguration : Eureka Client 自动配置类,主要是用来控制在SpringBoot中Eureka相关的Bean的配置和初始化
  • 2、RibbonEurekaAutoConfiguration: Ribbon负责负载均衡相关的配置
  • 3、EurekaDiscoveryClientConfiguration: 配置自动注册和应用健康检查器

  对于SpringBoot自动配置原理了解同学可以知道,在SpringBoot自动配置原理中,很多的自动配置类都是以XXXAutoConfigration来进行配置的,按照这个思路,可以在源码中搜索EurekeClientAutoConfigration。
在这里插入图片描述
  会发现在在这其中确实有一个叫做EurekaClientAutoConfiguration的自动配置类那么下面就来了解一下这个自动配置类。首先来分析一下在这个类开始的时候这些注解信息都是什么意思

@Configuration
@EnableConfigurationProperties
//表示在EurekaClientConfig存在的时候其作用
@ConditionalOnClass(EurekaClientConfig.class)
//表示在容器加载的时候通过Import的方式注入一些依赖
@Import(DiscoveryClientOptionalArgsConfiguration.class)
//注入Bean
@ConditionalOnBean(EurekaDiscoveryClientConfiguration.Marker.class)
//如果有eureka.client.enabled存在的时候
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
//自动配置之前
@AutoConfigureBefore({ NoopDiscoveryClientAutoConfiguration.class,
		CommonsClientAutoConfiguration.class, ServiceRegistryAutoConfiguration.class })
//自动配置之后
@AutoConfigureAfter(name = {"org.springframework.cloud.autoconfigure.RefreshAutoConfiguration",
		"org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration",
		"org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration"})
public class EurekaClientAutoConfiguration {

  从代码中可以知道,在自动化配置之前进行的操作是对NoopDiscoveryClientAutoConfiguration、CommonsClientAutoConfiguration、ServiceRegistryAutoConfiguration三个自动配置进行的自动配置操作。对于这些自动配置注入完成之后,进入到了EurekaClientAutoConfiguration 的自动配置。那么在EurekaClientAutoConfiguration的自动配置中都有那些内容呢?

  在以DEBUG模式下除了上面那个异常值得注意以外还有一个位置需要注意

 DEBUG 646 --- [           main] o.s.core.env.StandardEnvironment         : Initialized StandardEnvironment with PropertySources [MapPropertySource@791412502 {name='systemProperties', properties={java.runtime.name=Java(TM) SE Runtime Environment, spring.output.ansi.enabled=always, sun.boot.library.path=/Library/Java/JavaVirtualMachines/jdk1.8.0_74.jdk/Contents/Home/jre/lib, java.vm.version=25.74-b02, gopherProxySet=false, java.vm.vendor=Oracle Corporation, java.vendor.url=http://java.oracle.com/, java.rmi.server.randomIDs=true, path.separator=:, java.vm.name=Java HotSpot(TM) 64-Bit Server VM, file.encoding.pkg=sun.io, user.country=CN, sun.java.launcher=SUN_STANDARD, sun.os.patch.level=unknown, PID=646, java.vm.specification.name=Java Virtual Machine Specification, user.dir=/Users/nihui/Documents/IDEAProject/NewSpringCloud/eureka, java.runtime.version=1.8.0_74-b02, java.awt.graphicsenv=sun.awt.CGraphicsEnvironment, java.endorsed.dirs=/Library/Java/JavaVirtualMachines/jdk1.8.0_74.jdk/Contents/Home/jre/lib/endorsed, os.arch=x86_64, java.io.tmpdir=/var/folders/j5/2623h9kj7235x5190hb1zs2w0000gn/T/, line.separator=
, java.vm.specification.vendor=Oracle Corporation, os.name=Mac OS X, sun.jnu.encoding=UTF-8, spring.beaninfo.ignore=true, 

首先就是对于环境的配置

private ConfigurableEnvironment env;

public EurekaClientAutoConfiguration(ConfigurableEnvironment env) {
	this.env = env;
}

注入一个Bean,DiscoveryClient是SpringCloud中提供服务发现的顶级接口,在Eureka中有其实现类

@Bean
public DiscoveryClient discoveryClient(EurekaInstanceConfig config, EurekaClient client) {
	return new EurekaDiscoveryClient(config, client);
}
public interface DiscoveryClient {

	//获取实现类的描述
	String description();

	//通过服务的ID获取服务实例的信息
	List<ServiceInstance> getInstances(String serviceId);

	// 获取所有的服务实例ID列表
	List<String> getServices();

}

  上面方法中实际返回的是一个EurekaDiscoveryClient,也就是说在容器中实际存在的是一个EurekaDiscoveryClient的对象。那么EurekaDiscoveryClient到底如何?

public EurekaDiscoveryClient(EurekaInstanceConfig config, EurekaClient eurekaClient) {
	this.config = config;
	this.eurekaClient = eurekaClient;
}

实现的getInstances方法如下

@Override
public List<ServiceInstance> getInstances(String serviceId) {
	List<InstanceInfo> infos = this.eurekaClient.getInstancesByVipAddress(serviceId,false);
	List<ServiceInstance> instances = new ArrayList<>();
	for (InstanceInfo info : infos) {
		instances.add(new EurekaServiceInstance(info));
	}
	return instances;
}

上面提到了一个EurekaClient类在这个类在自动配置的时候就已经注入到容器中了。@ImplementedBy注解在之前提到过是Google提供的实现动态绑定的注解。而它所实现的DiscoveryClient是一个实现类。com.netflix.discovery.DiscoveryClient
org.springframework.cloud.client.discovery.DiscoveryClient

@ImplementedBy(DiscoveryClient.class)
public interface EurekaClient extends LookupService {

在SpringCloud中通过组合方式调用了Eureka中的服务发现方法。

服务发现客户端

  在上面会看到在Spring Cloud中提供了一个DiscoveryClient,在Eureka中提供了一个DiscoveryClient,那么这两个到底是什么关系呢?首先我们知道在SpringCloud中的DiscoveryClient是一个接口,在Eureka中的是一个接口实现类,上面说了在应用启动的时候Eureka自动配置中注入了一个DiscoveryClient,它的功能是服务的发现。而在Eureka Client中真正起作用的是DiscoveryClient这实现类。

1、DiscoveryClient是干什么的?

  DiscoveryClient是Eureka Client 的核心类,包括了与Eureka Server交互的关键逻辑主要功能如下

  • 1、注册服务实例到Eureka Server中
  • 2、发送心跳检测更新Server的租约
  • 3、服务下线功能
  • 4、查询在Eureka Server中注册的服务实例列表
    2、DiscoveryClient的类图结构
    在这里插入图片描述

  从类图结构来看,其实最终实现的都是LookupService接口,而对于一个接口来说就是定义一些实现的规则。那么下面就来看看LookupService接口需要哪些实现规则。

public interface LookupService<T> {
	//根据服务实例注册的appName来获取封装有相同appName的服务实例信息容器
    Application getApplication(String appName);
	//返回当前注册表中所有的服务实例信息
    Applications getApplications();
	//根据服务实例的ID获取服务实例信息
    List<InstanceInfo> getInstancesById(String id);
	//获取下一个服务
    InstanceInfo getNextServerFromEureka(String virtualHostname, boolean secure);
}

  Application是持有服务实例的信息,也可以理解为同一个服务集群信息,这些实例都挂载在同一个服务名appName下。InstanceInfo表示一个服务实例信息。当然在一个应用服务集群中会有很多的InstanceInfo实例,所以在操作的时候Application对于InstanceInfo是具有原子性的,也就是Application中的操作对于所有的InstanceInfo都是同步操作。

  之前提到了EurekaClient继承了LookupService接口并且有如下的操作

public interface EurekaClient extends LookupService {

    // ========================
    // getters for InstanceInfo
    // ========================

    /**
     * @param region the region that the Applications reside in
     * @return an {@link com.netflix.discovery.shared.Applications} for the matching region. a Null value
     *         is treated as the local region.
     */
    public Applications getApplicationsForARegion(@Nullable String region);

    /**
     * Get all applications registered with a specific eureka service.
     *
     * @param serviceUrl The string representation of the service url.
     * @return The registry information containing all applications.
     */
    public Applications getApplications(String serviceUrl);

    /**
     * Gets the list of instances matching the given VIP Address.
     *
     * @param vipAddress The VIP address to match the instances for.
     * @param secure true if it is a secure vip address, false otherwise
     * @return - The list of {@link InstanceInfo} objects matching the criteria
     */
    public List<InstanceInfo> getInstancesByVipAddress(String vipAddress, boolean secure);

    /**
     * Gets the list of instances matching the given VIP Address in the passed region.
     *
     * @param vipAddress The VIP address to match the instances for.
     * @param secure true if it is a secure vip address, false otherwise
     * @param region region from which the instances are to be fetched. If <code>null</code> then local region is
     *               assumed.
     *
     * @return - The list of {@link InstanceInfo} objects matching the criteria, empty list if not instances found.
     */
    public List<InstanceInfo> getInstancesByVipAddress(String vipAddress, boolean secure, @Nullable String region);

    /**
     * Gets the list of instances matching the given VIP Address and the given
     * application name if both of them are not null. If one of them is null,
     * then that criterion is completely ignored for matching instances.
     *
     * @param vipAddress The VIP address to match the instances for.
     * @param appName The applicationName to match the instances for.
     * @param secure true if it is a secure vip address, false otherwise.
     * @return - The list of {@link InstanceInfo} objects matching the criteria.
     */
    public List<InstanceInfo> getInstancesByVipAddressAndAppName(String vipAddress, String appName, boolean secure);

    // ==========================
    // getters for local metadata
    // ==========================

    /**
     * @return in String form all regions (local + remote) that can be accessed by this client
     */
    public Set<String> getAllKnownRegions();

    /**
     * @return the current self instance status as seen on the Eureka server.
     */
    public InstanceInfo.InstanceStatus getInstanceRemoteStatus();

    /**
     * @deprecated see {@link com.netflix.discovery.endpoint.EndpointUtils} for replacement
     *
     * Get the list of all eureka service urls for the eureka client to talk to.
     *
     * @param zone the zone in which the client resides
     * @return The list of all eureka service urls for the eureka client to talk to.
     */
    @Deprecated
    public List<String> getDiscoveryServiceUrls(String zone);

    /**
     * @deprecated see {@link com.netflix.discovery.endpoint.EndpointUtils} for replacement
     *
     * Get the list of all eureka service urls from properties file for the eureka client to talk to.
     *
     * @param instanceZone The zone in which the client resides
     * @param preferSameZone true if we have to prefer the same zone as the client, false otherwise
     * @return The list of all eureka service urls for the eureka client to talk to
     */
    @Deprecated
    public List<String> getServiceUrlsFromConfig(String instanceZone, boolean preferSameZone);

    /**
     * @deprecated see {@link com.netflix.discovery.endpoint.EndpointUtils} for replacement
     *
     * Get the list of all eureka service urls from DNS for the eureka client to
     * talk to. The client picks up the service url from its zone and then fails over to
     * other zones randomly. If there are multiple servers in the same zone, the client once
     * again picks one randomly. This way the traffic will be distributed in the case of failures.
     *
     * @param instanceZone The zone in which the client resides.
     * @param preferSameZone true if we have to prefer the same zone as the client, false otherwise.
     * @return The list of all eureka service urls for the eureka client to talk to.
     */
    @Deprecated
    public List<String> getServiceUrlsFromDNS(String instanceZone, boolean preferSameZone);

    // ===========================
    // healthcheck related methods
    // ===========================

    /**
     * @deprecated Use {@link #registerHealthCheck(com.netflix.appinfo.HealthCheckHandler)} instead.
     *
     * Register {@link HealthCheckCallback} with the eureka client.
     *
     * Once registered, the eureka client will invoke the
     * {@link HealthCheckCallback} in intervals specified by
     * {@link EurekaClientConfig#getInstanceInfoReplicationIntervalSeconds()}.
     *
     * @param callback app specific healthcheck.
     */
    @Deprecated
    public void registerHealthCheckCallback(HealthCheckCallback callback);

    /**
     * Register {@link HealthCheckHandler} with the eureka client.
     *
     * Once registered, the eureka client will first make an onDemand update of the
     * registering instanceInfo by calling the newly registered healthcheck handler,
     * and subsequently invoke the {@link HealthCheckHandler} in intervals specified
     * by {@link EurekaClientConfig#getInstanceInfoReplicationIntervalSeconds()}.
     *
     * @param healthCheckHandler app specific healthcheck handler.
     */
    public void registerHealthCheck(HealthCheckHandler healthCheckHandler);

    /**
     * Register {@link EurekaEventListener} with the eureka client.
     *
     * Once registered, the eureka client will invoke {@link EurekaEventListener#onEvent} 
     * whenever there is a change in eureka client's internal state.  Use this instead of 
     * polling the client for changes.  
     * 
     * {@link EurekaEventListener#onEvent} is called from the context of an internal thread 
     * and must therefore return as quickly as possible without blocking.
     * 
     * @param eventListener
     */
    public void registerEventListener(EurekaEventListener eventListener);
    
    /**
     * Unregister a {@link EurekaEventListener} previous registered with {@link EurekaClient#registerEventListener}
     * or injected into the constructor of {@link DiscoveryClient}
     * 
     * @param eventListener
     * @return True if removed otherwise false if the listener was never registered.
     */
    public boolean unregisterEventListener(EurekaEventListener eventListener);
    
    /**
     * @return the current registered healthcheck handler
     */
    public HealthCheckHandler getHealthCheckHandler();

    // =============
    // other methods
    // =============

    /**
     * Shuts down Eureka Client. Also sends a deregistration request to the eureka server.
     */
    public void shutdown();
    
    /**
     * @return the configuration of this eureka client
     */
    public EurekaClientConfig getEurekaClientConfig();
    
    /**
     * @return the application info manager of this eureka client
     */
    public ApplicationInfoManager getApplicationInfoManager();
}

&esmp; 会看到,EurekaClient在原有的LookupService基础上扩展了很多的方法,提供了很多的获取实例的方式,主要的扩展有如下几个方面

  • 1、提供多种方式获取InstanceInfo
  • 2、提供本地客户端数据
  • 3、提供为客户端注册和获取健康检查处理器的能力
    /**
     * Register {@link HealthCheckHandler} with the eureka client.
     *
     * Once registered, the eureka client will first make an onDemand update of the
     * registering instanceInfo by calling the newly registered healthcheck handler,
     * and subsequently invoke the {@link HealthCheckHandler} in intervals specified
     * by {@link EurekaClientConfig#getInstanceInfoReplicationIntervalSeconds()}.
     *
     * @param healthCheckHandler app specific healthcheck handler.
     */
    public void registerHealthCheck(HealthCheckHandler healthCheckHandler);

    /**
     * Register {@link EurekaEventListener} with the eureka client.
     *
     * Once registered, the eureka client will invoke {@link EurekaEventListener#onEvent} 
     * whenever there is a change in eureka client's internal state.  Use this instead of 
     * polling the client for changes.  
     * 
     * {@link EurekaEventListener#onEvent} is called from the context of an internal thread 
     * and must therefore return as quickly as possible without blocking.
     * 
     * @param eventListener
     */
    public void registerEventListener(EurekaEventListener eventListener);

  Eureka Server 通过心跳机制来识别一个实例的状态,Eureka Clinet 中 在一个定时任务定时通过HealthCheckHandler检查当前Client的状态,如果Client的状态发生了变化之后就会触发新的注册事件。从而更新Eureka Server的注册表中该服务实例的相关信息

public interface HealthCheckHandler {
    InstanceInfo.InstanceStatus getStatus(InstanceInfo.InstanceStatus currentStatus);
}

 HealthCheckHandler代码如上所指,其实现类org.springframework.cloud.netflix.eureka.EurekaHealthCheckHandler,主要是通过org.springframework.boot.actuate.health.HealthIndicator和org.springframework.boot.actuate.health.HealthAggregator来实现对于SpringBoot应用状态的监控。
  在Eureka中的事件模式属于观察者模式,事件监听器将监听Client的服务实例信息变化,从而触发对应的处理事件。
在这里插入图片描述

总结

  上面的内容从Eureka自动配置入手,简单的分析了Eureka的与SpringCloud 的服务注册发现机制,解决了在使用DEBUG的方式进行自动配置操作中出现的问题。从上面了解到Spring Cloud 与Spring Cloud Eureka并不是同一个东西,Spring Cloud Eureka 与Eureka Client也不是同一个东西,可以说通过源码的分析收获很大,了解的观察者模式,为后期Spring与设计模式系列打下基础。

猜你喜欢

转载自blog.csdn.net/nihui123/article/details/102669342