Spring中的EurekaServer启动详解

 更新时间:2023年11月21日 10:00:41   作者:dalianpai  
这篇文章主要介绍了Spring中的EurekaServer启动详解,初始化eureka,包含eureka集群的同步和发布注册,这个方法时重写ServletContextListener#contextInitialized,是eureka启动的入口了,需要的朋友可以参考下

EurekaServer启动

看方法上的注释,初始化eureka,包含eureka集群的同步和发布注册,这个方法时重写ServletContextListener#contextInitialized,是eureka启动的入口了。

在 Servlet 容器( 例如 Tomcat、Jetty )启动时,调用 #contextInitialized() 方法。

/**
     * Initializes Eureka, including syncing up with other Eureka peers and publishing the registry.
     *
     * @see
     * javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
     */
    @Override
    public void contextInitialized(ServletContextEvent event) {
        try {
            //初始化eureka环境信息
            initEurekaEnvironment();
            //初始化eureka的上下文
            initEurekaServerContext();
 
            ServletContext sc = event.getServletContext();
            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的环境

private static final String TEST = "test";
 
    private static final String ARCHAIUS_DEPLOYMENT_ENVIRONMENT = "archaius.deployment.environment";
 
    private static final String EUREKA_ENVIRONMENT = "eureka.environment";
 
    private static final String CLOUD = "cloud";
    private static final String DEFAULT = "default";
 
    private static final String ARCHAIUS_DEPLOYMENT_DATACENTER = "archaius.deployment.datacenter";
 
    private static final String EUREKA_DATACENTER = "eureka.datacenter";  
 
  protected void initEurekaEnvironment() throws Exception {
        logger.info("Setting the eureka configuration..");
 
        String dataCenter = ConfigurationManager.getConfigInstance().getString(EUREKA_DATACENTER);
        if (dataCenter == null) {
            logger.info("Eureka data center value eureka.datacenter is not set, defaulting to default");
            ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_DATACENTER, DEFAULT);
        } else {
            ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_DATACENTER, dataCenter);
        }
        String environment = ConfigurationManager.getConfigInstance().getString(EUREKA_ENVIRONMENT);
        if (environment == null) {
            ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_ENVIRONMENT, TEST);
            logger.info("Eureka environment value eureka.environment is not set, defaulting to test");
        }
    }

在ConfigurationManager.getConfigInstance()中,其实就是初始化ConfigurationManager的实例

(1)创建一个ConcurrentCompositeConfiguration实例,代表了所谓的配置,包括了eureka需要的所有的配置。在初始化这个实例的时候,调用了clear()方法,fireEvent()发布了一个事件(EVENT_CLEAR),fireEvent()这个方法其实是父类的方法,牵扯比较复杂的另外一个项目(ConfigurationManager本身不是属于eureka的源码,是属于netflix config项目的源码)。

/**
     * Creates an empty CompositeConfiguration object which can then
     * be added some other Configuration files
     */
    public ConcurrentCompositeConfiguration()
    {
        clear();
    }
 
    @Override
    public final void clear()
    {
        fireEvent(EVENT_CLEAR, null, null, true);
        configList.clear();
        namedConfigurations.clear();
        // recreate the in memory configuration
        containerConfiguration = new ConcurrentMapConfiguration();
        containerConfiguration.setThrowExceptionOnMissing(isThrowExceptionOnMissing());
        containerConfiguration.setListDelimiter(getListDelimiter());
        containerConfiguration.setDelimiterParsingDisabled(isDelimiterParsingDisabled());
        containerConfiguration.addConfigurationListener(eventPropagater);
        configList.add(containerConfiguration);
        
        overrideProperties = new ConcurrentMapConfiguration();
        overrideProperties.setThrowExceptionOnMissing(isThrowExceptionOnMissing());
        overrideProperties.setListDelimiter(getListDelimiter());
        overrideProperties.setDelimiterParsingDisabled(isDelimiterParsingDisabled());
        overrideProperties.addConfigurationListener(eventPropagater);
        
        fireEvent(EVENT_CLEAR, null, null, false);
        containerConfigurationChanged = false;
        invalidate();
    }

(2)就是往上面的那个ConcurrentCompositeConfiguration实例加入了一堆别的config,然后搞完了以后,就直接返回了这个实例,就是作为所谓的那个配置的单例

(3)初始化数据中心的配置,如果没有配置的话,就是DEFAULT data center

(4)初始化eurueka运行的环境,如果你没有配置的话,默认就给你设置为test环境

(5)initEurekaEnvironment的初始化环境的逻辑

初始化eureka的上下文

