【一】相关源代码类

(1)spring的事件发布监听机制的核心管理类:org.springframework.context.event.SimpleApplicationEventMulticaster.

  =>该类的初始化是放在项目加载时,在ioc容器xml配置文件解析加载完毕后,注册bean创建前后置处理实现类(BeanPostProcessor 接口实现),beanFactory配置处理(BeanFactoryPostProcessor接口实现)后,初始化该事件发布监听机制的核心类。

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh(); // 解析xml配置文件
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory); try {
// 注册未来bean实例化的前后置处理的PostProcessor接口实现
postProcessBeanFactory(beanFactory); //执行所有实现BeanFactoryPostProcessor接口实现,对beanFactory进行处理
invokeBeanFactoryPostProcessors(beanFactory); // 注册未来bean实例化的前后置处理的PostProcessor接口实现
registerBeanPostProcessors(beanFactory); // 注册未来bean实例化的前后置处理的PostProcessor接口实现
initMessageSource(); // 实例化spring事件发布监听机制的核心类,SimpleApplicationEventMulticaster
initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses.
onRefresh(); // 注册事件监听器
registerListeners(); // 实例化非懒加载的bean,完成ioc容器中bean的实例化和反转依赖,并在内部实现动态代理相关的操作
finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event.
finishRefresh();
} catch (BeansException ex) {
logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex); // Destroy already created singletons to avoid dangling resources.
destroyBeans(); // Reset 'active' flag.
cancelRefresh(ex); // Propagate exception to caller.
throw ex;
}
}
}

(2)spring的事件发布监听机制的监听器类的接口:org.springframework.context.ApplicationListener<E extends ApplicationEvent>

  =>监听器的定义必须实现该接口。

  =>所监听的事件也必须继承org.springframework.context.ApplicationEvent的抽象类

  =>在初始化管理类后,会注册监听器。会从beanFactory里得到所有实现ApplicationListener接口的bean的名字,并注册到ListenerRetriever的属性applicationListenerBeans集合中。

(3)spring的事件发布监听机制的事件的基础类:org.springframework.context.ApplicationEvent

  =>事件的事件类必须继承该基类

  =>定义监听器的同时,必须定义相关的事件类。

(4)spring的事件发布监听机制的存储事件监听的类:org.springframework.context.event.AbstractApplicationEventMulticaster.ListenerRetriever

    =>该类内部存储了一个n个事件对应的多个监听器

    =>属性Set<ApplicationListener<?>> applicationListeners  存储的是事件监听器的实例

    =>属性Set<String> applicationListenerBeans  存储的事件监听器在ioc容器中的beanNames

(5)spring的事件发布监听机制的存储事件体的类:org.springframework.context.event.AbstractApplicationEventMulticaster.ListenerCacheKey

    =>一个事件体的class类型+事件源(事件体内存储的数据)的class类型决定由那些监听监听器处理该事件

    =>属性Class<?> eventType 存储的事件体的class类型

    =>属性Class<?> sourceType 存储的事件源的class类型(事件体内数据)

【二】设计思想

(1)通过事件体,拿到事件类的cls1类型,和事件源(事件体内部存储的数据类)的cls类型

(2)然后在IOC容器中所有实现ApplicationListener接口的事件监听器中进行匹配。找到所有适合该事件的事件监听器集合。将事件监听集合形成ListenerRetriever对象。

  =>从IOC容器中的一个个事件监听器实现类的范型填充类的类型(也就是事件体的 类型)cls2

  =>Listener可能是代理对象(因为@Async注解),Listenner的ioc在实例化阶段,会被spring创建成代理对象。spring内部也会做处理,得到代理对象代理的targetClass,也就是Listenner的真实类型。

  =>看当前事件体的类型cls1是否是事件监听器的范型填充类的类型cls2的子类或本身。如果是,则表示这个事件监听器匹配该事件。

(3)将该事件体,的事件类的cls1类型+事件源的cls类型。形成ListenerCacheKey对象,以此为key,以事件监听集合ListenerRetriever对象作为value,存储在AbstractApplicationEventMulticaster类中private final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<ListenerCacheKey, ListenerRetriever>(64);属性中作为cache,方便下次匹配,不再从ioc容器中重新匹配。

【三】事件缓冲,扩展。hasMap中以对象作为key。需要重写hasCode方法,equals方法

private static class ListenerCacheKey {

        private final Class<?> eventType;

        private final Class<?> sourceType;

        public ListenerCacheKey(Class<?> eventType, Class<?> sourceType) {
this.eventType = eventType;
this.sourceType = sourceType;
} @Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
ListenerCacheKey otherKey = (ListenerCacheKey) other;
return ObjectUtils.nullSafeEquals(this.eventType, otherKey.eventType) &&
ObjectUtils.nullSafeEquals(this.sourceType, otherKey.sourceType);
} @Override
public int hashCode() {
return ObjectUtils.nullSafeHashCode(this.eventType) * 29 + ObjectUtils.nullSafeHashCode(this.sourceType);
}
}

