spring cloud 服务发现之Eureka Client(二)—自动装配

spring cloud 服务发现之Eureka Client(一)—客户端配置DEMO章节中介绍了如何快速的启动一个Eureka Client, 并将当前服务信息注册到Eureka Server中。在这篇文章中,将主要介绍在Eureka Client自动状态的过程中,需要执行那些过程,那些类是在启动过程中比不可少了。

这篇文章中,主要介绍通用的使用过程,其他的装配过程基本类似。

EnableDiscoveryClient

该类作为通用的服务发现客户端的启用类,可以用作不同的服务发现组件。该类源码如下:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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;
}
@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; }
@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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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;
}
}
@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; } }
@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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@Configuration
@EnableConfigurationProperties(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public class AutoServiceRegistrationConfiguration {
}
@Configuration @EnableConfigurationProperties(AutoServiceRegistrationProperties.class) @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) public class 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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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");
}
}
}
@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"); } } }
@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。在该类中,主要会依赖注入两个类型,AutoServiceRegistrationPropertiesAutoServiceRegistration 类型,下面主要看下AutoServiceRegistration 类型,该类在什么地方被创建?

EurekaDiscoveryClientConfigServiceBootstrapConfiguration

在Spring boot 启动过程中会扫描spring.factories文件,并加载文件中的配置内容,在Spring cloud commons中,有如下配置:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceBootstrapConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceBootstrapConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceBootstrapConfiguration

查看该类的配置源码:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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 {
}
@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 { }
@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 启动

当以上两个条件满足时, 该类才会启动配置, 在装配的过程中,主要设计到两个配置对象: EurekaDiscoveryClientConfigurationEurekaClientAutoConfiguration

EurekaDiscoveryClientConfiguration

查看该类源码:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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();
}
}
}
}
@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(); } } } }
@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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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" })
@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" })
@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 配置了当前配置完成后,继续配置 NoopDiscoveryClientAutoConfigurationCommonsClientAutoConfigurationServiceRegistryAutoConfiguration装配类型
  • AutoConfigureAfter 装配开始前,则需要引入 RefreshAutoConfiguration, EurekaDiscoveryClientConfiguration, AutoServiceRegistrationAutoConfiguration 类型

DiscoveryClientOptionalArgsConfiguration

该类型从命名上可知,这是一个可选项,源码如下:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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();
}
}
@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(); } }
@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

在装配开始前,将优先配置该类, 该类具体源码如下:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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) {
}
}
....
}
@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) { } } .... }
@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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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;
}
@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; }
@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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@Bean
@ConditionalOnMissingBean
public ManagementMetadataProvider serviceManagementMetadataProvider() {
return new DefaultManagementMetadataProvider();
}
@Bean @ConditionalOnMissingBean public ManagementMetadataProvider serviceManagementMetadataProvider() { return new DefaultManagementMetadataProvider(); }
@Bean
    @ConditionalOnMissingBean
    public ManagementMetadataProvider serviceManagementMetadataProvider() {
        return new DefaultManagementMetadataProvider();
    }

该类主要对Instance中的元数据信息进行管理,

装配中-InetUtils

这个类型是Spring提供的一个工具类,该类的自动注入是放在spring-cloud-commons模块中,通过UtilAutoConfiguration类型进行装配,源码如下:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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);
}
}
@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); } }
@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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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;
}
@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; }
@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对象作为参数, 我们看下该类主要用处:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public EurekaInstanceConfigBean(InetUtils inetUtils) {
this.inetUtils = inetUtils;
this.hostInfo = this.inetUtils.findFirstNonLoopbackHostInfo();
this.ipAddress = this.hostInfo.getIpAddress();
this.hostname = this.hostInfo.getHostname();
}
public EurekaInstanceConfigBean(InetUtils inetUtils) { this.inetUtils = inetUtils; this.hostInfo = this.inetUtils.findFirstNonLoopbackHostInfo(); this.ipAddress = this.hostInfo.getIpAddress(); this.hostname = this.hostInfo.getHostname(); }
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()中进行获取,具体查看下该方法中执行逻辑:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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 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 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;
    }
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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;
}
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; }
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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@Bean
public EurekaServiceRegistry eurekaServiceRegistry() {
return new EurekaServiceRegistry();
}
@Bean public EurekaServiceRegistry eurekaServiceRegistry() { return new EurekaServiceRegistry(); }
@Bean
    public EurekaServiceRegistry eurekaServiceRegistry() {
        return new EurekaServiceRegistry();
    }

装配中-ApplicationInfoManager

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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);
}
@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); }
@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的实现。具体代码如下

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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;
}
@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; }
@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

该类主要保存了当前服务实例的注册信息,具体源码如下:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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();
}
@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(); }
@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

该类则是开启自动服务注册的入口,配置如下:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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);
}
@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); }
@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对象,具体代码如下:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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);
}
}
}
@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); } } }
@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对象,具体配置如下:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@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;
}
}
}
@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; } } }
@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之后,就能够正常执行了

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注