应用程序启动后在Spring上下文中初始化bean的最佳方法是什么?
我需要在应用程序启动后在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中监听ApplicationReadyEvent事件,并将代码初始化为该类中的bean。
@Configuration class ApplicationStartingListener implements ApplicationListener{ ---- Code to init bean here ---- @Override public void onApplicationEvent(ApplicationReadyEvent event) { --- If I put init bean code in here, is it correct? ---- } }
这是最好的方法吗? 还是有其他更好的解决方案?
我将枚举其他方法以初始化bean,我将方法分为标准方法和Spring Boot方法。
标准方法
-
@PostConstruct
:它只是一个在创建bean后触发方法的注释,它不允许输入参数。 -
@Bean(init-method="somInitMehotd")
:这种方法与Spring bean生命周期完全相关,并且在bean创建之后调用它,如果你使用带有@PostConstruct
注释的另一个方法,那么将首先调用@PostConstruct
。 此方法不允许输入参数。 -
ApplicationListener
:此接口允许侦听与Context Lifecycle相关的标准事件,也可以侦听自定义事件。 例如:创建一个类MyAppListener
并实现ApplicationListener
MyAppListener
ApplicationListener
在这种情况下,MyAppListener
将实现一个接收onApplicationEvent
方法
春靴方法
-
运行者:有两个非常有用的接口
CommandLineRunner
和ApplicationRunner
,它们都将在创建ApplicationContext后运行,它们都允许将bean作为输入参数注入。 -
Spring引导侦听器:Spring Application提供了一些额外的事件,而不是来自Application Context的标准事件。 其中一个事件是
ApplicationReadyEvent
,当应用程序准备好接收请求时它就会触发。 为了监听此事件,只需使用ApplicationReadyEvent
作为通用实现ApplicationListener
。
这是一个例子:
MyBean类有不同的方法,将为上面列出的每种方法调用,每个方法都会调用一个print方法,并且该方法有一个Thread.sleep,以validation每个监听器的调用顺序。
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
并处理它。
public class ContextRefreshListener implements ApplicationListener { @Override public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { contextRefreshedEvent.getApplicationContext().getBean(MyBean.class).contextInit(); } }
BootListener
将接收来自Spring Application的ApplicationReadyEvent。
public class MyBootListener implements ApplicationListener { @Override public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { applicationReadyEvent.getApplicationContext().getBean(MyBean.class).bootListenerInit(); } }
最后是Spring Boot应用程序
@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
调用的。