【spring源码学习】spring的事件发布监听机制源码解析的更多相关文章

  1. 深入理解Spring的容器内事件发布监听机制

    目录 1. 什么是事件监听机制 2. JDK中对事件监听机制的支持 2.1 基于JDK实现对任务执行结果的监听 3.Spring容器对事件监听机制的支持 3.1 基于Spring实现对任务执行结果的监 ...

  2. Spring事件监听机制源码解析

    Spring事件监听器使用 1.Spring事件监听体系包括三个组件:事件.事件监听器,事件广播器. 事件:定义事件类型和事件源,需要继承ApplicationEvent. package com.y ...

  3. Spring Boot(六)自定义事件及监听

    事件及监听并不是SpringBoot的新功能,Spring框架早已提供了完善的事件监听机制,在Spring框架中实现事件监听的流程如下: 自定义事件,继承org.springframework.con ...

  4. SpringBoot事件监听机制源码分析(上) SpringBoot源码(九)

    SpringBoot中文注释项目Github地址: https://github.com/yuanmabiji/spring-boot-2.1.0.RELEASE 本篇接 SpringApplicat ...

  5. Spring笔记(7) - Spring的事件和监听机制

    一.背景 事件机制作为一种编程机制,在很多开发语言中都提供了支持,同时许多开源框架的设计中都使用了事件机制,比如SpringFramework. 在 Java 语言中,Java 的事件机制参与者有3种 ...

  6. 【cocos2d-js官方文档】事件分发监听机制(摘录)

    简介 游戏开发中一个很重要的功能就是交互,如果没有与用户的交互,那么游戏将变成动画,而处理用户交互就需要使用事件监听器了. 总概: 事件监听器(cc.EventListener) 封装用户的事件处理逻 ...

  7. jsonp和事件发布监听

    模拟jsonp var id = 0; function JSONP(url,param,cb){ var callbackName = "json_" + id++; var a ...

  8. Spring知识点回顾(07)事件发布和监听

    Spring知识点回顾(07)事件发布和监听 1.DemoEvent extends ApplicationEvent { public DemoEvent(Object source, String ...

  9. Spring事件发布与监听机制

    我是陈皮,一个在互联网 Coding 的 ITer,微信搜索「陈皮的JavaLib」第一时间阅读最新文章,回复[资料],即可获得我精心整理的技术资料,电子书籍,一线大厂面试资料和优秀简历模板. 目录 ...

随机推荐

  1. 【JavaScript】用JS绘制一个球

    参考: 1.http://www.w3school.com.cn/html5/html_5_canvas.asp 2.http://blog.csdn.net/qq_27626333/article/ ...

  2. jQuery可自动播放动画的焦点图

    在线演示 本地下载

  3. 20145217《网络对抗》 MAL_简单后门学习总结

    20145217<网络对抗> MAL_简单后门学习总结 实践内容: 1.netcat的应用 2.socat的应用 3.meterpreter的应用 知识点学习总结 后门程序一般是指那些绕过 ...

  4. 20145219 《Java程序设计》第09周学习总结

    20145219 <Java程序设计>第09周学习总结 教材学习内容总结 JDBC入门 JDBC简介 1.JDBC是java联机数据库的标准规范,它定义了一组标准类与接口,应用程序需要联机 ...

  5. mysql配置文件生效顺序

    安装完数据库 除了将my.cnf放在/etc/下放在其他地方也是可以的 cp /usr/share/mysql/my-default.cnf /etc/my.cnf 今天就看一下这些my.cnf是怎么 ...

  6. 配置iptables实现本地端口转发的方法详解

    场景假如你在用 resin 调试一个 Web 程序,需要频繁地重启 resin.这个 Web 程序需要开在 80 端口上,而 Linux 限制 1024 以下的端口必须有 root 权限才能开启.但是 ...

  7. 详细Http状态查询

    状态代码 状态信息 含义 100 Continue 初始的请求已经接受,客户应当继续发送请求的其余部分.(HTTP 1.1新) 101 Switching Protocols 服务器将遵从客户的请求转 ...

  8. eclipse中设置新建jsp文件的编码格式

    每次新建jsp文件时,默认都是ISO-8859-1,每次涉及有中文的时候都得改成UTF-8,这就很麻烦了. 解决的方法就是,设置新建jsp文件的编码格式. 解决方法 结果 或者更改它的encoding

  9. eclipse设置控制台字体大小

    步骤如下

  10. 一个Elasticsearch嵌套nested查询的实例

    创建索引和数据准备 PUT course PUT course/_mapping/course { "properties": { "course":{ &qu ...