ApplicationListener监听器耍过没?

1,876 阅读4分钟

这是我参与更文挑战的第3天,活动详情查看: 更文挑战

书接上文的存本地的缓存那篇文章,在我们项目启动的过程中,总会有某些数据需要加载,而在数据加载完成时我们会需要进行其他的一些处理(这些处理必须在数据被加载完成才可以进行),通常情况下,我们日常是不会没事使用这玩意的,毕竟这玩意多了伤身,对于机器也一样,伤项目

可是正常开发时不用不代表项目搭建时不用,不代表后期不改动,毕竟我们的目标是星辰大海

废话不多说,先来直呼标题

ApplicationListener是什么

这玩意是一个监听器,观察者模式的完美运用,应用程序事件侦听要实现的接口。 基于观察者设计模式的标准 java.util.EventListener 接口。 从 Spring 3.0 开始,ApplicationListener 可以一般地声明它感兴趣的事件类型。当注册到 Spring ApplicationContext 时,事件将被相应地过滤,侦听器被调用以仅匹配事件对象(机翻(手动狗头))

ApplicationListener怎么用

首先我们得理清原理

  1. 先来看下该接口

    public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    	void onApplicationEvent(E event);
    }
    

可以看出里面泛型是ApplicationEvent的,那ApplicationListener的包org.springframework.context下监听事件可以用啥

正是这四个大哥;

为了保证文章的通俗易懂,我决定对官方的注释不翻译(看不懂也没关系,后面需要英文有用)

1.**ContextRefreshedEvent :**Event raised when an ApplicationContext gets initialized or refreshed.(当ApplicationContext被初始化或刷新时引发的事件(ed完成时,所有是完成时引发时间))

2.**ContextClosedEvent:**Event raised when an ApplicationContext gets closed(ApplicationContext关闭时引发的事件).

3.**ContextStartedEvent:**Event raised when an ApplicationContext gets started(当ApplicationContext启动时引发事件).

4.**ContextStoppedEvent:**Event raised when an ApplicationContext gets stopped(当ApplicationContext停止时引发事件)。

当然存在拓展,拓展的此处不讨论

下面捡取一个也就是我项目用到的说吧ContextRefreshedEvent(没错,正是在下);其他的也是相同的思路;

首先得看定义完成bean装载触发,那必须得监听bean对吧,源码注释有个see also

org.springframework.context.event.ApplicationEventMulticaster

懒得写,写的还不清晰,直接上图

可以看到最终的实现监听类是SimpleApplicationEventMulticaster,官方给的定义是Multicasts all events to all registered listeners(所有事件注册给监听器)

先来看看抽象类AbstractApplicationEventMulticaster提供基本的监听器注册工具

这里就是获取到监听事件,那么得

首先看下加载或刷新配置的AbstractApplicationContext.refresh()方法;

注释对于我这个英文很差的都可以看懂,各位一定也行

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.准备刷新
			prepareRefresh();
			// Tell the subclass to refresh the internal bean factory.
                        告诉子类刷新bean工厂方法,如果该bean工厂存在就销毁重新创建
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			// Prepare the bean factory for use in this context.
                        上下文准备使用bean工厂
			prepareBeanFactory(beanFactory);
			try {
				// Allows post-processing of the bean factory in context subclasses.
                                上下文子类对bean处理,加载所有bean,但未实例化bean
				postProcessBeanFactory(beanFactory);
				// Invoke factory processors registered as beans in the context.
                                调用工厂注册bean处理器
				invokeBeanFactoryPostProcessors(beanFactory);
				// Register bean processors that intercept bean creation.
                                注册bean
				registerBeanPostProcessors(beanFactory);
				// Initialize message source for this context.
				initMessageSource();
				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();下面有讨论
				// Initialize other special beans in specific context subclasses.
				onRefresh();//暂且没做处理
				// Check for listener beans and register them.
				registerListeners();
				// Instantiate all remaining (non-lazy-init) singletons.
                                初始化所以剩余的bean---非延迟
				finishBeanFactoryInitialization(beanFactory);
				// Last step: publish corresponding event.
                                看到没这里是发布事件,下面有解释
				finishRefresh();
			}
		}
	}

**initApplicationEventMulticaster()**初始化ApplicationEventMulticaster;先去查找有没有applicationEventMulticaster这个bean,如果存在就给事件分发器,没有就交给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 {
			this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
			beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
		}
	}

注意,这代码里很多地方用到了单例模式,没事可以阅读阅读!!!

**finishRefresh()**我们关注下倒数第二个方法的调用

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.
		publishEvent(new ContextRefreshedEvent(this));

		// Participate in LiveBeansView MBean, if active.
		LiveBeansView.registerApplicationContext(this);
	}

publishEvent()将给定的事件发布给所有的侦听器,这里也有一段代码

// 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);
		}

这里用到了earlyApplicationEvents,这个是前面refresh方法之前的,early嘛。。。刷新前注册本地监听器;

multicastEvent(applicationEvent, eventType)会调用invokeListener(listener, event);

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		Executor executor = getTaskExecutor();
		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

先看下getApplicationListeners(event, type)方法;该方法部分注释是:Return a Collection of ApplicationListeners matching the given event type(返回匹配的事件类型)

该方法会去调用ListenerCacheKey类

这块检索侦听结束。。。

invokeListener(listener, event)再调用doInvokeListener(listener, event);

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			listener.onApplicationEvent(event);
		}

看看看;回来了呦onApplicationEvent。。。

芜湖。。。看源码好累啊。。。

调用也很简单,这样(记得Component注解)

@Component
public class MytestDemo implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        System.out.println("调用到监听器");
    }
}