Eureka源码分析:ApplicationInfoManager初始化构建
完整初始化代码
// 1、加载eureka-server.properties文件中的配置项
EurekaServerConfig eurekaServerConfig = new DefaultEurekaServerConfig();
// For backward compatibility
JsonXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), XStream.PRIORITY_VERY_HIGH);
XmlXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), XStream.PRIORITY_VERY_HIGH);
logger.info("Initializing the eureka client...");
logger.info(eurekaServerConfig.getJsonCodecName());
ServerCodecs serverCodecs = new DefaultServerCodecs(eurekaServerConfig);
// 2、初始化ApplicationInfoManager
// eureka-client -> Application
ApplicationInfoManager applicationInfoManager = null;
// 3、初始化eureka-server的内部的eureka-client(用于与其他eureka-server节点同步注册和通信)
if (eurekaClient == null) {
// eureka实例配置项
// eureka-client.properties 加载到ConfigurationManager,然后封装到EurekaInstanceConfig中去,对外暴露配置项
// isCloud云获取配置数据 / 获取本地默认配置(PropertiesInstanceConfig)
EurekaInstanceConfig instanceConfig = isCloud(ConfigurationManager.getDeploymentContext())
? new CloudInstanceConfig()
: new MyDataCenterInstanceConfig();
// ApplicationInfoManager 应用信息管理器赋值
applicationInfoManager = new ApplicationInfoManager(
instanceConfig, new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get());
// 获取eureka-client默认配置项
EurekaClientConfig eurekaClientConfig = new DefaultEurekaClientConfig();
// 用ApplicationInfoManager和DefaultEurekaClientConfig,初始化eureka-client
eurekaClient = new DiscoveryClient(applicationInfoManager, eurekaClientConfig);
} else {
// eureka-client中获取 ApplicationInfoManager 应用信息管理器
applicationInfoManager = eurekaClient.getApplicationInfoManager();
}
前置:初始化EurekaInstanceConfig
// eureka实例配置项
// eureka-client.properties 加载到ConfigurationManager,然后封装到EurekaInstanceConfig中去,对外暴露配置项
// isCloud云获取配置数据 / 获取本地默认配置(PropertiesInstanceConfig)
EurekaInstanceConfig instanceConfig = isCloud(ConfigurationManager.getDeploymentContext())
? new CloudInstanceConfig()
: new MyDataCenterInstanceConfig();
// ApplicationInfoManager 应用信息管理器赋值
applicationInfoManager = new ApplicationInfoManager(
instanceConfig, new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get());
当isCloud判断为空时,去获取默认配置项
EurekaInstanceConfig instanceConfig = isCloud(ConfigurationManager.getDeploymentContext())
? new CloudInstanceConfig()
: new MyDataCenterInstanceConfig();
从上图可以得知MyDataCenterInstanceConfig,该类的继承关系
从 eureka-client.properties 文件中获取 eureka 的配置项
AbstractInstanceConfig 存储了各个配置项的默认值
EurekaInstanceConfig则是默认配置项对外暴露的接口
初始化InstanceInfo
InstanceInfo构建初始化核心类
com.netflix.appinfo.providers.EurekaConfigBasedInstanceInfoProvider
InstanceInfo 为 EurekaConfigBasedInstanceInfoProvider 的内部类
com.netflix.appinfo.InstanceInfo
初始化InstanceInfo的核心代码EurekaConfigBasedInstanceInfoProvider#get()
@Override
public synchronized InstanceInfo get() {
// eureka-server的服务实例信息
if (instanceInfo == null) {
// 心跳续约信息
// Build the lease information to be passed to the server based on config
LeaseInfo.Builder leaseInfoBuilder = LeaseInfo.Builder.newBuilder()
.setRenewalIntervalInSecs(config.getLeaseRenewalIntervalInSeconds())
.setDurationInSecs(config.getLeaseExpirationDurationInSeconds());
if (vipAddressResolver == null) {
vipAddressResolver = new Archaius1VipAddressResolver();
}
// 构造器模式,构建服务实例信息
// Builder the instance information to be registered with eureka server
InstanceInfo.Builder builder = InstanceInfo.Builder.newBuilder(vipAddressResolver);
// set the appropriate id for the InstanceInfo, falling back to datacenter Id if applicable, else hostname
String instanceId = config.getInstanceId();
DataCenterInfo dataCenterInfo = config.getDataCenterInfo();
if (instanceId == null || instanceId.isEmpty()) {
if (dataCenterInfo instanceof UniqueIdentifier) {
instanceId = ((UniqueIdentifier) dataCenterInfo).getId();
} else {
instanceId = config.getHostName(false);
}
}
String defaultAddress;
if (config instanceof RefreshableInstanceConfig) {
// Refresh AWS data center info, and return up to date address
defaultAddress = ((RefreshableInstanceConfig) config).resolveDefaultAddress(false);
} else {
defaultAddress = config.getHostName(false);
}
// fail safe
if (defaultAddress == null || defaultAddress.isEmpty()) {
defaultAddress = config.getIpAddress();
}
// 构造器模式构建复杂Bean数据
builder.setNamespace(config.getNamespace())
.setInstanceId(instanceId)
.setAppName(config.getAppname())
.setAppGroupName(config.getAppGroupName())
.setDataCenterInfo(config.getDataCenterInfo())
.setIPAddr(config.getIpAddress())
.setHostName(defaultAddress)
.setPort(config.getNonSecurePort())
.enablePort(PortType.UNSECURE, config.isNonSecurePortEnabled())
.setSecurePort(config.getSecurePort())
.enablePort(PortType.SECURE, config.getSecurePortEnabled())
.setVIPAddress(config.getVirtualHostName())
.setSecureVIPAddress(config.getSecureVirtualHostName())
.setHomePageUrl(config.getHomePageUrlPath(), config.getHomePageUrl())
.setStatusPageUrl(config.getStatusPageUrlPath(), config.getStatusPageUrl())
.setASGName(config.getASGName())
.setHealthCheckUrls(config.getHealthCheckUrlPath(),
config.getHealthCheckUrl(), config.getSecureHealthCheckUrl());
// 初始化当前eureka-server的服务实例状态 InstanceStatus.STARTING/InstanceStatus.UP
// Start off with the STARTING state to avoid traffic
if (!config.isInstanceEnabledOnit()) {
InstanceStatus initialStatus = InstanceStatus.STARTING;
LOG.info("Setting initial instance status as: " + initialStatus);
builder.setStatus(initialStatus);
} else {
LOG.info("Setting initial instance status as: {}. This may be too early for the instance to advertise "
+ "itself as available. You would instead want to control this via a healthcheck handler.",
InstanceStatus.UP);
}
// 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 = builder.build();
// 将续约信息存储到服务实例信息内(InstanceInfo)
instanceInfo.setLeaseInfo(leaseInfoBuilder.build());
}
return instanceInfo;
}
初始化ApplicationInfoManager
/**
* public for DI use. This class should be in singleton scope so do not create explicitly.
* Either use DI or create this explicitly using one of the other public constructors.
*/
@Inject
public ApplicationInfoManager(EurekaInstanceConfig config, InstanceInfo instanceInfo, OptionalArgs optionalArgs) {
// eureka配置项
this.config = config;
// eureka server中的eureka client实例信息
this.instanceInfo = instanceInfo;
// 状态监听器
this.listeners = new ConcurrentHashMap<String, StatusChangeListener>();
if (optionalArgs != null) {
this.instanceStatusMapper = optionalArgs.getInstanceStatusMapper();
} else {
this.instanceStatusMapper = NO_OP_MAPPER;
}
// Hack to allow for getInstance() to use the DI'd ApplicationInfoManager
instance = this;
}