在spring cloud 服务发现之Eureka Client(一)—客户端配置DEMO章节中介绍了如何快速的启动一个Eureka Client, 并将当前服务信息注册到Eureka Server中。在这篇文章中,将主要介绍在Eureka Client自动状态的过程中,需要执行那些过程,那些类是在启动过程中比不可少了。
这篇文章中,主要介绍通用的使用过程,其他的装配过程基本类似。
EnableDiscoveryClient
该类作为通用的服务发现客户端的启用类,可以用作不同的服务发现组件。该类源码如下:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(EnableDiscoveryClientImportSelector.class) public @interface EnableDiscoveryClient { /** * If true, the ServiceRegistry will automatically register the local server. * @return - {@code true} if you want to automatically register. */ boolean autoRegister() default true; }
通过该类的源码可以看到,该类型通过Import
引入了EnableDiscoveryClientImportSelector
类型,该类型主要是对EnableDiscoveryClient
注解的解析和配置。
EnableDiscoveryClientImportSelector
@Order(Ordered.LOWEST_PRECEDENCE - 100) public class EnableDiscoveryClientImportSelector extends SpringFactoryImportSelector<EnableDiscoveryClient> { @Override public String[] selectImports(AnnotationMetadata metadata) { String[] imports = super.selectImports(metadata); AnnotationAttributes attributes = AnnotationAttributes.fromMap( metadata.getAnnotationAttributes(getAnnotationClass().getName(), true)); // 判断是否auto register boolean autoRegister = attributes.getBoolean("autoRegister"); if (autoRegister) { List<String> importsList = new ArrayList<>(Arrays.asList(imports)); // 自动引入AutoServiceRegistrationConfiguration importsList.add( "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration"); imports = importsList.toArray(new String[0]); } else { Environment env = getEnvironment(); if (ConfigurableEnvironment.class.isInstance(env)) { ConfigurableEnvironment configEnv = (ConfigurableEnvironment) env; LinkedHashMap<String, Object> map = new LinkedHashMap<>(); map.put("spring.cloud.service-registry.auto-registration.enabled", false); MapPropertySource propertySource = new MapPropertySource( "springCloudDiscoveryClient", map); configEnv.getPropertySources().addLast(propertySource); } } return imports; } }
通过Import
的方式,引入了新的配置AutoServiceRegistrationConfiguration
类型。
AutoServiceRegistrationConfiguration
@Configuration @EnableConfigurationProperties(AutoServiceRegistrationProperties.class) @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) public class AutoServiceRegistrationConfiguration { }
该类主要是判断spring.cloud.service-registry.auto-registration.enabled
的配置信息是否启用服务自动注册功能,并引入配置类AutoServiceRegistrationProperties
.
注解的功能整体到该类就截止了,整体并没有特殊的功能,主要就是加载必要的配置类型,生成Properties配置文件。
AutoServiceRegistrationAutoConfiguration
@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 (this.autoServiceRegistration == null && this.properties.isFailFast()) { throw new IllegalStateException("Auto Service Registration has " + "been requested, but there is no AutoServiceRegistration bean"); } } }
这是一个装配类型,该类型的启动,主要依赖于spring.cloud.service-registry.auto-registration.enabled
配置的值,在缺省情况下为true。在该类中,主要会依赖注入两个类型,AutoServiceRegistrationProperties
与AutoServiceRegistration
类型,下面主要看下AutoServiceRegistration
类型,该类在什么地方被创建?
EurekaDiscoveryClientConfigServiceBootstrapConfiguration
在Spring boot 启动过程中会扫描spring.factories
文件,并加载文件中的配置内容,在Spring cloud commons中,有如下配置:
org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceBootstrapConfiguration
查看该类的配置源码:
@ConditionalOnClass(ConfigServicePropertySourceLocator.class) @ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled", matchIfMissing = false) @Configuration @Import({ EurekaDiscoveryClientConfiguration.class, // this emulates // @EnableDiscoveryClient, the import // selector doesn't run before the // bootstrap phase EurekaClientAutoConfiguration.class }) public class EurekaDiscoveryClientConfigServiceBootstrapConfiguration { }
该类被启动有两个条件:
ConfigServicePropertySourceLocator
类必须存在spring.cloud.config.discovery.enabled
启动
当以上两个条件满足时, 该类才会启动配置, 在装配的过程中,主要设计到两个配置对象: EurekaDiscoveryClientConfiguration
与 EurekaClientAutoConfiguration
EurekaDiscoveryClientConfiguration
查看该类源码:
@Configuration @EnableConfigurationProperties @ConditionalOnClass(EurekaClientConfig.class) @ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true) @ConditionalOnDiscoveryEnabled public class EurekaDiscoveryClientConfiguration { @Bean public Marker eurekaDiscoverClientMarker() { return new Marker(); } @Configuration @ConditionalOnProperty(value = "eureka.client.healthcheck.enabled", matchIfMissing = false) protected static class EurekaHealthCheckHandlerConfiguration { @Autowired(required = false) private HealthAggregator healthAggregator = new OrderedHealthAggregator(); @Bean @ConditionalOnMissingBean(HealthCheckHandler.class) public EurekaHealthCheckHandler eurekaHealthCheckHandler() { return new EurekaHealthCheckHandler(this.healthAggregator); } } class Marker { } @Configuration @ConditionalOnClass(RefreshScopeRefreshedEvent.class) protected static class EurekaClientConfigurationRefresher implements ApplicationListener<RefreshScopeRefreshedEvent> { @Autowired(required = false) private EurekaClient eurekaClient; @Autowired(required = false) private EurekaAutoServiceRegistration autoRegistration; public void onApplicationEvent(RefreshScopeRefreshedEvent event) { // This will force the creation of the EurkaClient bean if not already created // to make sure the client will be reregistered after a refresh event if (eurekaClient != null) { eurekaClient.getApplications(); } if (autoRegistration != null) { // register in case meta data changed this.autoRegistration.stop(); this.autoRegistration.start(); } } } }
该装配类型生效,需要满足一下条件:
- 在
classpath
中必须要引入EurekaClientConfig
类型 - 启用配置
eureka.client.enabled
, 默认值为true
- 启用
spring.cloud.config.discovery.enabled
配置,默认值为true
该配置类型主要做了两件事情:
- 生成
Marker
对象,在Eureka Server
装配时,也是通过Marker对象来启动装配的,因此这个Marker
也是作为开关使用 - 根据
eureka.client.healthcheck.enabled
默认值为false
,如果为true
,则开启EurekaHealthCheckHandler
类型 - 生成
EurekaClientConfigurationRefresher
Bean, 用于处理RefreshScopeRefreshedEvent
事件.
EurekaClientAutoConfiguration
@Configuration @EnableConfigurationProperties @ConditionalOnClass(EurekaClientConfig.class) @Import(DiscoveryClientOptionalArgsConfiguration.class) @ConditionalOnBean(EurekaDiscoveryClientConfiguration.Marker.class) @ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true) @ConditionalOnDiscoveryEnabled @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" })
首先需要关注该装配类型什么时候能够生效, 当前类型生效需要满足以下条件:
- 在
classpath
环境中能够找到EurekaClientConfig
类型 - 需要依赖
EurekaDiscoveryClientConfiguration
中生成Marker
Bean对象。 - 需要启用配置
eureka.client.enabled
,默认值为true
- 需要启用配置
spring.cloud.discovery.enabled
,默认为true
当环境中满足以上权限时,则EurekaClientAutoConfiguration自动装配开始,在装配开始前,主要包含了:
- 引入
DiscoveryClientOptionalArgsConfiguration
配置类型 AutoConfigureBefore
配置了当前配置完成后,继续配置NoopDiscoveryClientAutoConfiguration
,CommonsClientAutoConfiguration
,ServiceRegistryAutoConfiguration
装配类型AutoConfigureAfter
装配开始前,则需要引入RefreshAutoConfiguration
,EurekaDiscoveryClientConfiguration
,AutoServiceRegistrationAutoConfiguration
类型
DiscoveryClientOptionalArgsConfiguration
该类型从命名上可知,这是一个可选项,源码如下:
@Configuration public class DiscoveryClientOptionalArgsConfiguration { @Bean @ConditionalOnMissingClass("com.sun.jersey.api.client.filter.ClientFilter") @ConditionalOnMissingBean(value = AbstractDiscoveryClientOptionalArgs.class, search = SearchStrategy.CURRENT) public RestTemplateDiscoveryClientOptionalArgs restTemplateDiscoveryClientOptionalArgs() { return new RestTemplateDiscoveryClientOptionalArgs(); } @Bean @ConditionalOnClass(name = "com.sun.jersey.api.client.filter.ClientFilter") @ConditionalOnMissingBean(value = AbstractDiscoveryClientOptionalArgs.class, search = SearchStrategy.CURRENT) public MutableDiscoveryClientOptionalArgs discoveryClientOptionalArgs() { return new MutableDiscoveryClientOptionalArgs(); } }
该类型主要是配置DiscoveryClient
使用,在缺少AbstractDiscoveryClientOptionalArgs
对象时,能够生成对应对象,用于存储参数信息。
前置装配 – RefreshAutoConfiguration
在装配开始前,将优先配置该类, 该类具体源码如下:
@Configuration @ConditionalOnClass(RefreshScope.class) @ConditionalOnProperty(name = RefreshAutoConfiguration.REFRESH_SCOPE_ENABLED, matchIfMissing = true) @AutoConfigureBefore(HibernateJpaAutoConfiguration.class) public class RefreshAutoConfiguration { /** * Name of the refresh scope name. */ public static final String REFRESH_SCOPE_NAME = "refresh"; /** * Name of the prefix for refresh scope. */ public static final String REFRESH_SCOPE_PREFIX = "spring.cloud.refresh"; /** * Name of the enabled prefix for refresh scope. */ public static final String REFRESH_SCOPE_ENABLED = REFRESH_SCOPE_PREFIX + ".enabled"; @Bean @ConditionalOnMissingBean(RefreshScope.class) public static RefreshScope refreshScope() { return new RefreshScope(); } @Bean @ConditionalOnMissingBean public static LoggingRebinder loggingRebinder() { return new LoggingRebinder(); } @Bean @ConditionalOnMissingBean public ContextRefresher contextRefresher(ConfigurableApplicationContext context, RefreshScope scope) { return new ContextRefresher(context, scope); } @Bean public RefreshEventListener refreshEventListener(ContextRefresher contextRefresher) { return new RefreshEventListener(contextRefresher); } @Configuration @ConditionalOnClass(name = "javax.persistence.EntityManagerFactory") protected static class JpaInvokerConfiguration implements LoadTimeWeaverAware { @Autowired private ListableBeanFactory beanFactory; @PostConstruct public void init() { String cls = "org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker"; if (this.beanFactory.containsBean(cls)) { this.beanFactory.getBean(cls); } } @Override public void setLoadTimeWeaver(LoadTimeWeaver ltw) { } } .... }
该类型主要是对spring cloud中RefreshScope
相关的配置信息, 这里不错探讨
前置装配-EurekaDiscoveryClientConfiguration
该类前面已经详细说过,这里就不再讲述了
前置装配-AutoServiceRegistrationAutoConfiguration
该类前面也已经讲述过了,这里也不在讲述.
装配中-EurekaClientConfigBean
@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; }
该类主要是实现EurekaClient
配置对象,该类是基于EurekaClientConfig
进行二次封装, 主要由spring实现。在properties中的eureka.client
前缀配置信息,最终会被解析为当前对象。
装配中-ManagementMetadataProvider
@Bean @ConditionalOnMissingBean public ManagementMetadataProvider serviceManagementMetadataProvider() { return new DefaultManagementMetadataProvider(); }
该类主要对Instance中的元数据信息进行管理,
装配中-InetUtils
这个类型是Spring提供的一个工具类,该类的自动注入是放在spring-cloud-commons模块中,通过UtilAutoConfiguration
类型进行装配,源码如下:
@Configuration @ConditionalOnProperty(value = "spring.cloud.util.enabled", matchIfMissing = true) @AutoConfigureOrder(0) @EnableConfigurationProperties public class UtilAutoConfiguration { @Bean public InetUtilsProperties inetUtilsProperties() { return new InetUtilsProperties(); } @Bean @ConditionalOnMissingBean public InetUtils inetUtils(InetUtilsProperties properties) { return new InetUtils(properties); } }
该类的装配实现中,依赖spring.cloud.util.enabled
的配置信息,该配置信息默认true
装配中-EurekaInstanceConfigBean
@Bean @ConditionalOnMissingBean(value = EurekaInstanceConfig.class, search = SearchStrategy.CURRENT) public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils, ManagementMetadataProvider managementMetadataProvider) { // 当前实例hostName String hostname = getProperty("eureka.instance.hostname"); // prefer-ip-address配置 boolean preferIpAddress = Boolean .parseBoolean(getProperty("eureka.instance.prefer-ip-address")); // 读取ip-address配置 String ipAddress = getProperty("eureka.instance.ip-address"); // 读取secure-port-enabled配置 boolean isSecurePortEnabled = Boolean .parseBoolean(getProperty("eureka.instance.secure-port-enabled")); // 获取servlet context-path信息 String serverContextPath = env.getProperty("server.servlet.context-path", "/"); // 获取port信息 int serverPort = Integer.parseInt( env.getProperty("server.port", env.getProperty("port", "8080"))); // 获取management信息 Integer managementPort = env.getProperty("management.server.port", Integer.class); // 获取management servlet context-path信息 String managementContextPath = env .getProperty("management.server.servlet.context-path"); // 获取jmx 中remote port信息 Integer jmxPort = env.getProperty("com.sun.management.jmxremote.port",Integer.class); // 初始化ConfigBean对象,该对象在初始化过程中, 将会获取当前服务的实例信息 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); } // 获取status-page-url-path信息 String statusPageUrlPath = getProperty("eureka.instance.status-page-url-path"); // 获取health-check-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); } // 获取与management 相关的信息组装 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(); metadataMap.computeIfAbsent("management.port", k -> 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; }
该方法其实是为了组装EurekaInstanceConfigBean
对象信息,该对象信息是通过前置配置eureka.instance.*
进行配置。该类型在配置换完成之后,则包含了默认的配置信息。
在初始化EurekaInstanceConfigBean
对象时,传入的参数中需要InetUtil对象作为参数, 我们看下该类主要用处:
public EurekaInstanceConfigBean(InetUtils inetUtils) { this.inetUtils = inetUtils; this.hostInfo = this.inetUtils.findFirstNonLoopbackHostInfo(); this.ipAddress = this.hostInfo.getIpAddress(); this.hostname = this.hostInfo.getHostname(); }
从代码中不难看出,在初始化bean时,主要需要赋值三个元素:
- 获取当前服务实例的hostInfo信息
- 获取当前服务实例的ipAddress信息
- 获取当前服务实例的hostname信息
这三个信息都是通过inetutils.findFirstNonLoopbackHostInfo()
中进行获取,具体查看下该方法中执行逻辑:
public HostInfo findFirstNonLoopbackHostInfo() { InetAddress address = findFirstNonLoopbackAddress(); if (address != null) { return convertAddress(address); } HostInfo hostInfo = new HostInfo(); hostInfo.setHostname(this.properties.getDefaultHostname()); hostInfo.setIpAddress(this.properties.getDefaultIpAddress()); return hostInfo; }
public InetAddress findFirstNonLoopbackAddress() { InetAddress result = null; try { int lowest = Integer.MAX_VALUE; // 获取当前实例下的所有绑定IP地址列表 for (Enumeration<NetworkInterface> nics = NetworkInterface .getNetworkInterfaces(); nics.hasMoreElements();) { NetworkInterface ifc = nics.nextElement(); // 判断当前的network interface是否处于UP并且处于running状态 if (ifc.isUp()) { this.log.trace("Testing interface: " + ifc.getDisplayName()); if (ifc.getIndex() < lowest || result == null) { lowest = ifc.getIndex(); } else if (result != null) { continue; } // @formatter:off if (!ignoreInterface(ifc.getDisplayName())) { for (Enumeration<InetAddress> addrs = ifc .getInetAddresses(); addrs.hasMoreElements();) { InetAddress address = addrs.nextElement(); if (address instanceof Inet4Address && !address.isLoopbackAddress() // 判断是否为循环IP地址, 该类IP地址主要由软件实现 && isPreferredAddress(address)) { this.log.trace("Found non-loopback interface: " + ifc.getDisplayName()); result = address; } } } // @formatter:on } } } catch (IOException ex) { this.log.error("Cannot get first non-loopback address", ex); } if (result != null) { return result; } try { // 如果默认没有获取到IP地址,则使用本地地址作为IP地址 return InetAddress.getLocalHost(); } catch (UnknownHostException e) { this.log.warn("Unable to retrieve localhost"); } return null; }
装配中-EurekaServiceRegistry
@Bean public EurekaServiceRegistry eurekaServiceRegistry() { return new EurekaServiceRegistry(); }
装配中-ApplicationInfoManager
@Bean @ConditionalOnMissingBean(value = ApplicationInfoManager.class, search = SearchStrategy.CURRENT) @org.springframework.cloud.context.config.annotation.RefreshScope @Lazy public ApplicationInfoManager eurekaApplicationInfoManager( EurekaInstanceConfig config) { InstanceInfo instanceInfo = new InstanceInfoFactory().create(config); return new ApplicationInfoManager(config, instanceInfo); }
该类主要依赖了前面的EurekaInstanceConfigBean
对象,然后通过create方法创建InstanceInfo
信息,然后再通过ApplicationInfoManager
进行管理当前实例信息.
装配中-EurekaClient
该类作为主要核心类,则主要负责与Eureka Server进行通信,并获取Applications列表, 该类装配实现是在RefreshableEurekaClientConfiguration
中实现,因为我们当前处于spring-cloud的环境中,依赖于refresh scope的实现。具体代码如下
@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, @Autowired(required = false) HealthCheckHandler healthCheckHandler) { // If we use the proxy of the ApplicationInfoManager we could run into a // problem // when shutdown is called on the CloudEurekaClient where the // ApplicationInfoManager bean is // requested but wont be allowed because we are shutting down. To avoid this // we use the // object directly. ApplicationInfoManager appManager; if (AopUtils.isAopProxy(manager)) { appManager = ProxyUtils.getTargetObject(manager); } else { appManager = manager; } CloudEurekaClient cloudEurekaClient = new CloudEurekaClient(appManager, config, this.optionalArgs, this.context); cloudEurekaClient.registerHealthCheck(healthCheckHandler); return cloudEurekaClient; }
在创建EurekaClient
对象时,主要使用了CloudEurekaClient
对象实现了原始netflix的EurekaClient
的实现,同时注册HealthCheckHandler
对象。保证EurekaClient
正常的运作。
装配中-EurekaRegistration
该类主要保存了当前服务实例的注册信息,具体源码如下:
@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(); }
通过以上信息可以看出, 当前类型生效的有一下前提:
AutoServiceRegistrationProperties
bean的存在,而该Bean则是通过EnableDiscoveryClient
进行初始化- 开启
spring.cloud.service-registry.auto-registration.enabled
配置信息,默认为true
通过以上信息可以看出,在默认情况下,该类是能够自动装配的。
装配中-EurekaAutoServiceRegistration
该类则是开启自动服务注册的入口,配置如下:
@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); }
装配后置-NoopDiscoveryClientAutoConfiguration
该类已经被标记为废除,同时依赖于没有DiscoveryClient
对象,通过以上步骤,会发现,当前装配类不会执行。
装配后置-CommonsClientAutoConfiguration
该类主要作为通用的DiscoveryClient
的配置, 主要是配置HealIndicator
对象,具体代码如下:
@Configuration @AutoConfigureOrder(0) public class CommonsClientAutoConfiguration { @Configuration @EnableConfigurationProperties(DiscoveryClientHealthIndicatorProperties.class) @ConditionalOnClass(HealthIndicator.class) @ConditionalOnBean(DiscoveryClient.class) @ConditionalOnDiscoveryEnabled protected static class DiscoveryLoadBalancerConfiguration { @Bean @ConditionalOnProperty(value = "spring.cloud.discovery.client.health-indicator.enabled", matchIfMissing = true) public DiscoveryClientHealthIndicator discoveryClientHealthIndicator( ObjectProvider<DiscoveryClient> discoveryClient, DiscoveryClientHealthIndicatorProperties properties) { return new DiscoveryClientHealthIndicator(discoveryClient, properties); } @Bean @ConditionalOnProperty(value = "spring.cloud.discovery.client.composite-indicator.enabled", matchIfMissing = true) @ConditionalOnBean({ DiscoveryHealthIndicator.class, HealthAggregator.class }) public DiscoveryCompositeHealthIndicator discoveryCompositeHealthIndicator( HealthAggregator aggregator, List<DiscoveryHealthIndicator> indicators) { return new DiscoveryCompositeHealthIndicator(aggregator, indicators); } @Bean public HasFeatures commonsFeatures() { return HasFeatures.abstractFeatures(DiscoveryClient.class, LoadBalancerClient.class); } } @Configuration @ConditionalOnClass(Endpoint.class) @ConditionalOnProperty(value = "spring.cloud.features.enabled", matchIfMissing = true) protected static class ActuatorConfiguration { @Autowired(required = false) private List<HasFeatures> hasFeatures = new ArrayList<>(); @Bean @ConditionalOnEnabledEndpoint public FeaturesEndpoint featuresEndpoint() { return new FeaturesEndpoint(this.hasFeatures); } } }
装配后置-ServiceRegistryAutoConfiguration
该类主要是对ServiceRegistry的再次封装,返回ServiceRegistryEndpoint对象,具体配置如下:
@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(this.registration); return endpoint; } } }
以上就是Eureka Client整体装配过程,后面将对里面的细节进行详细的说明。
当我们有时候会发现会后的两个配置不会执行,是因为最后两项都是对registry的服务状态的暴露,因此需要我们引入spring-boot-starter-actuator之后,就能够正常执行了