关于spring相关文章回顾:
一、spring中Bean的初始化过程
二、spring中bean的生命周期
三、spring中AOP技术解析
四、spring中的事件驱动机制解析
public abstract class ApplicationEvent extends EventObject {
private static final long serialVersionUID = 7099057708183571937L;
private final long timestamp;
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
public final long getTimestamp() {
return this.timestamp;
}
}
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
// 此子接口提供了泛型,和提供了统一的处理方法
void onApplicationEvent(E event);
}
@FunctionalInterface
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
// 这个接口是Spring4.2后提供的,可以发布任意的事件对象(即使不是ApplicationEvent的子类了)
// 当这个对象不是一个ApplicationEvent,我们会使用PayloadApplicationEvent来包装一下再发送
void publishEvent(Object event);
}
ApplicationEventPublisher 事件发布器是Spring 事件监听机制的核心。ApplicationContext的抽象实现类AbstractApplicationContext是所有Spring容器的基础。
AbstractApplicationContext类的源码中有方法registerListeners,这个注册的动作是在方法refresh()中被调用的,也就是在初始化容器的时候调用自动调用的。
/**
* 注册监听器
*/
protected void registerListeners() {
//getApplicationListeners()获得容器中所有的ApplicationListener对象
for (ApplicationListener<?> listener : getApplicationListeners()) {
//注册监听器对象的实例,真正的注册事件监听器的对象是ApplicationEventMulticaster
getApplicationEventMulticaster().addApplicationListener(listener);
}
//注册监听器对象的名称,真正的注册事件监听器的对象是ApplicationEventMulticaster
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 发布某些事件earlyEventsToProcess 包含的事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
其中,getApplicationListeners()获得容器中所有的ApplicationListener对象:
public Collection<ApplicationListener<?>> getApplicationListeners() {
return this.applicationListeners;
}
其中,this.applicationListeners字段的write过程是在方法addApplicationListener()中。其中涉及到对象applicationEventMulticaster,该对象是作为ApplicationContext实现事件发布器的委托对象,真正的监听器注册,发送事件都是由该对象实现。
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
Assert.notNull(listener, "ApplicationListener must not be null");
if (this.applicationEventMulticaster != null) {
this.applicationEventMulticaster.addApplicationListener(listener);
}
else {
this.applicationListeners.add(listener);
}
}
继续跟代码可以查到方法addApplicationListener()被ApplicationListenerDetector中的postProcessAfterInitialization()方法调用:
@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)) {
//添加监听器
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
}
else if (Boolean.FALSE.equals(flag)) {
if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
// inner bean with other scope - can't reliably process events
logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
"but is not reachable for event multicasting by its containing ApplicationContext " +
"because it does not have singleton scope. Only top-level listener beans are allowed " +
"to be of non-singleton scope.");
}
this.singletonNames.remove(beanName);
}
}
return bean;
}
ApplicationListenerDetector实现了BeanPostProcessor接口,可以在容器级别对所有bean的生命周期过程进行增强。这里主要是为了能够在初始化所有bean后识别出所有的事件监听器bean并将其注册到事件发布器中。具体可以参看refresh()方法中的prepareBeanFactory(beanFactory)过程,其中就注册ApplicationListenerDetector对象。
我们一般都会使用AbstractApplicationContext#publish()来发布一个事件,AbstractApplicationContext类的方法中发布事件的过程源码:
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
// Decorate event as an ApplicationEvent if necessary
// 如果这个事件不是ApplicationEvent类型,那就包装成这个类型
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
} else {
// 注意此处:第一个参数为source,这里传的source,第二个是payload,才传的是事件本身
applicationEvent = new PayloadApplicationEvent<>(this, event);
// 若没有指定类型。就交给PayloadApplicationEvent,它会根据泛型类型生成出来的~~~
if (eventType == null) {
eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
// 如果是早期事件,就添加进去 会立马发布了(一般都不属于这种)
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
} else {
// 最终把这些时间都委派给了`ApplicationEventMulticaster` 让它去发送事件
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
// 此处注意:特别重要,如果是父容器,也会向父容器里广播一份~~~~~
if (this.parent != null) {
// 这个判断的用意是,既然eventType已经解析出来了,所以就调用protected内部方法即可,而不用再次解析一遍了
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
// 如果是普通的发布,就没有eventType了
else {
this.parent.publishEvent(event);
}
}
}
从以上的源码中我们看到不论是监视器注册,还是事件的发布均由ApplicationEventMulticaster作为ApplicationContext的委托方进行实际的操作,接下来,我们分析一下ApplicationEventMulticaster:
/** Helper class used in event publishing */
private ApplicationEventMulticaster applicationEventMulticaster;
/**
* 跟一下该字段applicationEventMulticaster被Write的时机,
* 发现是在initApplicationEventMulticaster()方法中,而该方法会在Spring容器初始化的时候被调用
*/
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);
if (logger.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default [" + this.applicationEventMulticaster + "]");
}
}
}
逻辑很简单:
1.如果容器中存在ApplicationEventMulticaster该对象则直接获得该对象
2.若不存在ApplicationEventMulticaster对象则创建一个子类实例,
SimpleApplicationEventMulticaster。
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
// 若set了一个执行器,那所有的监听器都将会异步执行
@Nullable
private Executor taskExecutor;
// 监听者执行失败的回调~~~~~~(比如做回滚等等)
@Nullable
private ErrorHandler errorHandler;
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 这里面有个细节:如果有执行器executor ,那就会扔给线程池异步去执行
// 默认情况下是没有的(Spring默认情况下同步执行这些监听器的) 我们可以调用set方法配置一个执行器(建议)
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
// 放在线程池里执行,相当于异步执行。绝大多数情况下,这里都是null
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
} else {
//这里会调用doInvokeListener(listener, event)这个方法
invokeListener(listener, event);
}
}
}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 如果是实现了ApplicationListener接口,则直接调用其中的onApplicationEvent()方法;
//如果是用@EventListener注释,则调用ApplicationListenerMethodAdapter中的onApplicationEvent()方法
listener.onApplicationEvent(event);
}
}
invokeListener的处理逻辑:
1.判断是否存在错误处理器,若存在错误处理器,当发生异常的时候调用对应的错误处理方法;
2.不存在错误错误处理器,直接调用doInvokeListener(listener, event);方法
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
//调用事件监视器中的onApplicationEvent方法,完成事件发布工作
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass().getName())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
processEvent(event);
}
public void processEvent(ApplicationEvent event) {
// 获取参数,最终会交给回调的方法的。事件类型是PayloadApplicationEvent,那就把.getPayload(),否则就是event本身喽
Object[] args = resolveArguments(event);
// 解析condition表达式(注意,此处把args传进去了) 因此我们表达式里是可以用这个参数的哦
if (shouldHandle(event, args)) {
// 就是执行目标方法,我们一般返回值都是void,所以就是null
// 但是,但是,但是注意了,此处若返回的不是null,还有处理~~~~非常给力:
Object result = doInvoke(args);
if (result != null) {
// 如果返回值是数组或者Collection,会把里面内容当作事件循环publishEvent
// 如果就是个POJO,那就直接publish
// 事件的传递性 就这么的来了,强大啊
handleResult(result);
}
else {
logger.trace("No result object given - no result to handle");
}
}
}
Spring的使用@EventListener监听事件。若监听方法有返回值,那将会把这个返回值当作事件源,一直发送下去,直到返回void或者null停止
通过事件找事件监听器的基本思想很简单:
具体在类AbstractApplicationEventMulticaster的方法getApplicationListeners()中实现的:
// @since 1.2.3
// 提供基本的侦听器注册功能 比如处理代理对象类型~~~
public abstract class AbstractApplicationEventMulticaster
implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
// 它是一个内部类,内部持有applicationListeners和applicationListenerBeans的引用
// 是一个类似包装的类,详细可参加下面具体分析
private final ListenerRetriever defaultRetriever = new
ListenerRetriever(false);
// 如果指定了event事件和eventType,那就这个方法 绝大多数情况下都是这里~~~
// 获取该事件对应的监听者:相当于只会获取supportsEvent() = true支持的这种事件~
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
// 这个key是它俩共同决定的~~~~
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// Quick check for existing entry on ConcurrentHashMap...
// 缓存里若存在 直接返回即可~~~~
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
// 这里面~~~ 有个缓存安全的特殊处理,其最为核心的方法,其实还是retrieveApplicationListeners
// 若是缓存安全的,才会缓存它 否则直接return即可~~~~
// 什么叫缓存安全isCacheSafe:原理很简单,就是判断该类型是否在指定classloader或者其parent classloader中
if (this.beanClassLoader == null || (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
// Fully synchronized building and caching of a ListenerRetriever
synchronized (this.retrievalMutex) {
retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
retriever = new ListenerRetriever(true);
// 需要缓存起来,所以才需要把retriever传过去,否则传null即可~(下面传的null)
Collection<ApplicationListener<?>> listeners = retrieveApplicationListeners(eventType, sourceType, retriever);
// 每个事件对应的Listener,都缓存在此处了~(注意:首次get的才给与缓存)
// 因为有的是个体的beanName,有的是给的Bean,所以首次去拿时候缓存吧~~~
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
} else {
// No ListenerRetriever caching -> no synchronization necessary
return retrieveApplicationListeners(eventType, sourceType, null);
}
}
}
基本逻辑:
1.通过事件源类型和事件类型构成ListenerCacheKey
2.从缓存中查找,存在直接方法,不存在走下一步
3.缓存中不存在则,Collection
retrieveApplicationListeners(eventType, sourceType, retriever);
4.将查到的结果缓存起来
这就是我们getApplicationListeners的具体内容,我们发现:它只会拿注册到本容器的监听器(注册在谁身上就是谁的)并不会去父类的拿的,所以这点一定要注意,你自己写监听器的时候也是需要注意这一点的,避免一些重复执行吧。
关于AbstractApplicationEventMulticaster#retrieveApplicationListeners方法,它就是从defaultRetriever把applicationListeners和beanNames都拿出来合并:
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
ResolvableType eventType, Class<?> sourceType, ListenerRetriever retriever) {
LinkedList<ApplicationListener<?>> allListeners = new LinkedList<ApplicationListener<?>>();
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
synchronized (this.retrievalMutex) {
listeners = new LinkedHashSet<ApplicationListener<?>>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
}
for (ApplicationListener<?> listener : listeners) {
//找到指定类型的监听器
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
//返回结果
return allListeners;
}
对应看supportsEvent方法:
protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, Class<?> sourceType) {
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
处理逻辑:
1.当前Listener是GenericApplicationListener 类型,直接强转,否则通过适配器GenericApplicationListenerAdapter获得对象GenericApplicationListener
2.对于获得GenericApplicationListener 对象直接调用其中 的supportsEventType和supportsSourceType方法即可判断该监视器是否支持该事件类型
ApplicationListener和@EventListener的区别是跟他们什么时候注册有关。上面已经讲述了AbstractApplicationEventMulticaster是怎么获取到当前的所有的监听器的,那么他们的区别就在于:它俩注册的时机不一样(此处统一不考虑手动注册时间的情况)。
@EventListener存在漏事件的现象,但是ApplicationListener能监听到所有的相关事件
// @since 4.3.4 出现得还是比较晚的~~~
class ApplicationListenerDetector implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor {
...
// 这个方法会在merge Bean的定义信息时候执行,缓存下该Bean是否是单例Bean
// 因为后面注册的时候:只有单例Bean才给注册为监听器~~~
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (this.applicationContext != null) {
this.singletonNames.put(beanName, beanDefinition.isSingleton());
}
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (this.applicationContext != null && bean instanceof ApplicationListener) {
// 显然 只有单例Bean才会add进去 注册进去
if (Boolean.TRUE.equals(flag)) {
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
} else if (Boolean.FALSE.equals(flag)) {
// 输出一个warn日志:
if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
// 提示用户这个Bean实现了ApplicationListener 但是并不是单例的
logger.warn("...");
}
// 不是单例的就从缓存移除吧~~~~
this.singletonNames.remove(beanName);
}
}
return bean;
}
...
}
因为它是以Bean定义的形式注册进工厂的,并且 refresh() 中有一步 registerListeners() 它负责注册所有的监听器(Bean形式的),然后才是finishBeanFactoryInitialization(beanFactory),所以它是不会落掉事件的。
由此知道,如果你在普通的单例Bean初始化期间(比如给属性赋值时、构造函数内。。。)发出了一个时间,@EventListener这种方式的监听器很有可能是监听不到的。
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
// 让EventListenerMethodProcessor惰性加载~~~~
if (beanDefinitionName.equals(AnnotationConfigUtils.EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
beanFactory.getBeanDefinition(beanDefinitionName).setLazyInit(true);
}
}
}
}
这样容器完成所有的单例实例化步骤后,其实EventListenerMethodProcessor这个Bean并没有完成真正的实例化的。而beanFactory.preInstantiateSingletons()方法最后一步为:
public void preInstantiateSingletons() throws BeansException {
// Trigger post-initialization callback for all applicable beans...
// 执行所有的SmartInitializingSingleton 这里面最为核心的就在于~~~~
// getSingleton(beanName)这个方法,是直接去Map里找,只有被实例化的的单例Bean才会返回true,否则是false
// 不知为何Spring此处不用getBean() 我个人认为 这是Spring为了提高速度的一个疏忽吧~~~~~
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
smartSingleton.afterSingletonsInstantiated();
return null;
}
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
如上:getSingleton方法是直接去DefaultSingletonBeanRegistry的Map
本文暂时只介绍了Spring中的一些简单的事件驱动机制,及源码分析希望能够帮助读者对事件监听机制有一个深入的理解和把握。