gpt4 book ai didi

java - Spring Boot 2 - 在初始化 bean 之前做一些事情

转载 作者:行者123 更新时间:2023-12-01 10:22:06 24 4
gpt4 key购买 nike

问题陈述

我想在初始化 bean 之前从类路径中或外部位置的属性文件中加载属性。这些属性也是 Bean 初始化的一部分。我无法从 Spring 的标准 application.properties 或其自定义中 Autowiring 属性,因为同一个属性文件必须可由多个可部署对象访问。

我试过的

我知道 Spring Application Events ;其实我已经上钩了
ContextRefreshedEvent 在 Spring Context 初始化后执行一些任务(在这个阶段也初始化了 Beans)。

对于我的问题陈述,来自 Spring Docs ApplicationEnvironmentPreparedEvent 的描述看起来很有希望,但钩子(Hook)不起作用。


@SpringBootApplication
public class App {

public static void main(String[] args) throws IOException {
SpringApplication.run(App.class, args);
}


@EventListener
public void onStartUp(ContextRefreshedEvent event) {
System.out.println("ContextRefreshedEvent"); // WORKS
}

@EventListener
public void onShutDown(ContextClosedEvent event) {
System.out.println("ContextClosedEvent"); // WORKS
}

@EventListener
public void onEvent6(ApplicationStartedEvent event) {
System.out.println("ApplicationStartedEvent"); // WORKS BUT AFTER ContextRefreshedEvent
}


@EventListener
public void onEvent3(ApplicationReadyEvent event) {
System.out.println("ApplicationReadyEvent"); // WORKS WORKS BUT AFTER ContextRefreshedEvent
}


public void onEvent1(ApplicationEnvironmentPreparedEvent event) {
System.out.println("ApplicationEnvironmentPreparedEvent"); // DOESN'T WORK
}


@EventListener
public void onEvent2(ApplicationContextInitializedEvent event) {
System.out.println("ApplicationContextInitializedEvent"); // DOESN'T WORK
}


@EventListener
public void onEvent4(ApplicationContextInitializedEvent event) {
System.out.println("ApplicationContextInitializedEvent");
}

@EventListener
public void onEvent5(ContextStartedEvent event) {
System.out.println("ContextStartedEvent");
}

}


更新

正如 M.Deinum 在评论中所建议的那样,我尝试添加一个应用程序上下文初始化程序,如下所示。它似乎也不起作用。
    public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(App.class)
.initializers(applicationContext -> {
System.out.println("INSIDE CUSTOM APPLICATION INITIALIZER");
})
.run(args);

}

更新#2

虽然我的问题陈述是关于加载属性,但我的问题/好奇实际上是关于 如何在类被初始化为 bean 并放入 Spring IoC 容器之前运行一些代码 .现在,这些 bean 在初始化期间需要一些属性值,我不能/不想 Autowiring 它们,原因如下:

正如评论和答案中所述,同样可以使用 Spring Boot 的外部化配置和配置文件来完成。但是,我需要分别维护应用程序属性和与域相关的属性。一个基本域属性应该至少有 100 个属性,并且数量会随着时间的推移而增长。应用程序属性和与域相关的属性都有一个用于不同环境(开发、SIT、UAT、生产)的属性文件。属性文件覆盖一个或多个基本属性。那是 8 个属性文件。现在,需要将同一个应用程序部署到多个地区。这使它成为 8 * n属性文件,其中 n是地理的数量。我希望所有属性文件都存储在一个公共(public)模块中,以便不同的部署可以访问它们。环境和地理在运行时将被称为系统属性。

虽然这些可以通过使用 Spring 配置文件和优先顺序来实现,但我希望对其进行编程控制( 我还将维护自己的属性存储库 )。例如。我会编写一个名为 MyPropUtil 的便利实用程序并像这样访问它们:
public class MyPropUtil {
private static Map<String, Properties> repository;

public static initialize(..) {
....
}

public static String getDomainProperty(String key) {
return repository.get("domain").getProperty(key);
}

public static String getAppProperty(String key) {
return repository.get("app").getProperty(key);
}

public static String getAndAddBasePathToAppPropertyValue(String key) {
...
}

}

@Configuration
public class MyComponent {

@Bean
public SomeClass getSomeClassBean() {
SomeClass obj = new SomeClass();
obj.someProp1(MyPropUtil.getDomainProperty('domainkey1'));
obj.someProp2(MyPropUtil.getAppProperty('appkey1'));
// For some properties
obj.someProp2(MyPropUtil.getAndAddBasePathToAppPropertyValue('some.relative.path.value'));
....
return obj;
}

}

从文档看来, ApplicationEventsApplicationInitializers符合我的需要,但我无法让他们为我的问题陈述工作。

最佳答案

聚会迟到了,但希望我能为您更新的问题陈述提供解决方案。

这将集中在 的问题上。如何在类被初始化为 bean 并放入 Spring IoC 容器之前运行一些代码

我注意到的一个问题是您正在通过 @EventListener 注释定义应用程序事件。

由于这些注解由 EventListenerMethodProcessor 处理,因此仅在启动所有 bean 后才调用它们。仅在上下文准备就绪时触发(请参阅 SmartInitializingSingleton#afterSingletonsInstantiated)

因此,在上下文准备好之前发生的一些事件。例如ContextStartedEvent、ApplicationContextInitializedEvent 不会出现在您的监听器中。

相反,您可以做的是直接扩展这些事件的接口(interface)。

@Slf4j
public class AllEvent implements ApplicationListener<ApplicationEvent> {

@Override
public void onApplicationEvent(final ApplicationEvent event) {
log.info("I am a {}", event.getClass().getSimpleName());
}

注意缺少的@Component。甚至可以发生 bean 实例化 之后 其中一些事件。如果您使用@Component,那么您将获得以下日志
I am a DataSourceSchemaCreatedEvent
I am a ContextRefreshedEvent
I am a ServletWebServerInitializedEvent
I am a ApplicationStartedEvent
I am a ApplicationReadyEvent

仍然比注释性监听器更好、更即时,但仍不会接收到初始化事件。为此,您需要按照 here 中的说明进行操作。

总结一下,
  • 创建目录资源/META-INF
  • 创建文件 spring.factories
  • org.springframework.context.ApplicationListener=full.path.to.my.class.AllEvent

  • 结果:-
    I am a ApplicationContextInitializedEvent
    I am a ApplicationPreparedEvent
    I am a DataSourceSchemaCreatedEvent
    I am a ContextRefreshedEvent
    I am a ServletWebServerInitializedEvent
    I am a ApplicationStartedEvent
    I am a ApplicationReadyEvent

    特别是,ApplicationContextInitializedEvent 应该允许您执行所需的任何实例化任务。

    关于java - Spring Boot 2 - 在初始化 bean 之前做一些事情,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58725479/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com