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

2022-09-01 07:14:29

在我的应用程序启动后,我需要在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 ---
   }
}

但是有些bean我需要在应用程序启动后进行初始化,所以我的方法是在Spring中创建一个类,listen to 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? ----
    }
}

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


答案 1

为了初始化bean,我将枚举其他方法,我将该方法分组为标准方法和Spring Boot方法。

标准方法

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

弹簧靴方法

  1. 运行器:有两个非常有用的接口,它们都将在创建AdplicationContext后运行,它们都允许注入bean作为输入参数。CommandLineRunnerApplicationRunner

  2. Spring boot 侦听器:Spring 应用程序提供一些额外的事件,而不是来自应用程序上下文的标准事件。其中一个事件是,当应用程序准备好接收请求时,它将被触发。为了侦听此事件,只需将 using 实现为泛型。ApplicationReadyEventApplicationListenerApplicationReadyEvent

下面是一个示例:

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();
        }
    }
}

下面是将侦听并处理它的类。ContextRefreshListenerContextRefreshedEvent

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

    }
}

它将从春季应用程序接收。BootListenerApplicationReadyEvent

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

最后是弹簧启动应用程序

@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();
        };
    }

}

输出为:

Post init called
Bean init called
Context init called
Runner init called 
Boot init called

Post init called输出来自

@PostConstruct
public void init(){
    this.initByPostconstruct="Post init called";

Bean init called来自价值initMethod

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

Context init called来自ContextRefreshedEvent

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

}

Runner init called来自CommandLineRunner

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

Boot init called来自ApplicationReadyEvent

   public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
        applicationReadyEvent.getApplicationContext().getBean(MyBean.class).bootListenerInit();
    }

所有列出的场景都是由触发的,我没有直接调用任何事件,它们都是由.SpringSpring Framework


答案 2

推荐