Spring 的事件机制(应用事件和容器事件)
- 1. Spring Boot事件机制
- 2. ApplicationEvent: 应用事件和容器事件
- 2.1 应用事件的触发顺序
- 3. ApplicationListener:事件监听器的注册方式
- 3.1 spring.factories注册方式
- 3.2 配置SpringApplication
- 3.3 配置ApplicationContext
- 3.4 注册ApplicationEventListener接口的Bean
- 3.5 @EventListener @TransactionalEventListener
- 3.6 事件监听器执行顺序
- 4. ApplicationEventPublisher:事件发布
- 5. ApplicationEventMulticaster:监听器的注册&广播
- 参考
1. Spring Boot事件机制
Spring Boot事件机制是基于Java的事件机制进行设计的,主要包含事件源、事件、事件监听三部分。
在Spring Boot中
- ApplicationEvent是Spring的事件接口
- ApplicationListener是Spring的事件监听器接口,所有的监听器都实现该接口
- ApplicationEventPublisher是Spring的事件发布接口,ApplicationContext实现了该接口
- ApplicationEventMulticaster是Spring事件机制中的事件广播器,默认实现SimpleApplicationEventMulticaster
2. ApplicationEvent: 应用事件和容器事件
Spring Boot中有两类事件,应用事件和容器事件。
应用事件为Spring boot启动过程中的事件,对应类SpringApplicationEvent;容器事件为Spring容器启动过程中的事件,对应类ApplicationContextEvent。SpringApplicationEvent和ApplicationContextEvent一脉相承都继承自ApplicationEvent。
下图是相关应用事件和容器事件核心类的类图:
2.1 应用事件的触发顺序
- org.springframework.boot.context.event.ApplicationStartingEvent
- org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent
- org.springframework.boot.context.event.ApplicationContextInitializedEvent
- org.springframework.boot.context.event.ApplicationPreparedEvent
- org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent
- org.springframework.boot.context.event.ApplicationStartedEvent
- org.springframework.boot.context.event.ApplicationReadyEvent
3. ApplicationListener:事件监听器的注册方式
容器监听器可以 在应用启动和容器加载的不同阶段 进行注册。它有以下几种注册方式:
- spring.factories
- SpringApplication.addListeners, SpringApplicationBuilder.listeners
- ApplicationContext.addApplicationListener
- 注册ApplicationEventListener接口的Bean
- @EventListener @TransactionalEventListener
3.1 spring.factories注册方式
实现org.springframework.context.ApplicationListener接口并注册到\META-INF\spring.factories文件中。
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
示例:spring-boot-autoconfigure-2.1.5.RELEASE.jar!\META-INF\spring.factories
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
3.2 配置SpringApplication
通过org.springframework.boot.SpringApplication#addListeners,org.springframework.boot.builder.SpringApplicationBuilder#listeners方法设置ApplicationListener。
3.3 配置ApplicationContext
配置ApplicationContext通常发生在org.springframework.boot.SpringApplication#applyInitializers,该方法主要是通过ApplicationContextInitializer进行ApplicationContext的一些初始化操作。
通过调用方法org.springframework.context.support.AbstractApplicationContext#addApplicationListener进行ApplicationListener注册。
3.4 注册ApplicationEventListener接口的Bean
实现org.springframework.context.ApplicationListener并注册到Bean。
示例:
@Component
public class ContextRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> {
private Logger logger = LoggerFactory.getLogger(ContextRefreshedEventListener.class);
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
logger.info("========== Application context refreshed!");
}
}
@Component
@Order(2)
public class ContextEventListener implements GenericApplicationListener {
private Logger logger = LoggerFactory.getLogger(ContextClosedEventListener.class);
@Override
public boolean supportsEventType(ResolvableType eventType) {
Class<?> type = eventType.getRawClass();
if (type == null) {
return false;
}
return ContextRefreshedEvent.class.isAssignableFrom(type)
|| ContextStartedEvent.class.isAssignableFrom(type)
|| ContextClosedEvent.class.isAssignableFrom(type)
|| ContextStoppedEvent.class.isAssignableFrom(type);
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
logger.info("========== " + event.getClass().getName());
}
}
3.5 @EventListener @TransactionalEventListener
注解处理类:
org.springframework.context.event.EventListenerMethodProcessor
@Component
public class SbiaFeatureEventListener {
private static final Logger LOGGER = LoggerFactory.getLogger(SbiaFeatureEventListener.class);
@EventListener
public void listenSbiaFeature(SbiaFeatureApplicationEvent event) {
LOGGER.info("com.tm.sbia.feature.context.listener.SbiaFeatureEventListener.listenSbiaFeature invoked!");
}
}
3.6 事件监听器执行顺序
可以通过以下几种方式指定Listener的处理顺序。
- 实现PriorityOrdered接口
- 实现Order接口
- 在类、方法、注解上添加@Order或@Priority注解
org.springframework.core.annotation.AnnotationAwareOrderComparator#findOrder
protected Integer findOrder(Object obj) {
// Check for regular Ordered interface
Integer order = super.findOrder(obj);
if (order != null) {
return order;
}
// Check for @Order and @Priority on various kinds of elements
if (obj instanceof Class) {
return OrderUtils.getOrder((Class<?>) obj);
}
else if (obj instanceof Method) {
Order ann = AnnotationUtils.findAnnotation((Method) obj, Order.class);
if (ann != null) {
return ann.value();
}
}
else if (obj instanceof AnnotatedElement) {
Order ann = AnnotationUtils.getAnnotation((AnnotatedElement) obj, Order.class);
if (ann != null) {
return ann.value();
}
}
else {
order = OrderUtils.getOrder(obj.getClass());
if (order == null && obj instanceof DecoratingProxy) {
order = OrderUtils.getOrder(((DecoratingProxy) obj).getDecoratedClass());
}
}
return order;
}
4. ApplicationEventPublisher:事件发布
应用事件的发布通过EventPublishingRunListener -> SpringApplicationRunListener进行;
容器时间的发布通过ApplicationEventPublisher的实现类发布;
@Component
public class SbiaFeatrueEventPublisher implements ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
public void publishSbiaFeatureEvent() {
applicationEventPublisher.publishEvent(new SbiaFeatureApplicationEvent(this));
}
}
5. ApplicationEventMulticaster:监听器的注册&广播
ApplicationEventPublisher的默认实现SimpleApplicationEventMulticaster。
SimpleApplicationEventMulticaster -> AbstractApplicationEventMulticaster -> ApplicationEventMulticaster
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SbiaFeatureApp.class)
public class SbiaFeatrueEventPublisherTest {
@Autowired
private SbiaFeatrueEventPublisher publisher;
@Test
public void publishSbiaFeatureEvent() {
publisher.publishSbiaFeatureEvent();
}
}