理解微服務註冊到Eureka Server上的過程(以appname爲例)

閱讀本文你將瞭解

  • 微服務註冊到Eureka Server上的粗粒度過程
  • 爲什麼appname是大寫。
  • appName的配置:spring.application.name與eureka.instance.appname,及它們的優先級。

Prepare

首先解釋一下什麼是appname

圖中的CONFIG-SERVER,GATEWAY,IOT 就是appname。下面我們來分析一下它的詳細邏輯。

(1) 首先找到:org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration.EurekaClientConfiguration.eurekaApplicationInfoManager(EurekaInstanceConfig)

裏面有以下代碼:

@Bean
@ConditionalOnMissingBean(value = ApplicationInfoManager.class, search = SearchStrategy.CURRENT)
public ApplicationInfoManager eurekaApplicationInfoManager(EurekaInstanceConfig config) {
InstanceInfo instanceInfo = new InstanceInfoFactory().create(config);
return new ApplicationInfoManager(config, instanceInfo);
}

從中,可以看到,該方法調用了new InstanceInfoFactory().create(config); 。

(2) 跟進org.springframework.cloud.netflix.eureka.InstanceInfoFactory.create(EurekaInstanceConfig) ,可以看到以下代碼:

public InstanceInfo create(EurekaInstanceConfig config) {
LeaseInfo.Builder leaseInfoBuilder = LeaseInfo.Builder.newBuilder()
.setRenewalIntervalInSecs(config.getLeaseRenewalIntervalInSeconds())
.setDurationInSecs(config.getLeaseExpirationDurationInSeconds());
// Builder the instance information to be registered with eureka
// server
InstanceInfo.Builder builder = InstanceInfo.Builder.newBuilder();
String namespace = config.getNamespace();
if (!namespace.endsWith(".")) {
namespace = namespace + ".";
}
builder.setNamespace(namespace).setAppName(config.getAppname())
.setInstanceId(config.getInstanceId())
.setAppGroupName(config.getAppGroupName())
.setDataCenterInfo(config.getDataCenterInfo())
.setIPAddr(config.getIpAddress()).setHostName(config.getHostName(false))
.setPort(config.getNonSecurePort())
.enablePort(InstanceInfo.PortType.UNSECURE,
config.isNonSecurePortEnabled())
.setSecurePort(config.getSecurePort())
.enablePort(InstanceInfo.PortType.SECURE, config.getSecurePortEnabled())
.setVIPAddress(config.getVirtualHostName())
.setSecureVIPAddress(config.getSecureVirtualHostName())
.setHomePageUrl(config.getHomePageUrlPath(), config.getHomePageUrl())
.setStatusPageUrl(config.getStatusPageUrlPath(),
config.getStatusPageUrl())
.setHealthCheckUrls(config.getHealthCheckUrlPath(),
config.getHealthCheckUrl(), config.getSecureHealthCheckUrl())
.setASGName(config.getASGName());
// Start off with the STARTING state to avoid traffic
if (!config.isInstanceEnabledOnit()) {
InstanceInfo.InstanceStatus initialStatus = InstanceInfo.InstanceStatus.STARTING;
if (log.isInfoEnabled()) {
log.info("Setting initial instance status as: " + initialStatus);
}
builder.setStatus(initialStatus);
}
else {
if (log.isInfoEnabled()) {
log.info("Setting initial instance status as: "
+ InstanceInfo.InstanceStatus.UP
+ ". This may be too early for the instance to advertise itself as available. "
+ "You would instead want to control this via a healthcheck handler.");
}
}
// Add any user-specific metadata information
for (Map.Entry<String, String> mapEntry : config.getMetadataMap().entrySet()) {
String key = mapEntry.getKey();
String value = mapEntry.getValue();
builder.add(key, value);
}
InstanceInfo instanceInfo = builder.build();
instanceInfo.setLeaseInfo(leaseInfoBuilder.build());
return instanceInfo;
}

代碼比較長,但是不難看出,該代碼是在通過傳入的配置,去構建一個InstanceInfo,也就是某個微服務實例的各種信息。

在代碼中,找到以下代碼:

builder.setNamespace(namespace).setAppName(config.getAppname())
.setInstanceId(config.getInstanceId())

我們不妨跟進setAppname中看看。

(3) 查看com.netflix.appinfo.InstanceInfo.Builder.setAppName(String)

public Builder setAppName(String appName) {
result.appName = StringCache.intern(appName.toUpperCase(Locale.ROOT));
return this;
}

我們可以看到,是該方法將appName轉大寫了。

(4) 回到

builder.setNamespace(namespace).setAppName(config.getAppname())
.setInstanceId(config.getInstanceId())

這段代碼,通過DEBUG,我們可以看到代碼中的config,是

org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean

(5) 查看該類,我們會發現這正式Eureka Instance的配置類。因此,我們可以使用eureka.instance.appname去配置appName。

@Data
@ConfigurationProperties("eureka.instance")
public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, EnvironmentAware, InitializingBean {
private static final String UNKNOWN = "unknown";
@Getter(AccessLevel.PRIVATE)
@Setter(AccessLevel.PRIVATE)
private HostInfo hostInfo;
@Getter(AccessLevel.PRIVATE)
@Setter(AccessLevel.PRIVATE)
private InetUtils inetUtils;
/**
* Get the name of the application to be registered with eureka.
*/
private String appname = UNKNOWN;

(6) 那麼,爲什麼我們可以通過spring.application.name去配置微服務的appName呢?代碼在這裏:

org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean.afterPropertiesSet()

@Override
public void afterPropertiesSet() throws Exception {
RelaxedPropertyResolver springPropertyResolver = new RelaxedPropertyResolver(this.environment, "spring.application.");
String springAppName = springPropertyResolver.getProperty("name");
if(StringUtils.hasText(springAppName)) {
setAppname(springAppName);
setVirtualHostName(springAppName);
setSecureVirtualHostName(springAppName);
}
}

經過以上分析,我們可以看到spring.application.name的優先級比eureka.instance.appname高。例如:

server:
    port: 8000
    spring:
        application:
            name: aaa
    eureka:
        client:
            serviceUrl:
            defaultZone: http://localhost:8761/eureka/
            instance:
                appname: bbb
                prefer-ip-address: true

兩者都配置的時候,註冊到Eureka Server上的appname是aaa

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章