SpringBoot(2) - SpringApplication - Application事件与监听器
除了一般的Spring的事件,例如ContextRefreshedEvent,SpringApplication也会一些额外application事件。
提示:
一些事件实际上是在ApplicationContext被创建之前触发,所以不能通过@Bean将它们注册为监听器。可以通过SpringApplication.addListeners(...)或者SpringApplicationBuilder.listeners(...)方法注册。
假如自动注册这些监听器,且不管application是否是否被创建,那么可以在项目中添加一个META-INF/spring.factories文件,通过org.springframework.context.ApplicationListener属性配置监听器。如:
org.springframework.context.ApplicationListener=com.example.project.MyListener
1. 当项目启动时,Application事件按照以下次序发送:
- ApplicationStartingEvent:开始启动时,除了监听器已经注册和初始化,其他没有任何处理时发送。此时可以获取SpringApplication实例,做一些执行前设置。
- ApplicationEnvironmentPreparedEvent:Environment已经创建,但上下文context还没有创建时发送。可以获取ConfigurableEnvironment实例,修改默认配置或新增额外的配置
- ApplicationPreparedEvent:所有bean定义已经加载,上下文刷新之前发送。可以获取到上下文,但是无法获取bean进行操作
- ApplicationReadyEvent:上下文刷新之后,一些相关的回调已经被处理(表明应用准备去服务请求)后发送。可以获取上下文,也可以进行操作
- ApplicationFailedEvent:启动时有异常时发送。可以获取到异常信息
使用Spring Framework的事件发布机制发送应用程序事件。 该机制的一部分确保了发布到子上下文中的监听器事件也发布到任何祖先上下文中的监听器。 因此,如果应用程序使中使用SpringApplication实例的层次结构,则监听器可能会收到相同类型的应用程序事件的多个实例。即同一事件监听器会触发多次,但是实例不同。
为了允许监听器区分其上下文的事件和后代上下文的事件,它应该请求注入其应用程序上下文,然后将注入的上下文与事件的上下文进行比较。 可以通过实现ApplicationContextAware来注入上下文,或者,如果监听器是bean,则使用@Autowired。Application事件使用Spring Framework的事件发布机制发送。
2. 示例
以ApplicationReadyEvent为例,此时已经初始化好所有bean,可以对这些bean进行操作。其余事件定义方式类似
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.Arrays;
public class MyApplicationReadyEventListener implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
ConfigurableApplicationContext ac = event.getApplicationContext();
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
Arrays.stream(beanDefinitionNames).forEach(beanName -> {
System.out.println(beanName + " --- " + ac.getBean(beanName));
});
System.out.println("=== execute MyApplicationReadyEventListener ===");
}
}
SpringApplication中进行注册:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.addListeners(new MyApplicationReadyEventListener());
app.run(args);
}
}
打印如下: