应用程序启动后在Spring上下文中初始化bean的最佳方法是什么?

Tho*_* Vo 15 java spring

我需要在应用程序启动后在Spring上下文中初始化bean; 目前,我使用注释@Configuration在类中初始化bean,如下所示:

@Configuration
public class AppConfig {
   @Inject
   @Bean
   public BeanA init(param1, param2, etc...) {
       --- Code to construct bean A ---
   }

   @Inject
   @Bean
   public BeanB init(param1, param2, etc...) {
       --- Code to construct bean B ---
   }
}
Run Code Online (Sandbox Code Playgroud)

但是我需要在应用程序启动后初始化一些bean,所以我的方法是创建一个类,在Spring中监听ApplicationReadyEvent事件,并将代码初始化为该类中的bean.

@Configuration
class ApplicationStartingListener implements ApplicationListener<ApplicationReadyEvent>{
    ---- Code to init bean here ----

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        --- If I put init bean code in here, is it correct? ----
    }
}
Run Code Online (Sandbox Code Playgroud)

这是最好的方法吗?还是有其他更好的解决方案?

Dan*_* C. 42

我将枚举其他方法以初始化bean,我将方法分为标准方法和Spring Boot方法.

标准方法

  1. @PostConstruct:它只是一个在创建bean后触发方法的注释,它不允许输入参数.
  2. @Bean(init-method="somInitMehotd"):这种方法与Spring bean生命周期完全相关,并且在创建bean之后调用它,如果你使用另一个带@PostConstruct注释的方法,那么@PostConstruct将首先调用它.此方法不允许输入参数.
  3. ApplicationListener:此界面允许侦听与上下文生命周期相关的标准事件,也可以侦听自定义事件.例如:创建一个类MyAppListenerApplicationListener<ContextRefreshedEvent>在这种情况下实现MyAppListener将实现一个onApplicationEvent接收a 的方法ContextRefreshedEvent

春靴方法

  1. 该参赛者:有两个非常有用的接口CommandLineRunner,并ApplicationRunner在创建后的ApplicationContext他们都可以注入豆作为输入参数他们都将运行.

  2. Spring引导侦听器:Spring Application提供了一些额外的事件,而不是来自Application Context的标准事件.其中一个事件是ApplicationReadyEvent,当应用程序准备好接收请求时它就会触发.为了监听这些事件,只需将ApplicationListenerusing ApplicationReadyEvent用作泛型.

这是一个例子:

MyBean类有不同的方法,将为上面列出的每种方法调用,每个方法都会调用一个print方法,并且该方法有一个Thread.sleep,以验证每个监听器的调用顺序.

import javax.annotation.PostConstruct;
public class MyBean {

    private String myVar="";

    public MyBean(){

    }

    @PostConstruct
    public void postConstructInit(){

        this.myVar="Post init called";
        print();

    }

    public void beanInit(){

        this.myVar="Bean init called";
        print();
    }

    public void contextInit(){

        this.myVar="Context init called";
        print();
    }

    public void runnerInit(){

        this.myVar="Runner init called";
        print();
    }

    public void bootListenerInit(){

        this.myVar="Boot init called";
        print();
    }



    public void print(){
        System.out.println(this.myVar);
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是ContextRefreshListener将听取ContextRefreshedEvent并处理它的类.

public class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        contextRefreshedEvent.getApplicationContext().getBean(MyBean.class).contextInit();

    }
}
Run Code Online (Sandbox Code Playgroud)

它是BootListener将接收ApplicationReadyEvent的是来自Spring应用程序.

public class MyBootListener implements ApplicationListener<ApplicationReadyEvent> {
    @Override
    public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
        applicationReadyEvent.getApplicationContext().getBean(MyBean.class).bootListenerInit();
    }
}
Run Code Online (Sandbox Code Playgroud)

最后是Spring Boot Application

@SpringBootApplication
public class StackoverflowBootApplication {


    public static void main(String[] args) {

        SpringApplication.run(StackoverflowBootApplication.class, args);

    }

    @Bean(name = "myBean", initMethod = "beanInit")
    public MyBean getMyBean(){
        return new MyBean();
    }


    @Bean
    public ContextRefreshListener getContextRefreshedListener(){return new ContextRefreshListener();}


    @Bean
    public MyBootListener getBootListener(){return new MyBootListener();}

    @Bean
    public CommandLineRunner getRunner(ApplicationContext ctx){
        return (args) -> {
            ctx.getBean(MyBean.class).runnerInit();
        };
    }

}
Run Code Online (Sandbox Code Playgroud)

输出是:

Post init called
Bean init called
Context init called
Runner init called 
Boot init called
Run Code Online (Sandbox Code Playgroud)

Post init called 输出来自

@PostConstruct
public void init(){
    this.initByPostconstruct="Post init called";
Run Code Online (Sandbox Code Playgroud)

Bean init called来自initMethod价值

@Bean(name = "myBean", initMethod = "beanInit")
public MyBean getMyBean(){
    return new MyBean();
}
}
Run Code Online (Sandbox Code Playgroud)

Context init called 来自 ContextRefreshedEvent

public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
    contextRefreshedEvent.getApplicationContext().getBean(MyBean.class).contextInit();

}
Run Code Online (Sandbox Code Playgroud)

Runner init called 来自 CommandLineRunner

@Bean
public CommandLineRunner getRunner(ApplicationContext ctx){
    return (args) -> {
        ctx.getBean(MyBean.class).runnerInit();
    };
}
Run Code Online (Sandbox Code Playgroud)

Boot init called 来自 ApplicationReadyEvent

   public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
        applicationReadyEvent.getApplicationContext().getBean(MyBean.class).bootListenerInit();
    }
Run Code Online (Sandbox Code Playgroud)

所有列出的场景都是由Spring我触发的,我没有直接调用任何事件,所有这些事件都被调用了Spring Framework.