二.SpringCloud源码剖析-Eureka Client 初始化过程

系列文章目录

一.SpringCloud源码剖析-Eureka核心API

二.SpringCloud源码剖析-Eureka Client 初始化过程

三.SpringCloud源码剖析-Eureka服务注册

四.SpringCloud源码剖析-Eureka服务发现

五.SpringCloud源码剖析-Eureka Client服务续约

六.SpringCloud源码剖析-Eureka Client取消注册

七.SpringCloud源码剖析-Eureka Server的自动配置

八.SpringCloud源码剖析-Eureka Server初始化流程

九.SpringCloud源码剖析-Eureka Server服务注册流程

十.SpringCloud源码剖析-Eureka Server服务续约

十一.SpringCloud源码剖析-Eureka Server服务注册表拉取

十二.SpringCloud源码剖析-Eureka Server服务剔除

十三.SpringCloud源码剖析-Eureka Server服务下线

前言

前面我们简单了解了一下SpringCloud Eureka的核心API,这一章我们跟踪一下Eureka的启动过程

1.EurekaClientAutoConfiguration:Eureka自动配置

有了解过SpringBoot自动配置的同学应该知道,在主程序启动类上我们会贴一个 @SpringBootApplication 注解,该注解里面包含了一个 @EnableAutoConfiguration 注解,该注解的作用是开启SpringBoot的自动配置,即:在 @EnableAutoConfiguration 标签中使用了一个 AutoConfigurationImportSelector 选择器,该选择器会去扫描当前classpath环境中的 META-INF/spring.factories 文件中的自动配置类,然后完成相关的自动配置。如下:

  • @SpringBootApplication标签源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
  • @EnableAutoConfiguration 标签源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {...}
  • AutoConfigurationImportSelector选择器源码
public class AutoConfigurationImportSelector
		implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
		BeanFactoryAware, EnvironmentAware, Ordered {

	//省略部分代码......
	//扫描classpath下的spring.factories自动配置
	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
				.loadMetadata(this.beanClassLoader);
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		List<String> configurations = getCandidateConfigurations(annotationMetadata,
				attributes);
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = filter(configurations, autoConfigurationMetadata);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return StringUtils.toStringArray(configurations);
	}

selectImports 方法中会将扫描到的 META-INF/spring.factories 文件中的自动配置的一些类加载进来,然后注册到Spring容器中

其中在 spring-cloud-netflix-eureka-client-2.0.1.RELEASE.jar 这个jar包里面就有一个 META-INF/spring.factories文件,内容如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaClientConfigServerAutoConfiguration,\
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceAutoConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,\
org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration

我们这里需要重点关注是 EurekaClientAutoConfiguration 这个类,从名字就能看出它是对EureakClient的自动配置,来详细看一下它的源码