/**
     * init hook for server context. Override for custom logic.
     */
    protected void initEurekaServerContext() throws Exception {
        //加载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,对应的其实是一个eureka-client。
        ApplicationInfoManager applicationInfoManager = null;
 
        //初始化eureka-server内部的一个eureka-client,用来和其他eureka-server节点用来注册通信的
        if (eurekaClient == null) {
            //CommonConstants. 用来获取client信息
            EurekaInstanceConfig instanceConfig = isCloud(ConfigurationManager.getDeploymentContext())
                    ? new CloudInstanceConfig()
                    : new MyDataCenterInstanceConfig();
            
            applicationInfoManager = new ApplicationInfoManager(
                    instanceConfig, new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get());
            
            EurekaClientConfig eurekaClientConfig = new DefaultEurekaClientConfig();
            eurekaClient = new DiscoveryClient(applicationInfoManager, eurekaClientConfig);
        } else {
            applicationInfoManager = eurekaClient.getApplicationInfoManager();
        }
 
        //处理注册的相关事情
        PeerAwareInstanceRegistry registry;
        if (isAws(applicationInfoManager.getInfo())) {
            registry = new AwsInstanceRegistry(
                    eurekaServerConfig,
                    eurekaClient.getEurekaClientConfig(),
                    serverCodecs,
                    eurekaClient
            );
            awsBinder = new AwsBinderDelegate(eurekaServerConfig, eurekaClient.getEurekaClientConfig(), registry, applicationInfoManager);
            awsBinder.start();
        } else {
            registry = new PeerAwareInstanceRegistryImpl(
                    eurekaServerConfig,
                    eurekaClient.getEurekaClientConfig(),
                    serverCodecs,
                    eurekaClient
            );
        }
 
        //处理peer节点
        PeerEurekaNodes peerEurekaNodes = getPeerEurekaNodes(
                registry,
                eurekaServerConfig,
                eurekaClient.getEurekaClientConfig(),
                serverCodecs,
                applicationInfoManager
        );
 
        //完成eureka-server上下文的构建以及初始化过程
        serverContext = new DefaultEurekaServerContext(
                eurekaServerConfig,
                serverCodecs,
                registry,
                peerEurekaNodes,
                applicationInfoManager
        );
 
        EurekaServerContextHolder.initialize(serverContext);
 
        serverContext.initialize();
        logger.info("Initialized server context");
 
        // 第六步,处理一点善后的事情,从相邻的eureka节点拷贝注册信息
        int registryCount = registry.syncUp();
        //这个方法就是打开注册表,可以接收请求
        registry.openForTraffic(applicationInfoManager, registryCount);
 
        // 注册所有的监控
        EurekaMonitors.registerAllStats();
    }

配置文件读取

