spring-boot - ApplicationContextInitializer 由 Spring Cloud Bootstrap 上下文和 Spring Boot 加载两次
问题描述
在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。
问题:我们如何才能可靠地只加载一次初始化程序?
如果ApplicationContextInitializer
s 是幂等的,它可能应该出现在接口的 Javadocs 中。
在最坏的情况下,我们如何安全地区分 Spring Cloud boostrap 上下文和 Spring Boot 上下文?
解决方案
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.name
或bootstrap
作为后备的值。然后将其设置为ContextIdApplicationContextInitializer
. 您还可以使用它来确定您的初始化程序在哪个上下文中运行。
推荐阅读
- python-3.x - 多个列表的列表理解 Python 2.7/3
- php - 如何在opencart中批量手动将产品分配到类别
- python-3.x - 翻译来自多个数据框列的数据以创建句子
- c - * 根据其使用的上下文有不同的含义吗?
- vue.js - 多选仅呈现前两项
- javascript - 如何使用js自动控制浏览器
- cmake - 如何在 CMake 中显示 Foo::Bar 的内容?
- asp.net-mvc - 如何正确构建一组 mvc 视图以最小化许多模型的视图数量?
- python-3.x - 在 Celery 和 Django 中没有这样的带有 RabbitMQ 的传输 RPC
- reactjs - 我如何通过身份验证对路由做出明智的反应?