//EurekaClient自动配置
@Configuration
@EnableConfigurationProperties
@ConditionalOnClass(EurekaClientConfig.class)
@Import(DiscoveryClientOptionalArgsConfiguration.class)
@ConditionalOnBean(EurekaDiscoveryClientConfiguration.Marker.class)
@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 {
...省略...
  //注册EurekaClientConfigBean,该类实现了EurekaClientConfig客户端配置接口,EurekaClientConfigBean封装了客户端实例Eureaka Client注册到Eureak Server 服务端所需要的注册信息,比如:服务注册地址,拉取服务注册表的时间间隔, 注册信息复制到EurekaServer的时间等等
    @Bean
	@ConditionalOnMissingBean(value = EurekaClientConfig.class, search = SearchStrategy.CURRENT)
	public EurekaClientConfigBean eurekaClientConfigBean(ConfigurableEnvironment env) {
		EurekaClientConfigBean client = new EurekaClientConfigBean();
		if ("bootstrap".equals(this.env.getProperty("spring.config.name"))) {
			// We don't register during bootstrap by default, but there will be another
			// chance later.
			client.setRegisterWithEureka(false);
		}
		return client;
	}
	//注册EurekaInstanceConfigBean , eureka实例配置,实现了EurekaInstanceConfig配置接口,其中包括了:获取实例ID,
    //获取https协议端口,获取应用名,获取应用组名,获取租约心跳间隔时间,租约到期时间,获取ip,获取主机名等等方法。
    @Bean
	@ConditionalOnMissingBean(value = EurekaInstanceConfig.class, search = SearchStrategy.CURRENT)
	public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils,
															 ManagementMetadataProvider managementMetadataProvider) {
		String hostname = getProperty("eureka.instance.hostname");
		boolean preferIpAddress = Boolean.parseBoolean(getProperty("eureka.instance.prefer-ip-address"));
		String ipAddress = getProperty("eureka.instance.ip-address");
		boolean isSecurePortEnabled = Boolean.parseBoolean(getProperty("eureka.instance.secure-port-enabled"));

		String serverContextPath = env.getProperty("server.context-path", "/");
		int serverPort = Integer.valueOf(env.getProperty("server.port", env.getProperty("port", "8080")));

		Integer managementPort = env.getProperty("management.server.port", Integer.class);// nullable. should be wrapped into optional
		String managementContextPath = env.getProperty("management.server.servlet.context-path");// nullable. should be wrapped into optional
		Integer jmxPort = env.getProperty("com.sun.management.jmxremote.port", Integer.class);//nullable
		EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils);

		instance.setNonSecurePort(serverPort);
		instance.setInstanceId(getDefaultInstanceId(env));
		instance.setPreferIpAddress(preferIpAddress);
		instance.setSecurePortEnabled(isSecurePortEnabled);
		if (StringUtils.hasText(ipAddress)) {
			instance.setIpAddress(ipAddress);
		}

		if(isSecurePortEnabled) {
			instance.setSecurePort(serverPort);
		}

		if (StringUtils.hasText(hostname)) {
			instance.setHostname(hostname);
		}
		String statusPageUrlPath = getProperty("eureka.instance.status-page-url-path");
		String healthCheckUrlPath = getProperty("eureka.instance.health-check-url-path");

		if (StringUtils.hasText(statusPageUrlPath)) {
			instance.setStatusPageUrlPath(statusPageUrlPath);
		}
		if (StringUtils.hasText(healthCheckUrlPath)) {
			instance.setHealthCheckUrlPath(healthCheckUrlPath);
		}

		ManagementMetadata metadata = managementMetadataProvider.get(instance, serverPort,
				serverContextPath, managementContextPath, managementPort);

		if(metadata != null) {
			instance.setStatusPageUrl(metadata.getStatusPageUrl());
			instance.setHealthCheckUrl(metadata.getHealthCheckUrl());
			if(instance.isSecurePortEnabled()) {
				instance.setSecureHealthCheckUrl(metadata.getSecureHealthCheckUrl());
			}
			Map<String, String> metadataMap = instance.getMetadataMap();
			if (metadataMap.get("management.port") == null) {
				metadataMap.put("management.port", String.valueOf(metadata.getManagementPort()));
			}
		} else {
			//without the metadata the status and health check URLs will not be set
			//and the status page and health check url paths will not include the
			//context path so set them here
			if(StringUtils.hasText(managementContextPath)) {
				instance.setHealthCheckUrlPath(managementContextPath + instance.getHealthCheckUrlPath());
				instance.setStatusPageUrlPath(managementContextPath + instance.getStatusPageUrlPath());
			}
		}

		setupJmxPort(instance, jmxPort);
		return instance;
	}
	//注册DiscoveryClient服务发现客户端,它是spring-cloud-commons:2.0.1.RELEASE SpringCloud公共抽象包中的(org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient),
	//是Spring Cloudd的服务发现抽象接口 EurekaDiscoveryClient是它的实现
	@Bean
	public DiscoveryClient discoveryClient(EurekaInstanceConfig config, EurekaClient client) {
		return new EurekaDiscoveryClient(config, client);
	}

     //Eureak服务注册器,他是SpringCloud 在Netflix标准上拓展出来的,提供了服务注册,取消注册,设置服务状态,获取服务状态方法,ServiceRegistry负责服务注册,DiscoveryClient负责服务发现
	@Bean
	public EurekaServiceRegistry eurekaServiceRegistry() {
		return new EurekaServiceRegistry();
	}
	//EurekaAutoServiceRegistration :eureka服务自动注册器
    @Bean
	@ConditionalOnBean(AutoServiceRegistrationProperties.class)
	@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
	public EurekaAutoServiceRegistration eurekaAutoServiceRegistration(ApplicationContext context, EurekaServiceRegistry registry,
																	   EurekaRegistration registration) {
		return new EurekaAutoServiceRegistration(context, registry, registration);
	}
	//取消注册
	@Override
	public void stop() {
		this.serviceRegistry.deregister(this.registration);
		this.running.set(false);
	}
	//EureakClient配置,该配置没有刷新功能
    @Configuration
	@ConditionalOnMissingRefreshScope  //不可刷新
	protected static class EurekaClientConfiguration {

		@Autowired
		private ApplicationContext context;

		@Autowired
		private AbstractDiscoveryClientOptionalArgs<?> optionalArgs;
		//注册EurekaClient  客户端对象 , 它有一个实现 DiscoveryClient ,
		//这个实现 DiscoveryClient  是eureka-client:1.9.3包里面的,是Euraek的服务发现的核心实现
		@Bean(destroyMethod = "shutdown")
		@ConditionalOnMissingBean(value = EurekaClient.class, search = SearchStrategy.CURRENT)
		public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config) {
			return new CloudEurekaClient(manager, config, this.optionalArgs,
					this.context);
		}
		//注册ApplicationInfoManager  ,该对象用来管理 InstanceInfo
		@Bean
		@ConditionalOnMissingBean(value = ApplicationInfoManager.class, search = SearchStrategy.CURRENT)
		public ApplicationInfoManager eurekaApplicationInfoManager(
				EurekaInstanceConfig config) {
			InstanceInfo instanceInfo = new InstanceInfoFactory().create(config);
			return new ApplicationInfoManager(config, instanceInfo);
		}
		//注册EurekaRegistration,它是Eureka实例的服务注册信息,开启自动注册时,该对象才会被注册
		@Bean
		@ConditionalOnBean(AutoServiceRegistrationProperties.class)
		@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
		public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient,
													 CloudEurekaInstanceConfig instanceConfig,
													 ApplicationInfoManager applicationInfoManager,
													 @Autowired(required = false) ObjectProvider<HealthCheckHandler> healthCheckHandler) {
			return EurekaRegistration.builder(instanceConfig)
					.with(applicationInfoManager)
					.with(eurekaClient)
					.with(healthCheckHandler)
					.build();
		}
	}
	//这里也是EurekaClient的配置,只是可刷新的
    @Configuration
	@ConditionalOnRefreshScope
	protected static class RefreshableEurekaClientConfiguration {

		@Autowired
		private ApplicationContext context;

		@Autowired
		private AbstractDiscoveryClientOptionalArgs<?> optionalArgs;
		//注册Eureak客户端EurekaClient, @Lazy 懒初始化,该bean被用到的时候会被创建
		//EurekaClient有一个实现 DiscoveryClient这个实现 是eureka-client:1.9.3包里面的,是Euraek的服务发现的核心实现
		@Bean(destroyMethod = "shutdown")
		@ConditionalOnMissingBean(value = EurekaClient.class, search = SearchStrategy.CURRENT)
		@org.springframework.cloud.context.config.annotation.RefreshScope
		@Lazy
		public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config, EurekaInstanceConfig instance) {
			manager.getInfo(); // force initialization
			return new CloudEurekaClient(manager, config, this.optionalArgs,
					this.context);
		}
		//注册ApplicationInfoManager,它是InstanceInfo的管理器
		@Bean
		@ConditionalOnMissingBean(value = ApplicationInfoManager.class, search = SearchStrategy.CURRENT)
		@org.springframework.cloud.context.config.annotation.RefreshScope
		@Lazy
		public ApplicationInfoManager eurekaApplicationInfoManager(EurekaInstanceConfig config) {
		//注意:这里的InstanceInfo被创建的状态是InstanceStatus.STARTING;后面在初始化的过程中会修改为 InstanceStatus.UP;
			InstanceInfo instanceInfo = new InstanceInfoFactory().create(config);
			return new ApplicationInfoManager(config, instanceInfo);
		}

		@Bean
		@org.springframework.cloud.context.config.annotation.RefreshScope
		@ConditionalOnBean(AutoServiceRegistrationProperties.class)
		@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
		public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient,
													 CloudEurekaInstanceConfig instanceConfig,
													 ApplicationInfoManager applicationInfoManager,
													 @Autowired(required = false) ObjectProvider<HealthCheckHandler> healthCheckHandler) {
			return EurekaRegistration.builder(instanceConfig)
					.with(applicationInfoManager)
					.with(eurekaClient)
					.with(healthCheckHandler)
					.build();
		}

	}
	...省略...
	//健康指示器,用来管理服务的健康状况
    @Configuration
	@ConditionalOnClass(Health.class)
	protected static class EurekaHealthIndicatorConfiguration {
		@Bean
		@ConditionalOnMissingBean
		@ConditionalOnEnabledHealthIndicator("eureka")
		public EurekaHealthIndicator eurekaHealthIndicator(EurekaClient eurekaClient,
														   EurekaInstanceConfig instanceConfig, EurekaClientConfig clientConfig) {
			return new EurekaHealthIndicator(eurekaClient, instanceConfig, clientConfig);
		}
	}

