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。

下图是相关应用事件和容器事件核心类的类图:

spring 事件流 spring事件机制是使用_事件机制

2.1 应用事件的触发顺序

  1. org.springframework.boot.context.event.ApplicationStartingEvent
  2. org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent
  3. org.springframework.boot.context.event.ApplicationContextInitializedEvent
  4. org.springframework.boot.context.event.ApplicationPreparedEvent
  5. org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent
  6. org.springframework.boot.context.event.ApplicationStartedEvent
  7. 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();
    }
}