Spring事件使用案例
1. 自定义事件
public class MyEvent extends ApplicationEvent {
private String name;
public MyEvent(Object source) {
super(source);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2. 事件监听器
2.1 实现ApplicationListener 接口
@Component
public class MyEventListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
System.out.println("监听到事件:" + event.getSource());
}
}
2.2 @EventListener注解
@Component
public class MyEventListener{
@EventListener
public void onApplicationEvent(MyEvent event) {
System.out.println("监听到事件:" + event.getSource());
}
}
另外也可以通过@Async注解实现对事件的异步监听
@EventListener
@Async
public void onApplicationEvent(MyEvent event) {
System.out.println("监听到事件: " + event.getSource());
}
3. 事件发布
applicationContext.publishEvent(new MyEvent("PUBLISH EVENT1"));
源码解析
1. 如何找到自定义的事件监听器
通过ApplicationListenerDetector实现了BeanPostProcessor接口,在后置处理器中判断如果bean是ApplicationListener类型且是单例的那么进行添加。
private static class ApplicationListenerDetector
implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor {
private transient final AbstractApplicationContext applicationContext;
private transient final Map<String, Boolean> singletonNames = new ConcurrentHashMap<String, Boolean>(256);
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (this.applicationContext != null && beanDefinition.isSingleton()) {
this.singletonNames.put(beanName, Boolean.TRUE);
}
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 收集事件监听器
if (this.applicationContext != null && bean instanceof ApplicationListener) {
// potentially not detected as a listener by getBeanNamesForType retrieval
Boolean flag = this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
// singleton bean (top-level or inner): register on the fly
// 仅添加单例的bean
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
}
else if (flag == null) {
this.singletonNames.put(beanName, Boolean.FALSE);
}
}
return bean;
}
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) {
if (bean instanceof ApplicationListener) {
ApplicationEventMulticaster multicaster = this.applicationContext.getApplicationEventMulticaster();
multicaster.removeApplicationListener((ApplicationListener<?>) bean);
multicaster.removeApplicationListenerBean(beanName);
}
}
@Override
public boolean requiresDestruction(Object bean) {
return (bean instanceof ApplicationListener);
}
}
AbstractApplicationContext#addApplicationListener 加入到监听列表
public void addApplicationListener(ApplicationListener<?> listener) {
Assert.notNull(listener, "ApplicationListener must not be null");
if (this.applicationEventMulticaster != null) {
this.applicationEventMulticaster.addApplicationListener(listener);
}
// 加入到集合中
this.applicationListeners.add(listener);
}
2. 初始化事件管理器类和注册监听器
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备刷新上下文
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
// 初始化事件管理类
initApplicationEventMulticaster();
onRefresh();
// Check for listener beans and register them.
// 往事件发布器上注册事件监听器, 事件发布的核心逻辑在这
registerListeners();
finishBeanFactoryInitialization(beanFactory);
// 刷新完成
finishRefresh();
}
catch (BeansException ex) {
}
finally {
}
}
}
/**
* 初始化事件发布器
* 如果上下文没有定义事件发布器的话 使用SimpleApplicationEventMulticaster
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
*/
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
}
else {
// 如果没有自定义事件发布器,那么spring默认生成一个
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}
/**
* 往事件发布器上注册事件监听器, 事件发布的核心逻辑在这
* Add beans that implement ApplicationListener as listeners.
* Doesn't affect other listeners, which can be added without being beans.
*/
protected void registerListeners() {
// Register statically specified listeners first.
// 注册特殊的监听器
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
// 从beanFactory里面获取ApplicationListener监听器名称列表, 例如我们自定义的事件监听都在这里
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
// 把这些beanName添加到applicationListenerBeans监听器列表里,当事件发布时,通知这些beanName
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
// 添加事件监听器后, 判断是否有earlyApplicationEvents, 如果有就使用事件发布器进行广播
// earlyApplicationEvents表示在事件发布器还没有生成之前ApplicationContext需要发布的事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
事件发布重要方法 SimpleApplicationEventMulticaster#multicastEvent
@Override
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
// 如果设置了线程池,那么异步执行否则同步执行
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
// 执行监听器方法
invokeListener(listener, event);
}
});
}
else {
// 执行监听器方法
invokeListener(listener, event);
}
}
}
// 执行监听器方法
protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
// 执行onApplicationEvent方法
listener.onApplicationEvent(event);
}
其中注意点
2.1 上下文属性 AbstractApplicationContext #earlyApplicationEvents
这是用于存储发布器初始化之前的事件列表
/** ApplicationEvents published early */
private Set<ApplicationEvent> earlyApplicationEvents;
一旦事件发布器可用 立即被发布
public void refresh() throws BeansException, IllegalStateException {
//Prepare this context for refreshing.
prepareRefresh();
// ...
}
// 在这里初始化了该事件列表
protected void prepareRefresh() {
// Initialize any placeholder property sources in the context environment
initPropertySources();
// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
2.2 Spring 生命周期内置的事件监听
finishRefresh完成刷新时,发布了一个ContextRefreshedEvent事件。
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches();
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event.
// 发布了一个ContextRefreshedEvent事件
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
if (!NativeDetector.inNativeImage()) {
LiveBeansView.registerApplicationContext(this);
}
}
关于spring上下文生命周期发布事件的场景如下
-
AbstractApplicationContext#start
-
AbstractApplicationContext#stop
-
AbstractApplicationContext#refresh#finishRefresh
-
AbstractApplicationContext#registerShutdownHook#doClose
3. 事件发布真正调用的方法AbstractApplicationContext#publishEvent
protected void publishEvent(Object event, ResolvableType eventType) {
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<Object>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
}
}
// 如果earlyApplicationEvents不为空(prepareRefresh里面进行了初始化),那么加入发布器的事件列表
// 等待事件发布器准备好再进行广播
// 否则立即进行广播
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
// 广播事件
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
至于SimpleApplicationEventMulticaster#multicastEvent方法上文已经分析过了,不做赘述。
4. @EventListener注解方式的监听器是怎么处理的
通过EventListenerMethodProcessor,实现了SmartInitializingSingleton接口,在Bean实例化结束之后调用afterSingletonInstantiated()方法对每个单例Bean进行处理,如果一个方法上有@EventListener注解,那么会把方法包装成事件监听器。
@Override
public void afterSingletonsInstantiated() {
ConfigurableListableBeanFactory beanFactory = this.beanFactory;
Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
//...
try {
processBean(beanName, type);
}
catch (Throwable ex) {
throw new BeanInitializationException("Failed to process @EventListener " +
"annotation on bean with name '" + beanName + "'", ex);
}
}
}
private void processBean(final String beanName, final Class<?> targetType) {
if (!this.nonAnnotatedClasses.contains(targetType) &&
AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
!isSpringContainerClass(targetType)) {
Map<Method, EventListener> annotatedMethods = null;
try {
// 找到@EventListener注解标注的方法
annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
}
catch (Throwable ex) {
// ...
}
if (CollectionUtils.isEmpty(annotatedMethods)) {
// ...
}
else {
// Non-empty set of methods
ConfigurableApplicationContext context = this.applicationContext;
Assert.state(context != null, "No ApplicationContext set");
List<EventListenerFactory> factories = this.eventListenerFactories;
Assert.state(factories != null, "EventListenerFactory List not initialized");
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
// 将加了@EventListener注解的方法生成applicationListener类
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
// 添加到applicationListeners列表中
context.addApplicationListener(applicationListener);
break;
}
}
}
//...
}
}
}
当发布事件时, getApplicationListeners(event, type)获取到的ApplicationListener里面有上面生成的ApplicationListenerMethodAdapter包装类。最后调用包装对象的processEvent方法
public void processEvent(ApplicationEvent event) {
Object[] args = resolveArguments(event);
if (shouldHandle(event, args)) {
// 反射执行@EventListener标注的方法
Object result = doInvoke(args);
if (result != null) {
handleResult(result);
}
else {
logger.trace("No result object given - no result to handle");
}
}
}
【本文完】