我想在初始化bean之前,从类路径中的属性文件或外部位置加载属性。这些属性也是Bean初始化的一部分。我无法自动从Spring的标准application.properties或其自定义中提取属性,因为同一个属性文件必须可由多个部署程序访问。
我知道Spring应用程序事件;事实上,我已经在挂起ContextRefleShedEvent,以便在Spring上下文初始化之后执行一些任务(bean也在这个阶段初始化)。
对于我的问题陈述,从Spring文档的描述来看,ApplicationEnvironmentPrepareDevent
看起来很有希望,但是钩子不起作用。
@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);
}
虽然我的问题陈述是关于加载属性的,但我的问题/好奇实际上是关于如何在类初始化为bean并放入Spring IoC容器之前运行一些代码。现在,这些bean在初始化期间需要一些属性值,我不能/不想自动连接它们,原因如下:
虽然这些可以通过使用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;
}
}
从文档来看,ApplicationEvents
和ApplicationInitializers
似乎符合我的需要,但我无法使它们适用于我的问题声明。
派对有点晚了,但希望我能提供一个解决你更新的问题声明。
这将关注如何在类初始化为bean并放入Spring IoC容器之前运行一些代码的问题
我注意到的一个问题是,您是通过@EventListener注释定义应用程序事件的。
只有在启动所有bean时才调用这些注释,因为这些注释是由EventListenerMethodProcessor处理的,而EventListenerMethodProcessor仅在上下文就绪时才触发(请参见SmartInitializingSingleton#AfterSingletonSinStantiated)
因此,在上下文准备好之前发生的一些事件。例如ContextStartedEvent,ApplicationContextInitializedEvent将无法到达侦听器。
相反,您可以做的是直接为这些事件扩展接口。
@Slf4j
public class AllEvent implements ApplicationListener<ApplicationEvent> {
@Override
public void onApplicationEvent(final ApplicationEvent event) {
log.info("I am a {}", event.getClass().getSimpleName());
}
注意缺少@组件。甚至bean实例化也可以在其中一些事件之后发生。如果您使用@component,那么您将得到以下日志
I am a DataSourceSchemaCreatedEvent
I am a ContextRefreshedEvent
I am a ServletWebServerInitializedEvent
I am a ApplicationStartedEvent
I am a ApplicationReadyEvent
仍然比注释侦听器更好、更即时,但仍然不会接收初始化事件。为此,您需要做的是按照这里的说明操作
总而言之,
结果:-
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应该允许您执行所需的任何每实例化任务。
问题内容: 我的页面上有一个表单。该表单包含一个文本框和一个提交按钮。 提交表单后,通过单击按钮或在文本框中按Enter,我要进行查找(在这种情况下,使用Bing Maps对邮政编码进行地理编码),然后像往常一样将表单提交到服务器。 我当前的方法是将提交事件的处理程序添加到一个表单中,然后在完成后调用Submit(),但是我无法使它正常工作,并且无法调试问题: 问题答案: 是你的朋友在这里。在完成
我试图理解@bolov对删除默认构造函数问题的第一个公认答案。对象仍然可以创建......有时[1] 似乎我发现了一个错误,所以它搞乱了整个解释。 @bolov解释了为什么这段代码能够在c 11中成功编译: 场景A 以及为什么这段代码无法在c 11中编译: 场景C 他说,重点是第一个foo是聚合,第二个foo不是聚合。 然后他给出了cppreference的摘录: T类型对象的列表初始化的影响是:
我想为测试目的创建一个选项列表。起初,我是这样做的: 然后,我重构代码如下: 有更好的方法吗?
我找不到任何关于这个具体案例的具体SO帖子,所以我想问一下我认为是/否的问题。 以下是JLS§12.4.2(Java SE 8),清单6-7: 我的问题是:这是否意味着子类的final static变量在超类的静态初始化之前初始化(假设final static作为其声明的一部分初始化)?
问题内容: 我想创建用于测试目的的选项列表。首先,我这样做: 然后,我将代码重构如下: 有一个更好的方法吗? 问题答案: 实际上,初始化的“最佳”方法可能ArrayList是你编写的方法,因为它无需以List任何方式创建新方法: 问题是引用该实例需要大量输入。 还有其他选择,例如使用实例初始化程序(也称为“双括号初始化”)创建匿名内部类: 但是,我不太喜欢这种方法,因为最终得到的是ArrayLis
我在想Spring中bean的懒惰初始化。对我来说,这里的“懒惰”是否意味着当一个bean被引用时会被创建并不十分清楚。 我认为Spring中的延迟初始化支持是不同的。我认为这是一个基于“方法调用”的惰性创建。我的意思是,每当对该方法调用任何方法时,都会创建该方法。 我认为这可以通过创建特定bean的代理实例并对任何方法调用进行初始化来轻松解决。 我是否遗漏了一些东西?为什么没有实施?这个概念有什