本文已参与「新人创作礼」活动,一起开启掘金创作之路。
eureka-server启动
eureka-server作为web应用启动,执行监听器(com.netflix.eureka.EurekaBootStrap)初始化方法(contextInitialized(ServletContextEvent sce))。
- eureka-server 初始化环境:
initEurekaEnvironment(); - eureka-server 初始化上下文:
initEurekaServerContext();
package com.netflix.eureka;
/**
* The class that kick starts the eureka server.
*
* <p>
* The eureka server is configured by using the configuration
* {@link EurekaServerConfig} specified by <em>eureka.server.props</em> in the
* classpath. The eureka client component is also initialized by using the
* configuration {@link EurekaInstanceConfig} specified by
* <em>eureka.client.props</em>. If the server runs in the AWS cloud, the eureka
* server binds it to the elastic ip as specified.
* </p>
*
* @author Karthik Ranganathan, Greg Kim, David Liu
*/
/**
* 本质是个监听器
* <p>
* contextInitialized(ServletContextEvent sce) :当Servlet 容器启动Web 应用时调用该方法。在调用完该方法之后,容器再对Filter
* 初始化,并且对那些在Web 应用启动时就需要被初始化的Servlet 进行初始化。
* <p>
* contextDestroyed(ServletContextEvent sce) :当Servlet 容器终止Web 应用时调用该方法。在调用该方法之前,容器会先销毁所有的Servlet
* 和Filter 过滤器。
*/
public class EurekaBootStrap implements ServletContextListener {
/**
* Initializes Eureka, including syncing up with other Eureka peers and publishing the registry.
*
* @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
*/
/**
* 当Servlet 容器启动Web 应用时调用该方法。
* 在调用完该方法之后,容器再对Filter初始化,并且对那些在Web 应用启动时就需要被初始化的Servlet 进行初始化。
*
* @param event
*/
@Override
public void contextInitialized(ServletContextEvent event) {
try {
// 初始化 eureka-server 环境
initEurekaEnvironment();
// 初始化 eureka-server 容器
initEurekaServerContext();
// 获取 servletContext
ServletContext sc = event.getServletContext();
// 设置 servletContext 属性
// com.netflix.eureka.EurekaServerContext = EurekaServerContext 实例
sc.setAttribute(EurekaServerContext.class.getName(), serverContext);
} catch (Throwable e) {
logger.error("Cannot bootstrap eureka server :", e);
throw new RuntimeException("Cannot bootstrap eureka server :", e);
}
}
}
eureka-server初始化环境:initEurekaEnvironment();
配置管理器(double-checked locking)
ConfigurationManager.instance =(AbstractConfiguration)ConcurrentCompositeConfiguration;
ConcurrentCompositeConfiguration.addConfiguration(AbstractConfiguration);
创建一个 (AbstractConfiguration)ConcurrentCompositeConfiguration 实例,加入其他(AbstractConfiguration)config
ConfigurationManager.getConfigInstance()
public static AbstractConfiguration getConfigInstance() {
if (instance == null) {
synchronized (ConfigurationManager.class) {
if (instance == null) {
instance = getConfigInstance(Boolean.getBoolean(DynamicPropertyFactory.DISABLE_DEFAULT_CONFIG));
}
}
}
return instance;
}
private static AbstractConfiguration createDefaultConfigInstance() {
ConcurrentCompositeConfiguration config = new ConcurrentCompositeConfiguration();
try {
DynamicURLConfiguration defaultURLConfig = new DynamicURLConfiguration();
config.addConfiguration(defaultURLConfig, URL_CONFIG_NAME);
} catch (Throwable e) {
logger.warn("Failed to create default dynamic configuration", e);
}
if (!Boolean.getBoolean(DISABLE_DEFAULT_SYS_CONFIG)) {
SystemConfiguration sysConfig = new SystemConfiguration();
config.addConfiguration(sysConfig, SYS_CONFIG_NAME);
}
if (!Boolean.getBoolean(DISABLE_DEFAULT_ENV_CONFIG)) {
EnvironmentConfiguration envConfig = new EnvironmentConfiguration();
config.addConfiguration(envConfig, ENV_CONFIG_NAME);
}
ConcurrentCompositeConfiguration appOverrideConfig = new ConcurrentCompositeConfiguration();
config.addConfiguration(appOverrideConfig, APPLICATION_PROPERTIES);
config.setContainerConfigurationIndex(config.getIndexOfConfiguration(appOverrideConfig));
return config;
}
初始化数据中心
初始化数据中心(eureka.datacenter)的配置,如果没有配置的话,就是DEFAULT(default)
初始化运行环境
初始化eureka运行的环境(eureka.environment),如果你没有配置的话,默认设置为test环境
eureka-server 初始化上下文:initEurekaServerContext();
/**
* init hook for server context. Override for custom logic.
*/
protected void initEurekaServerContext() throws Exception {
// 获取 eureka-server 配置
// 面向接口的配置项读取
// DefaultEurekaServerConfig 创建实例时,执行init()方法,完成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);
ApplicationInfoManager applicationInfoManager = null;
// 获取应用管理器及Eureka客户端
if (eurekaClient == null) {
// EurekaClient 如果为 null
// 获取 eureka实例配置 实例
EurekaInstanceConfig instanceConfig =
isCloud(ConfigurationManager.getDeploymentContext()) ?
new CloudInstanceConfig() : new MyDataCenterInstanceConfig();
// 获取 应用信息管理器
applicationInfoManager = new ApplicationInfoManager(
// eureka实例配置 实例
instanceConfig,
// 基于 eureka实例配置 实例 获取 InstanceInfo 实例信息 实例
new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get());
// 获取 eureka客户端配置 实例
EurekaClientConfig eurekaClientConfig = new DefaultEurekaClientConfig();
// 获取 (EurekaClient)DiscoveryClient eureka客户端 实例
eurekaClient = new DiscoveryClient(applicationInfoManager, eurekaClientConfig);
} else {
// EurekaClient 不为空
// 获取 应用信息管理器
applicationInfoManager = eurekaClient.getApplicationInfoManager();
}
PeerAwareInstanceRegistry registry;
if (isAws(applicationInfoManager.getInfo())) { // 判断 实例信息 是不是 aws类型实例
// 如果是 aws类型实例
registry = new AwsInstanceRegistry(eurekaServerConfig,
eurekaClient.getEurekaClientConfig(), serverCodecs, eurekaClient);
awsBinder = new AwsBinderDelegate(eurekaServerConfig,
eurekaClient.getEurekaClientConfig(), registry, applicationInfoManager);
awsBinder.start();
} else {
// 如果不是 aws类型实例
// 获取 PeerAwareInstanceRegistry 注册表
// 服务配置信息、客户端配置信息、服务编码组件、客户端组件
registry = new PeerAwareInstanceRegistryImpl(eurekaServerConfig,
eurekaClient.getEurekaClientConfig(), serverCodecs, eurekaClient);
}
// 根据 注册表、服务端配置信息、客户端配置信息、服务编码组件、应用信息管理器等获取 Eureka单个服务节点 实例
PeerEurekaNodes peerEurekaNodes = getPeerEurekaNodes(registry, eurekaServerConfig,
eurekaClient.getEurekaClientConfig(), serverCodecs, applicationInfoManager);
// 获取 eureka服务上下文
serverContext = new DefaultEurekaServerContext(eurekaServerConfig, serverCodecs, registry
, peerEurekaNodes, applicationInfoManager);
// 构建 EurekaServerContextHolder 持有 EurekaServerContext serverContext
EurekaServerContextHolder.initialize(serverContext);
// EurekaServerContext serverContext eureka服务上下文初始化
serverContext.initialize();
logger.info("Initialized server context");
//
// Copy registry from neighboring eureka node
int registryCount = registry.syncUp();
registry.openForTraffic(applicationInfoManager, registryCount);
// Register all monitoring statistics.
EurekaMonitors.registerAllStats();
}
配置文件加载
面向接口的配置项读取
/**
* Configuration information required by the eureka server to operate.
*
* <p>
* Most of the required information is provided by the default configuration
* {@link com.netflix.eureka.DefaultEurekaServerConfig}.
*
* Note that all configurations are not effective at runtime unless and
* otherwise specified.
* </p>
*
* @author Karthik Ranganathan
*
*/
public interface EurekaServerConfig {
}
EurekaServerConfig 接口定义了所有eureka server需要的所有配置项,通过getXXX()的方法获取。
EurekaServerConfig 接口代表了eureka-server需要的所有的配置项。
/**
* A default implementation of eureka server configuration as required by
* {@link EurekaServerConfig}.
*
* <p>
* The information required for configuring eureka server is provided in a
* configuration file.The configuration file is searched for in the classpath
* with the name specified by the property <em>eureka.server.props</em> and with
* the suffix <em>.properties</em>. If the property is not specified,
* <em>eureka-server.properties</em> is assumed as the default.The properties
* that are looked up uses the <em>namespace</em> passed on to this class.
* </p>
*
* <p>
* If the <em>eureka.environment</em> property is specified, additionally
* <em>eureka-server-<eureka.environment>.properties</em> is loaded in addition
* to <em>eureka-server.properties</em>.
* </p>
*
* @author Karthik Ranganathan
*/
@Singleton
public class DefaultEurekaServerConfig implements EurekaServerConfig {
}
DefaultEurekaServerConfig 类实现 EurekaServerConfig 接口。
执行构造方法时,会执行一个init()方法,完成eureka-server.properties文件和eureka-server-环境.properties中的配置项的加载。
private static final DynamicStringProperty EUREKA_PROPS_FILE = DynamicPropertyFactory.getInstance().getStringProperty("eureka.server.props", "eureka"+ "-server");
EUREKA_PROPS_FILE,对应着要加载的eureka的配置文件的名字。默认是eureka-server
/**
* 加载properties中的配置,放入ConfigurationManager,由ConfigurationManager管理
*/
private void init() {
// 获取环境,默认是test(为了拼接配置文件名:eureka-server-test.properties)
String env = ConfigurationManager.getConfigInstance().getString(EUREKA_ENVIRONMENT, TEST);
// 更新 archaius.deployment.environment 对应的是什么环境
ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_ENVIRONMENT, env);
// 要加载的eureka的配置文件的名字。默认是 eureka-server
String eurekaPropsFile = EUREKA_PROPS_FILE.get();
try {
// 加载eureka-server.properties和eureka-server-环境.properties中的配置,加载到了Properties对象中去;
// eureka-server-环境.properties 覆盖 相同key的 eureka-server-环境.properties 配置
// 将加载出来的Properties中的配置项都放到ConfigurationManager中去,由ConfigurationManager管理
ConfigurationManager.loadCascadedPropertiesFromResources(eurekaPropsFile);
} catch (IOException e) {
logger.warn("Cannot find the properties specified : {}. This may be okay if there " + "are" + " " + "other environment " + "specific properties or the " + "configuration is " + "installed with a " + "different mechanism.", eurekaPropsFile);
}
}
加载eureka-server.properties
-
创建
DefaultEurekaServerConfig对象 -
执行DefaultEurekaServerConfig构造方法时调用init()方法
-
加载eureka-server.properties和eureka-server.properties中的配置到Properties对象中,将Properties对象中的配置放到ConfigurationManager中去
-
DefaultEurekaServerConfig提供的获取配置项的各个方法,都是通过硬编码的配置项名称,从DynamicPropertyFactory中获取配置项的值。 -
在获取配置项的时候,如果没有配置,那么就会有默认的值,全部属性都是有默认值的
获取DefaultEurekaServerConfig中的配置项的值
@Override
public String getAWSAccessId() {
String aWSAccessId =
configInstance.getStringProperty(namespace + "awsAccessId", null).get();
if (null != aWSAccessId) {
return aWSAccessId.trim();
} else {
return null;
}
}
DynamicPropertyFactory与ConfigurationManager
DynamicPropertyFactory在获取实例时,会判断config是否为null,如果为null的话,会从ConfigurationManager获取config。
DynamicPropertyFactory是从ConfigurationManager那儿来的,所以也包含了所有配置项的值
private static final DynamicPropertyFactory configInstance = com.netflix.config.DynamicPropertyFactory.getInstance();
public static DynamicPropertyFactory getInstance() {
if (config == null) {
synchronized (ConfigurationManager.class) {
if (config == null) {
AbstractConfiguration configFromManager = ConfigurationManager.getConfigInstance();
if (configFromManager != null) {
initWithConfigurationSource(configFromManager);
initializedWithDefaultConfig = !ConfigurationManager.isConfigurationInstalled();
logger.info("DynamicPropertyFactory is initialized with configuration sources: " + configFromManager);
}
}
}
}
return instance;
}
加载properties文件到Properties对象,放到ConfigurationManager中
从DynamicPropertyFactory读取
存:configurationManager
取:DynamicPropertyFactory