总结一下:这里注册了很多对象比较重要的有:
1.EurekaClientConfigBean :这个类实现了netflix 的 EurekaClientConfig客户端配置接口,是对Eureka客户端的配置对象,即我们在配置文件中配置的 eureka.client 节点下的配置都会被封装到该对象中。

2.EurekaInstanceConfigBean: 该类实现了netflix的EurekaInstanceConfig接口,是的服务实例信息配置,ApplicationManager通过该接口用来构建InstanceConfig,比如我们在配置文件中配置的eureka.instance 开头的配置就会配置到该对象中。

3.DiscoveryClient:注册了DiscoveryClient服务发现客户端接口,默认实现是EurekaDiscoveryClient。这个类来源于spring-cloud-common.2.0.1.jar 这个包,这个包是springcloud的抽象包的公共包里面制定了一系列公共的API,而DiscoveryClient中包含了服务发现的基本公共方法

4.配置了一些客户端自动注册组件

  • EurekaServiceRegistry: Eureak服务注册器,他是SpringCloud 在Netflix标准上拓展出来的,提供了服务注册,取消注册, 关闭服务,设置服务状态,获取服务状态方法
  • EurekaRegistration: 它是Eureka实例的服务注册信息对象,开启自动注册时,该对象才会被注册,EurekaServiceRegistry负责服务注册,EurekaRegistration存放服务注册信息
  • EurekaAutoServiceRegistration: Eureka服务自动注册器,用来注册EurekaRegistration信息

