对于这个Spring Boot启动变体,在尽早的时间构建特定的bean,有什么想法吗?

huangapple go评论68阅读模式
英文:

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&#39;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 = &quot;/admin&quot;;
    //...

    public static boolean EMAIL_CONFIRMATION;
    //...

    public ApplicationProperties(@Autowired Environment env) {
        this.init(env);
    }

    private void init(Environment env) {
        EMAIL_CONFIRMATION = env.getProperty(&quot;application.security.registration.email-confirmation&quot;, 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&lt;ApplicationEnvironmentPreparedEvent&gt;
{
    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event)
    {
     ApplicationProperties.EMAIL_CONFIRMATION = event.getEnvironment().getProperty(&quot;application.security.registration.email-confirmation&quot;, 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();
	} 
}

huangapple
  • 本文由 发表于 2023年3月3日 22:12:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/75628163.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定