英文:
Any thoughts on this Spring Boot start variant to build specifical bean at earliest possible time?
问题
以下是您要翻译的内容:
"The challenge is to build a specifical bean at the earliest possible time. That bean is needed for the further initialization process. The classes that need this particular bean do not autowire it, but only access static fields directly.
In principle, it would be possible to demand a dependency with @Dependson
, but I don't want to add this annotation to all relevant classes. Unfortunately, Spring Boot has no option to suggest a start order for beans.
I have now come up with the following working solution:
ConfigurableApplicationContext context = new SpringApplicationBuilder()
.parent(ApplicationProperties.class)
.child(Application.class)
.run(args);
This way ApplicationProperties.class
gets it's own context as parent and seems to being initialized before the main application context with Application.class
gets built up.
My question now is:
Is there anything against starting the application this way and can I be sure that the parent context is always built before the child context?
Many thanks for any information
Edit:
As requested, here the `ApplicationProperties.class`:
public class ApplicationProperties {
public static final String AUTH_LOGIN_SUCCESS_ADMIN_REDIRECT_URL = "/admin";
//...
public static boolean EMAIL_CONFIRMATION;
//...
public ApplicationProperties(@Autowired Environment env) {
this.init(env);
}
private void init(Environment env) {
EMAIL_CONFIRMATION = env.getProperty("application.security.registration.email-confirmation", Boolean.class, false);
//...
}
}"
<details>
<summary>英文:</summary>
The challenge is to build a specifical bean at the earliest possible time. That bean is needed for the further initialization process. The classes that need this particular bean do not autowire it, but only access static fields directly.
In principle, it would be possible to demand a dependency with `@Dependson`, but I don't want to add this annotation to all relevant classes. Unfortunately, Spring Boot has no option to suggest a start order for beans.
I have now come up with the following working solution:
```java
ConfigurableApplicationContext context = new SpringApplicationBuilder()
.parent(ApplicationProperties.class)
.child(Application.class)
.run(args);
This way ApplicationProperties.class
gets it's own context as parent and seems to being initialized before the main application context with Application.class
gets built up.
<h2>My question now is:</h2>
Is there anything against starting the application this way and can I be sure that the parent context is always built before the child context?
Many thanks for any information
<h2>Edit:</h2>
As requested, here the ApplicationProperties.class
:
public class ApplicationProperties {
public static final String AUTH_LOGIN_SUCCESS_ADMIN_REDIRECT_URL = "/admin";
//...
public static boolean EMAIL_CONFIRMATION;
//...
public ApplicationProperties(@Autowired Environment env) {
this.init(env);
}
private void init(Environment env) {
EMAIL_CONFIRMATION = env.getProperty("application.security.registration.email-confirmation", Boolean.class, false);
//...
}
}
It is a simple class for static properties, no annotation added and therefore no duplicate initialization when Application.class
does it's classpath scanning. The only reason this has to be intialized as bean is to get access to Spring Boot's Environment.
答案1
得分: 1
Spring Boot的启动分为多个步骤,在每个步骤开始时,通过发布机制发送应用程序事件。这允许开发人员在这些步骤中介入,但需要谨慎,正如文档中所描述的那样。
仅出于本问题的目的,OP只想在上下文和bean加载之前初始化某个类的某个静态字段,而在环境加载后执行。这可以安全地在步骤ApplicationEnvironmentPreparedEvent
中的一个已发布事件中发生。
如文档所述:
当上下文中要使用的环境已知但上下文尚未创建时,将发送ApplicationEnvironmentPreparedEvent。
因此,您可以创建您的监听器:
public class EnvPreparedListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent>
{
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event)
{
ApplicationProperties.EMAIL_CONFIRMATION = event.getEnvironment().getProperty("application.security.registration.email-confirmation", Boolean.class, false);
}
}
然后在您的@SpringBootApplication
类中注册此监听器:
@SpringBootApplication
public class ServiceLauncher {
public static void main(String[] args) {
new SpringApplicationBuilder(ServiceLauncher.class).listeners(new EnvPreparedListener()).run();
}
}
英文:
Spring Boot startup is done in steps and when each step starts there are application events sent via publishing mechanism. This allows the developer to intervene but with caution as described in docs during those steps.
Just for the purpose of this question, OP wants just to initialize some static field of some class before the context and beans are loaded, after the environment is loaded. This can safely happen with one of the published events in the step ApplicationEnvironmentPreparedEvent
As described in documentation
> An ApplicationEnvironmentPreparedEvent is sent when the Environment to
> be used in the context is known but before the context is created.
So you can create your listener
public class EnvPreparedListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent>
{
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event)
{
ApplicationProperties.EMAIL_CONFIRMATION = event.getEnvironment().getProperty("application.security.registration.email-confirmation", Boolean.class, false);
}
}
And then register this listener in your @SpringBootApplication
class with
@SpringBootApplication
public class ServiceLauncher {
public static void main(String[] args) {
new SpringApplicationBuilder(ServiceLauncher.class).listeners(new EnvPreparedListener()).run();
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论