启动应用程序后在Spring上下文中初始化bean的最佳方法? [英] Best way to initialize beans in Spring context after application started?

查看:115
本文介绍了启动应用程序后在Spring上下文中初始化bean的最佳方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的应用程序启动后,我需要在Spring上下文中初始化bean.当前,我在类中使用注解 @Configuration 初始化Bean,如下所示:

I need to initialize beans in the Spring context after my application has started; currently, I initialize beans in a class with annotation @Configuration like this:

@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 ---
   }
}

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

But some beans I need to initialize after application startup so my approach is create a class listen to ApplicationReadyEvent event in Spring and put the code to initialize beans in that class.

@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? ----
    }
}

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

Is this the best way? Or there are some other better solutions?

推荐答案

为了枚举bean,我将列举其他方法,并将该方法分为标准方法和Spring Boot方法.

I will enumerate other approaches in order to init beans, I grouped the approach in Standard Approach and Spring Boot Approach.

标准方法

  1. @PostConstruct:它只是在创建bean之后触发方法的注释,它不允许输入参数.
  2. @Bean(init-method="somInitMehotd"):此方法与Spring bean生命周期完全相关,并且在bean创建之后被调用,如果您正在使用带有@PostConstruct批注的另一种方法,则将首先调用@PostConstruct.这种方法不允许输入参数.
  3. ApplicationListener:此接口允许侦听与上下文生命周期相关的标准事件,也可以侦听自定义事件.例如:创建一个类MyAppListener并实现ApplicationListener<ContextRefreshedEvent>,在这种情况下,MyAppListener将实现一个onApplicationEvent方法,该方法接收一个ContextRefreshedEvent
  1. @PostConstruct: it is just an annotation that triggers a method after bean is create, it doesn't allow input parameters.
  2. @Bean(init-method="somInitMehotd"): this approach is totally related to Spring bean lifecycle and it is called after bean creation, if you are using another method with @PostConstruct annotation, then the @PostConstruct will be called first. This approach doesn't allow input parameters.
  3. ApplicationListener: this interface allows to listen the standard events related to the Context Lifecycle, also it can listen customized events. For example: create a class MyAppListener and implements ApplicationListener<ContextRefreshedEvent> in this case the MyAppListener will implement an onApplicationEvent method that receives a ContextRefreshedEvent

Spring Boot方式

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

  1. The runners: There are two very useful interfaces CommandLineRunner and ApplicationRunner both of them will run after ApplicationContext is created both of them allows to inject beans as input parameters.

Spring引导侦听器:除了来自应用程序上下文的标准事件之外,Spring Application还提供了一些其他事件.事件之一是ApplicationReadyEvent,当应用程序准备接收请求时,它将触发.为了侦听此事件,只需使用ApplicationReadyEvent作为通用类来实现ApplicationListener.

Spring boot listeners: Spring Application gives some additional events than the standards events that comes from the Application Context. One of the event is ApplicationReadyEvent and it is fire when the application is ready to receive request. In order to listen this events just implements the ApplicationListener using ApplicationReadyEvent as generic.

这里是示例:

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

MyBean class has different methods that will be called for each approach listed above, every method will call a print method and that method has a Thread.sleep in order to validate the order that every listener is called.

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

这是ContextRefreshListener类,它将侦听ContextRefreshedEvent并对其进行处理.

Here is the ContextRefreshListener class that will listen the ContextRefreshedEvent and handle it.

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

    }
}

BootListener将接收来自Spring Application的ApplicationReadyEvent.

And it is the BootListener that will receive the ApplicationReadyEvent that comes from Spring Application.

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

最后是Spring Boot应用程序

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

}

输出为:

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

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

All the listed scenarios were triggered by Spring, I didi'nt call any of the events directly, all of them were called by Spring Framework.

这篇关于启动应用程序后在Spring上下文中初始化bean的最佳方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