5.EurekaClient:这里通过CloudEurekaClient来实例化,他是用来和EureakServer进行交互,是netflix提供的接口类,它还有个比较重要的实现 DiscoveryClient 主要负责服务发现,这个是与注册中心EureakServer交互的最核心的实现,包括服务注册,注册表拉取,服务续约等等功能都在里面提现。需要注意的是该Bean在注册的时候使用了@Lazy进行延迟创建

6.ApplicationInfoManager:这个类是用来管理实例注册信息InstanceInfo的,其中还包括了对实例状的态监听机制

7.EurekaHealthIndicator:这个是用作服务的健康检查的,以及提供了获取服务状态,以及获取Applications服务注册表等方法

2.EurekaAutoServiceRegistration:Eureaka自动注册

spring-cloud-commons-2.0.1.RELEASE.jar SpringCloud公共包中/META-INF/spring.factories配置文件中有AutoServiceRegistrationAutoConfiguration自动配置类,当应用启动SpringBoot会扫描到该自动配置类,然后注册到Spring容器

# AutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.client.serviceregistry.ServiceRegistryAutoConfiguration,\
org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration

ServiceRegistryAutoConfiguration是配置注册的服务的端点信息,可通过端点 “/service-registry”查看到服务注册情况

@Configuration
public class ServiceRegistryAutoConfiguration {