public DefaultEurekaServerConfig() {
        init();
    }
 
    private void init() {
        String env = ConfigurationManager.getConfigInstance().getString(
                EUREKA_ENVIRONMENT, TEST);
        ConfigurationManager.getConfigInstance().setProperty(
                ARCHAIUS_DEPLOYMENT_ENVIRONMENT, env);
 
        String eurekaPropsFile = EUREKA_PROPS_FILE.get();
        try {
            // ConfigurationManager
            // .loadPropertiesFromResources(eurekaPropsFile);
            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的过程

(1)创建了一个DefaultEurekaServerConfig对象

(2)创建DefaultEurekaServerConfig对象的时候,在里面会有一个init方法

(3)先是将eureka-server.properties中的配置加载到了一个Properties对象中,然后将Properties对象中的配置放到ConfigurationManager中去,此时ConfigurationManager中去就有了所有的配置了

(4)然后DefaultEurekaServerConfig提供的获取配置项的各个方法,都是通过硬编码的配置项名称,从DynamicPropertyFactory中获取配置项的值,DynamicPropertyFactory是从ConfigurationManager那儿来的,所以也包含了所有配置项的值

(5)在获取配置项的时候,如果没有配置,那么就会有默认的值,全部属性都是有默认值的

创建 Eureka-Server 请求和响应编解码器

logger.info("Initializing the eureka client...");
logger.info(eurekaServerConfig.getJsonCodecName());
ServerCodecs serverCodecs = new DefaultServerCodecs(eurekaServerConfig);

创建Eureka-Client

//初始化一个ApplicationInfoManager,对应的其实是一个eureka-client。        ApplicationInfoManager applicationInfoManager = null;        //初始化eureka-server内部的一个eureka-client,用来和其他eureka-server节点用来注册通信的        if (eurekaClient == null) {            //CommonConstants. 用来获取client信息            EurekaInstanceConfig instanceConfig = isCloud(ConfigurationManager.getDeploymentContext())                    ? new CloudInstanceConfig()                    : new MyDataCenterInstanceConfig();                        applicationInfoManager = new ApplicationInfoManager(                    instanceConfig, new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get());                        EurekaClientConfig eurekaClientConfig = new DefaultEurekaClientConfig();            eurekaClient = new DiscoveryClient(applicationInfoManager, eurekaClientConfig);        } else {            applicationInfoManager = eurekaClient.getApplicationInfoManager();        }

在new MyDataCenterInstanceConfig()这个无参构造中,最终会去读取eureka-client.properties的配置,去提供一些默认值。

因为eureka-server本身也是一个eureka-client,因为当组成集群的时候,它自己也要向别的服务端进行注册

//初始化一个ApplicationInfoManager,对应的其实是一个eureka-client。
        ApplicationInfoManager applicationInfoManager = null;
 
        //初始化eureka-server内部的一个eureka-client,用来和其他eureka-server节点用来注册通信的
        if (eurekaClient == null) {
            //CommonConstants. 用来获取client信息
            EurekaInstanceConfig instanceConfig = isCloud(ConfigurationManager.getDeploymentContext())
                    ? new CloudInstanceConfig()
                    : new MyDataCenterInstanceConfig();
            
            applicationInfoManager = new ApplicationInfoManager(
                    instanceConfig, new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get());
            
            EurekaClientConfig eurekaClientConfig = new DefaultEurekaClientConfig();
            eurekaClient = new DiscoveryClient(applicationInfoManager, eurekaClientConfig);
        } else {
            applicationInfoManager = eurekaClient.getApplicationInfoManager();
        }

初始化 EurekaServerContextHolder

EurekaServerContextHolder.initialize(serverContext);

初始化 Eureka-Server 上下文

@PostConstruct
    @Override
    public void initialize() {
        logger.info("Initializing ...");
        //启动 Eureka-Server 集群节点集合(复制)
        peerEurekaNodes.start();
        try {
            // 初始化 应用实例信息的注册表
            registry.init(peerEurekaNodes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        logger.info("Initialized");
    }

从其他 Eureka-Server 拉取注册信息

// 第六步,处理一点善后的事情,从相邻的eureka节点拷贝注册信息
        int registryCount = registry.syncUp();
        //这个方法就是打开注册表,可以接收请求
        registry.openForTraffic(applicationInfoManager, registryCount);

注册监控

EurekaMonitors.registerAllStats();

到此这篇关于Spring中的EurekaServer启动详解的文章就介绍到这了,更多相关EurekaServer启动内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 浅谈Java日志框架slf4j作用及其实现原理

    浅谈Java日志框架slf4j作用及其实现原理

    日志记录是应用程序运行中必不可少的一部分。这篇文章主要介绍了浅谈Java日志框架slf4j作用及其实现原理,SLF4J是一个日志框架抽象层,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-03-03
  • maven一键删除仓库无用文件的实现

    maven一键删除仓库无用文件的实现

    大家都知道我们在使用Maven的时候,会下载一堆无用非jar文件,本文主要介绍了maven一键删除仓库无用文件的实现,具有一定的参考价值,感兴趣的可以了解一下
    2023-11-11
  • java web实现用户权限管理

    java web实现用户权限管理

    这篇文章主要介绍了java web实现用户权限管理,设计并实现一套简单的权限管理功能,感兴趣的小伙伴们可以参考一下
    2015-11-11
  • Java精确抽取网页发布时间

    Java精确抽取网页发布时间

    这篇文章主要为大家详细介绍了Java精确抽取网页发布时间的相关资料,尽量做到精确无误,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • SpringBoot利用filter实现xss防御功能

    SpringBoot利用filter实现xss防御功能

    Cross-Site Scripting(跨站脚本攻击)简称 XSS,是一种代码注入攻击,攻击者通过在目标网站上注入恶意脚本,使之在用户的浏览器上运行,利用这些恶意脚本,攻击者可获取用户的敏感信息,本文给大家介绍了SpringBoot利用filter实现xss防御功能,需要的朋友可以参考下
    2024-09-09
  • Java使用Apache POI库读取Excel表格文档的示例

    Java使用Apache POI库读取Excel表格文档的示例

    POI库是Apache提供的用于在Windows下读写各类微软Office文档的Java库,这里我们就来看一下Java使用Apache POI库读取Excel表格文档的示例:
    2016-06-06
  • Springboot整合Spring Cloud Kubernetes读取ConfigMap支持自动刷新配置的教程

    Springboot整合Spring Cloud Kubernetes读取ConfigMap支持自动刷新配置的教程

    这篇文章主要介绍了Springboot整合Spring Cloud Kubernetes读取ConfigMap支持自动刷新配置,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • JAVA正则表达式提取key-value类型字符值代码实例

    JAVA正则表达式提取key-value类型字符值代码实例

    这篇文章主要给大家介绍了关于JAVA正则表达式提取key-value类型字符值的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-10-10
  • Java缓存池代码实例详解

    Java缓存池代码实例详解

    本篇文章主要介绍了Java实现简单的缓存方法实例,需要的朋友可以参考下
    2017-04-04
  • 解决redisTemplate向redis中插入String类型数据时出现乱码问题

    解决redisTemplate向redis中插入String类型数据时出现乱码问题

    这篇文章主要介绍了解决redisTemplate向redis中插入String类型数据时出现乱码问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12

最新评论