【问题标题】:ApplicationContextInitializer loaded twice by Spring Cloud Bootstrap context & Spring BootApplicationContextInitializer 由 Spring Cloud Bootstrap 上下文和 Spring Boot 加载两次
【发布时间】:2019-01-02 12:46:22
【问题描述】:

当在spring.factories 文件中声明初始化器以创建 Spring Boot 启动器时,我们意识到这些初始化器被加载了两次:

  • 曾经由 Spring Cloud Boostrap 上下文提供
  • Spring Boot 上下文中一次

在我们的例子中,我们在 docker 容器中启动数据库,所以我们不想做两次。

根据这个问题,这是 Spring Cloud 的预期行为:https://github.com/spring-cloud/spring-cloud-config/issues/1151

当询问如何将 boostrap 上下文与“常规”应用程序上下文区分开来时,给出的答案是

检查上下文的 ID。

运行示例应用程序后,ConfigurableApplicationContext.getId() 默认返回:

  • application 用于 Spring Cloud Bootstrap 上下文
  • application-1 用于 Spring Boot 上下文

我们的一些用户没有定义spring.application.name,其他用户根本不使用 Spring Cloud。

问题:我们如何才能可靠地只加载一次初始化程序?

如果ApplicationContextInitializers 是幂等的,它可能应该出现在接口的 Javadocs 中。

在最坏的情况下,我们如何安全地区分 Spring Cloud boostrap 上下文和 Spring Boot 上下文?

【问题讨论】:

    标签: spring-boot spring-cloud


    【解决方案1】:

    我们在尝试将属性源注入 EnvironmentPostProcessor here 时遇到了同样的问题。解决方案非常简单,因为您只需要一个静态标志:

    public class YourInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>
    {
        private static boolean initialized = false;
    
        @Override
        public void initialize(ConfigurableApplicationContext applicationContext)
        {
            if (!initialized) {
                //do your things here
                initialized = true;
            }
        }
    }
    

    引导应用程序上下文将始终在常规 Spring Boot 应用程序上下文之前运行,因此您也可以使用它在正确的位置运行代码。

    最后,引导上下文在BootstrapApplicationListener 中实例化。从那里,您可以看到spring.application.name 属性设置为spring.cloud.bootstrap.namebootstrap 的值作为后备。然后将其设置为ContextIdApplicationContextInitializer 中应用程序上下文的 id。您还可以使用它来确定您的初始化程序在哪个上下文中运行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-18
      • 2019-06-20
      • 1970-01-01
      • 2012-09-08
      • 2016-02-01
      • 1970-01-01
      • 2013-11-22
      • 2019-02-15
      相关资源
      最近更新 更多