	@ConditionalOnBean(ServiceRegistry.class)
	@ConditionalOnClass(Endpoint.class)
	protected class ServiceRegistryEndpointConfiguration {
		@Autowired(required = false)
		private Registration registration;

		@Bean
		@ConditionalOnEnabledEndpoint
		public ServiceRegistryEndpoint serviceRegistryEndpoint(ServiceRegistry serviceRegistry) {
			ServiceRegistryEndpoint endpoint = new ServiceRegistryEndpoint(serviceRegistry);
			endpoint.setRegistration(registration);
			return endpoint;
		}
	}
}

------------------------------------------------------------------------

//查看注册服务端点
@Endpoint(id = "service-registry")
public class ServiceRegistryEndpoint {

	private final ServiceRegistry serviceRegistry;

	private Registration registration;

	public ServiceRegistryEndpoint(ServiceRegistry<?> serviceRegistry) {
		this.serviceRegistry = serviceRegistry;
	}

	public void setRegistration(Registration registration) {
		this.registration = registration;
	}
	
	@WriteOperation
	public ResponseEntity<?> setStatus(String status) {
		Assert.notNull(status, "status may not by null");

		if (this.registration == null) {
			return ResponseEntity.status(HttpStatus.NOT_FOUND).body("no registration found");
		}

		this.serviceRegistry.setStatus(this.registration, status);
		return ResponseEntity.ok().build();
	}
	//获取服务状态
	@ReadOperation
	public ResponseEntity getStatus() {
		if (this.registration == null) {
			return ResponseEntity.status(HttpStatus.NOT_FOUND).body("no registration found");
		}

		return ResponseEntity.ok().body(this.serviceRegistry.getStatus(this.registration));
	}

}

AutoServiceRegistrationAutoConfiguration是开启服务自动注册其中注入了AutoServiceRegistration确保该类会被注册,源码如下

