Dil*_*ral 6 java spring spring-boot
我想在初始化bean之前从类路径或外部位置的属性文件中加载属性。这些属性也是Bean初始化的一部分。我无法从Spring的标准application.properties或其自定义项自动装配属性,因为同一属性文件必须可由多个可部署对象访问。
我知道Spring应用程序事件;实际上,在初始化Spring Context之后,我已经钩住 ContextRefreshedEvent来执行一些任务(在此阶段还初始化了Bean)。
对于我的问题声明,从Spring Docs的描述来看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");
}
}
Run Code Online (Sandbox Code Playgroud)
正如M.Deinum在评论中所建议的那样,我尝试添加如下应用程序上下文初始化程序。它似乎也不起作用。
public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(App.class)
.initializers(applicationContext -> {
System.out.println("INSIDE CUSTOM APPLICATION INITIALIZER");
})
.run(args);
}
Run Code Online (Sandbox Code Playgroud)
虽然我的问题陈述是关于加载属性的,但我的问题/好奇心实际上是关于在将类初始化为bean并放入Spring IoC容器之前如何运行一些代码。现在,这些Bean在初始化期间需要一些属性值,由于以下原因,我不能/不想自动装配它们:
如评论和答案中所述,使用Spring Boot的外部化配置和配置文件可以完成相同的操作。但是,我需要分别维护应用程序属性和与域相关的属性。基本域属性应至少具有100个属性,并且该数目随时间增长。应用程序属性和与域相关的属性都具有用于不同环境(开发,SIT,UAT,生产)的属性文件。属性文件会覆盖一个或多个基本属性。这是8个属性文件。现在,需要将同一应用程序部署到多个地区。这使其成为8 * n
属性文件n
是地理区域的数量。我希望所有属性文件都存储在一个公共模块中,以便可以由不同的可部署对象访问。环境和地理位置在运行时称为系统属性。
尽管可以通过使用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) {
...
}
}
Run Code Online (Sandbox Code Playgroud)
@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;
}
}
Run Code Online (Sandbox Code Playgroud)
从文档,好像ApplicationEvents
和ApplicationInitializers
适合我的需要,但我不能,让他们工作,为我的问题发言。
聚会有点晚,但希望我可以为您更新的问题陈述提供解决方案。
这将关注如何在类初始化为bean并放入Spring IoC容器之前运行一些代码的问题
我注意到的一个问题是您正在通过 @EventListener 注释定义应用程序事件。
这些仅在所有 bean 启动后调用,因为这些注释由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());
}
Run Code Online (Sandbox Code Playgroud)
注意缺少的@Component。在其中一些事件之后,甚至可以发生 bean 实例化。如果你使用@Component,那么你会得到以下日志
I am a DataSourceSchemaCreatedEvent
I am a ContextRefreshedEvent
I am a ServletWebServerInitializedEvent
I am a ApplicationStartedEvent
I am a ApplicationReadyEvent
Run Code Online (Sandbox Code Playgroud)
仍然比注释性侦听器更好,更即时,但仍然不会接收初始化事件。为此,您需要做的是按照此处找到的说明进行操作
总结一下,
结果:-
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
Run Code Online (Sandbox Code Playgroud)
特别是,ApplicationContextInitializedEvent 应该允许您执行任何您需要的每个实例化任务。
小智 1
我觉得您的主要问题是您需要分别维护应用程序属性和域相关属性。 从 spring 的角度来看,这并不重要,因为所有属性文件在加载到内存中后都会合并在一起。例如,您有两个包含一些属性的文件:
application.related=property1 # this is in application.properties
Run Code Online (Sandbox Code Playgroud)
domain.related=property2 # this is in domain-specific.properties
Run Code Online (Sandbox Code Playgroud)
当它们被加载之后,你会得到一个包含所有属性的大东西,如果我没记错的话,它是一个org.springframework.core.env.ConfigurableEnvironment
实例。
然后你需要做的就是使用类似的东西注入你需要的属性@Value
。
对于主要问题,要将属性分离到不同的文件中,您只需要指定 spring 的spring.config.name
属性(通过环境变量、命令行或以编程方式)。按照上面的例子,应该是spring.config.name=application,domain-specific
。
此外,如果您确实想要进行编程控制,您可以添加一个EnvironmentPostProcessor
公开ConfigurableEnvironment
实例的自定义。
归档时间: |
|
查看次数: |
464 次 |
最近记录: |