@Configuration
@Import(AutoServiceRegistrationConfiguration.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public class AutoServiceRegistrationAutoConfiguration {

	@Autowired(required = false)
	private AutoServiceRegistration autoServiceRegistration;

	@Autowired
	private AutoServiceRegistrationProperties properties;

	@PostConstruct
	protected void init() {
		if (autoServiceRegistration == null && this.properties.isFailFast()) {
			throw new IllegalStateException("Auto Service Registration has been requested, but there is no AutoServiceRegistration bean");
		}
	}
}

EurekaAutoServiceRegistration是Eureka的自动注册器,在EurekaClientAutoConfiguration中对EurekaAutoServiceRegistration做了Bean的定义,当开启spring.cloud.service-registry.auto-registration.enabled=true(默认)该Bean注册起效 , 它是 AutoServiceRegistration的实现
在这里插入图片描述

EurekaAutoServiceRegistration 源码如下:

//自动注册器
public class EurekaAutoServiceRegistration implements AutoServiceRegistration, SmartLifecycle, Ordered {

	private static final Log log = LogFactory.getLog(EurekaAutoServiceRegistration.class);

	private AtomicBoolean running = new AtomicBoolean(false);

	private int order = 0;

	private AtomicInteger port = new AtomicInteger(0);

	private ApplicationContext context;
	//服务注册器
	private EurekaServiceRegistry serviceRegistry;
	//服务注册信息登记
	private EurekaRegistration registration;

	public EurekaAutoServiceRegistration(ApplicationContext context, EurekaServiceRegistry serviceRegistry, EurekaRegistration registration) {
		this.context = context;
		this.serviceRegistry = serviceRegistry;
		this.registration = registration;
	}
	//开启服务注册
	@Override
	public void start() {
		// only set the port if the nonSecurePort or securePort is 0 and this.port != 0
		if (this.port.get() != 0) {
			if (this.registration.getNonSecurePort() == 0) {
				this.registration.setNonSecurePort(this.port.get());
			}

			if (this.registration.getSecurePort() == 0 && this.registration.isSecure()) {
				this.registration.setSecurePort(this.port.get());
			}
		}

		// only initialize if nonSecurePort is greater than 0 and it isn't already running
		// because of containerPortInitializer below
		if (!this.running.get() && this.registration.getNonSecurePort() > 0) {
			//调用服务注册器进行服务注册
			this.serviceRegistry.register(this.registration);
			//发布一个服务注册事件
			this.context.publishEvent(
					new InstanceRegisteredEvent<>(this, this.registration.getInstanceConfig()));
			this.running.set(true);
		}
	}
	@Override
	public void stop() {
		//服务停止,取消服务注册
		this.serviceRegistry.deregister(this.registration);
		this.running.set(false);
	}

	@Override
	public boolean isRunning() {
		//获取服务状态是否运行
		return this.running.get();
	}

	@Override
	public int getPhase() {
		return 0;
	}

	@Override
	public boolean isAutoStartup() {
		return true;
	}

    //停止服务
	@Override
	public void stop(Runnable callback) {
		stop();
		callback.run();
	}

	@Override
	public int getOrder() {
		return this.order;
	}


    //监听web启动完成事件,执行start()方法开启服务注册
	@EventListener(WebServerInitializedEvent.class)
	public void onApplicationEvent(WebServerInitializedEvent event) {
		// TODO: take SSL into account
		int localPort = event.getWebServer().getPort();
		if (this.port.get() == 0) {
			log.info("Updating port to " + localPort);
			this.port.compareAndSet(0, localPort);
			start();
		}
	}
	
	//监听应用关闭事件,执行stop()方法
	@EventListener(ContextClosedEvent.class)
	public void onApplicationEvent(ContextClosedEvent event) {
		if( event.getApplicationContext() == context ) {
			stop();
		}
	}

}

EurekaAutoServiceRegistration监听了应用启动事件,调用EurekaServiceRegistry.register进行服务注册,同时监听应用关闭事件,调用EurekaServiceRegistry.deregister取消服务注册

3.EurekaServiceRegistry:服务注册器

EurekaServiceRegistry是Eureak服务注册器,他是SpringCloud 在Netflix标准ServiceRegistry上拓展出来的,提供了服务注册,取消注册, 关闭服务,设置服务状态,获取服务状态方法
在这里插入图片描述
ServiceRegistryEureakaServiceRegistry的接口,他是Netflix的服务发现抽象,ServiceRegistry需要依赖EurekaRegistration,EurekaRegistration是ServiceInstance的实现它约定了服务发现的实例应用的通用的信息
在这里插入图片描述

在应用启动时,EurekaAutoServiceRegistration会监听应用启动完成事件,在start()方法中调用,EureakaServiceRegistry.register方法开始服务注册,源码如下

//服务注册
public class EurekaServiceRegistry implements ServiceRegistry<EurekaRegistration> {

	private static final Log log = LogFactory.getLog(EurekaServiceRegistry.class);

	//注册方法,注册EurekaRegistration
	@Override
	public void register(EurekaRegistration reg) {
		//初始化客户端,该方法会触发 EurekaClient 的创建
		maybeInitializeClient(reg);

		if (log.isInfoEnabled()) {
			log.info("Registering application " + reg.getInstanceConfig().getAppname()
					+ " with eureka with status "
					+ reg.getInstanceConfig().getInitialStatus());
		}
		//初始化客户端状态,把InstanceStatus设置为 InstanceStatus.UP;
		reg.getApplicationInfoManager()
				.setInstanceStatus(reg.getInstanceConfig().getInitialStatus());
		//注册健康检查处理器
		reg.getHealthCheckHandler().ifAvailable(healthCheckHandler ->
				reg.getEurekaClient().registerHealthCheck(healthCheckHandler));
	}
	//初始化客户端,reg.getEurekaClient()会触发EureakClient(DiscoveryClient)的初始化
	private void maybeInitializeClient(EurekaRegistration reg) {
		// force initialization of possibly scoped proxies
		reg.getApplicationInfoManager().getInfo();
		//初始化Eurak客户端
		reg.getEurekaClient().getApplications();
	}
	//取消注册,设置服务状态为down
	@Override
	public void deregister(EurekaRegistration reg) {
		if (reg.getApplicationInfoManager().getInfo() != null) {

			if (log.isInfoEnabled()) {
				log.info("Unregistering application " + reg.getInstanceConfig().getAppname()
						+ " with eureka with status DOWN");
			}

			reg.getApplicationInfoManager().setInstanceStatus(InstanceInfo.InstanceStatus.DOWN);

			//shutdown of eureka client should happen with EurekaRegistration.close()
			//auto registration will create a bean which will be properly disposed
			//manual registrations will need to call close()
		}
	}
	//设置服务注册状态
	@Override
	public void setStatus(EurekaRegistration registration, String status) {
		InstanceInfo info = registration.getApplicationInfoManager().getInfo();

		//TODO: howto deal with delete properly?
		if ("CANCEL_OVERRIDE".equalsIgnoreCase(status)) {
			registration.getEurekaClient().cancelOverrideStatus(info);
			return;
		}

		//TODO: howto deal with status types across discovery systems?
		InstanceInfo.InstanceStatus newStatus = InstanceInfo.InstanceStatus.toEnum(status);
		registration.getEurekaClient().setStatus(newStatus, info);
	}
	//获取服务注册状态
	@Override
	public Object getStatus(EurekaRegistration registration) {
		String appname = registration.getInstanceConfig().getAppname();
		String instanceId = registration.getInstanceConfig().getInstanceId();
		InstanceInfo info = registration.getEurekaClient().getInstanceInfo(appname, instanceId);

		HashMap<String, Object> status = new HashMap<>();
		if (info != null) {
			status.put("status", info.getStatus().toString());
			status.put("overriddenStatus", info.getOverriddenStatus().toString());
		} else {
			status.put("status", UNKNOWN.toString());
		}

		return status;
	}

	public void close() {
	}

}

EurekaServiceRegistry中register方法初始化了Eureka客户端,以及注册了健康检查处理器,在private void maybeInitializeClient(EurekaRegistration reg)方法中reg.getEurekaClient().getApplications();会触发在EurekaClientAutoConfiguration自动配置中对EureakClient的延迟创建,使用的EurekaClient的实现com.netflix.discovery.DiscoveryClient

4.DiscoveryClient:服务发现

这个类来源于 eureka-client-19.3.jar这个包 ,DiscoveryClient这个类是用来和Eureak Server服务端做交互,通过程序的主入口类上的@EnableDiscoveryClient标签开启,该类在EurekaClientAutoConfiguration中被注册,该类的继承关系如下:

在这里插入图片描述
CloudEurekaClient实现了 com.netflix.discovery.DiscoveryClient接口,DiscoveryClient实现了com.netflix.discovery.EurekaClient接口,

EurekaClient是Netflix提供的服务发现抽象的接口,DiscoveryClient是其默认实现,CloudEurekaClient是spring cloud的提供的,其中重写了onCacheRefreshed()方法,目的是在刷新本地注册表缓存之后用于使用ApplicationEventPublisher发布HeartbeatEvent事件。
com.netflix.discovery.shared.LookupService
服务发现顶级接口,里面包含了服务查找方法

/**
 * Lookup service for finding active instances.
 * 用来查找活动的服务实例
 */
public interface LookupService<T> {

    /**
     根据应用名获取该名字对应的应用,Application中描述了该appName对应的多个应用实例
     */
    Application getApplication(String appName);

    /**
    获取所有的应用注册列表,Applications是eureka server返回的所有注册信息
     */
    Applications getApplications();

    /**
    根据ID获取服务实例信息信息对象列表
     */
    List<InstanceInfo> getInstancesById(String id);

    InstanceInfo getNextServerFromEureka(String virtualHostname, boolean secure);
}

com.netflix.discovery.EurekaClient
这里接口也来源于com.netflix.discovery.EurekaClient.1.9.3.jar这个包,EurekaClient是DiscoverClient的接口,定义了服务发现的基本功能,如下:

  • 提供获取InstanceInfo 服务实例信息的功能(以不同的方式)

  • 提供获取本地服务数据(已知地区、自有AZ等)

  • 提供注册和访问客户端的healthcheck健康检查处理程序的能力

他的源码如下

/**
为当前服务实现DiscoveryClient定义一个简单的接口
 * Define a simple interface over the current DiscoveryClient implementation.
 *
 * This interface does NOT try to clean up the current client interface for eureka 1.x. Rather it tries
 * to provide an easier transition path from eureka 1.x to eureka 2.x.
EurekaClient API合同包括:

- 提供获取InstanceInfo 服务实例信息的功能(以不同的方式)

- 提供获取本地客户数据的能力(已知地区、自有AZ等)

- 提供注册和访问客户端的healthcheck处理程序的能力
 * EurekaClient API contracts are:
 *  - provide the ability to get InstanceInfo(s) (in various different ways)
 *  - provide the ability to get data about the local Client (known regions, own AZ etc)
 *  - provide the ability to register and access the healthcheck handler for the client
 *
 * @author David Liu
 */
@ImplementedBy(DiscoveryClient.class)	//实现于DiscoveryClient
public interface EurekaClient extends LookupService {

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

    /**
    根据region地区获取服务列表Applications
     */
    public Applications getApplicationsForARegion(@Nullable String region);

     /**
     根据服务注册地址,返回Applications
     */
    public Applications getApplications(String serviceUrl);
     /**
     根据地址获取服务实例信息列表
     */
    public List<InstanceInfo> getInstancesByVipAddress(String vipAddress, boolean secure);
    
    /** 获取服务的远程注册状态 :InstanceStatus是用来描述服务注册状态的,
    状态有:UP,DOWN,STARTING,OUT_OF_SERVICE,UNKNOWN
     */
    public InstanceInfo.InstanceStatus getInstanceRemoteStatus();
    ...省略一些方法..
     /**
     注册健康检查回调处理器
     */
    @Deprecated
    public void registerHealthCheckCallback(HealthCheckCallback callback);

     /**
     注册健康检查处理器
     */
    public void registerHealthCheck(HealthCheckHandler healthCheckHandler);
    
    ...省略...
    //注册eureak监听器,监听eureka内部状态变化
    public void registerEventListener(EurekaEventListener eventListener);
     /**
     Eureak客户端down机,从Eureak服务端取消服务注册
     */
    public void shutdown();
    ...省略...

该接口是Eureak服务发现接口,在LookupService的基础上扩展,主要定义方法有:

  • 获取Applications服务列表
  • 获取InstanceInfo服务实例信息
  • 获取服务的远程状态(UP,DOWN,STARTING,OUT_OF_SERVICE,UNKNOWN)
  • 注册健康检查回调处理器
  • 注册健康检查处理器
  • 注册eureka状态监听器,监听eureka的状态变化
  • Eureak客户端down机,从Eureak服务端取消服务注册

com.netflix.discovery.DiscoveryClient
服务发现核心实现与Eureka Server交互,功能包括:

  • Eureka客户端负责向Eureka服务器注册实例
  • 与Eureak服务器续租
  • 关闭期间,从Eureka服务器取消租约
  • 查询在Eureka服务器上注册的服务/实例列表

5.总结

这里总结一个Eureak的启动流程

  1. 当程序启动,SpringBoot开启自动配置,EurekaClientAutoConfiguration Eureka客户端自动配置,和EurekaAutoServiceRegistration Eureka自动注册启动
  2. EurekaClientAutoConfiguration进行一些列组件的注册,包括对DiscoverClient服务发现客户端的组合,对EurekaServiceRegistry服务注册器的注册
  3. EurekaAutoServiceRegistration监听Web程序启动,调用EurekaServiceRegistry进行服务注册
  4. EurekaServiceRegistry是服务注册器,提供了服务注册,取消注册等方法,其中对DiscoverClient进行初始化,并注册健康检查处理器
  5. 5.DiscoveryClient服务发现客户端,负责与Eureka服务端进行交互

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

墨家巨子@俏如来

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值