原文:http://blog.csdn.net/liaokailin/article/details/48194777

监听源码分析

首先是我们自定义的main方法:

package com.lkl.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import com.lkl.springboot.listener.MyApplicationStartedEventListener; @SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
//app.setAdditionalProfiles("dev");
app.addListeners(new MyApplicationStartedEventListener());
app.run(args);
}
}

SpringApplication app = new SpringApplication(Application.class) 创建一个SpringApplication实例;创建实例执行对象构造方法;其构造方法如下:

   public SpringApplication(Object... sources) {
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.initialize(sources);
}

调用initialize(),该方法执行若干初始化操作,在后续再继续深入该方法。

app.addListeners(new MyApplicationStartedEventListener()); 调用SpringApplication添加监听的方法执行操作:

    public void addListeners(ApplicationListener... listeners) {
this.listeners.addAll(Arrays.asList(listeners));
}

this.listenersList<ApplicationListener<?>>类型,是SpringApplication中所有监听器的持有容器(在initialize()方法中也会往该监听集合中添加初始化的监听器)

执行完添加监听器方法后执行app.run(args)方法

    public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.started(); try {
DefaultApplicationArguments ex = new DefaultApplicationArguments(args);
context = this.createAndRefreshContext(listeners, ex);
this.afterRefresh(context, (ApplicationArguments)ex);
listeners.finished(context, (Throwable)null);
stopWatch.stop();
if(this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
} return context;
} catch (Throwable var6) {
this.handleRunFailure(context, listeners, var6);
throw new IllegalStateException(var6);
}
}

run()方法中完成了spring boot的启动,方法代码比较长,本篇重点放在事件监听上;

SpringApplicationRunListeners listeners = this.getRunListeners(args);

通过getRunListeners(args)获取执行时监听的集合,其代码如下:

    private SpringApplicationRunListeners getRunListeners(String[] args) {
Class[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, new Object[]{this, args}));
}

重点关注


private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args)
这个方法返回
    private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
LinkedHashSet names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}

看 SpringFactoriesLoader.loadFactoryNames(type, classLoader)

   public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName(); try {
Enumeration ex = classLoader != null?classLoader.getResources("META-INF/spring.factories"):ClassLoader.getSystemResources("META-INF/spring.factories");
ArrayList result = new ArrayList(); while(ex.hasMoreElements()) {
URL url = (URL)ex.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
} return result;
} catch (IOException var8) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
}
}

其中

Enumeration ex = classLoader != null?classLoader.getResources("META-INF/spring.factories"):ClassLoader.getSystemResources("META-INF/spring.factories");

通过类加载器获取resources; "META-INF/spring.factories"; 代码会去扫描项目工程中/META-INF下的spring.factories文件,获取org.springframework.boot.SpringApplicationRunListener对应数据

spring-boot-1.3.6.RELEASE中可以找到如下信息

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

即通过SpringApplicationRunListeners listeners = this.getRunListeners(args);最终拿到的是EventPublishingRunListener

(这里还要做一个详细的回顾)

在获取EventPublishingRunListener实例时,执行对应构造方法

    public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.multicaster = new SimpleApplicationEventMulticaster();
Iterator var3 = application.getListeners().iterator(); while(var3.hasNext()) {
ApplicationListener listener = (ApplicationListener)var3.next();
this.multicaster.addApplicationListener(listener);
} }

SpringApplication中的监听器传递给SimpleApplicationEventMulticaster实例multicaster

执行

        SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.started();
    public void started() {
Iterator var1 = this.listeners.iterator(); while(var1.hasNext()) {
SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();
listener.started();
} }

调用EventPublishingRunListener中的started()方法

  public void started() {
this.publishEvent(new ApplicationStartedEvent(this.application, this.args));
}

在该方法中首先创建一个ApplicationStartedEvent事件,将this.application传递过去,因此在执行ApplicationStartedEvent监听时可以获取SpringApplication实例。

执行publishEvent() 方法(这里就开始执行监听事件后调用的方法了)

    private void publishEvent(SpringApplicationEvent event) {
this.multicaster.multicastEvent(event);
}

(这里还要分析一下multicaster接口的初始化)

调用SimpleApplicationEventMulticaster#multicastEvent(event)

    public void multicastEvent(ApplicationEvent event) {
this.multicastEvent(event, this.resolveDefaultEventType(event));
} public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = eventType != null?eventType:this.resolveDefaultEventType(event);
Iterator var4 = this.getApplicationListeners(event, type).iterator(); while(var4.hasNext()) {
final ApplicationListener listener = (ApplicationListener)var4.next();
Executor executor = this.getTaskExecutor();
if(executor != null) {
executor.execute(new Runnable() {
public void run() {
SimpleApplicationEventMulticaster.this.invokeListener(listener, event);
}
});
} else {
this.invokeListener(listener, event);
}
} }

在该代码中需要注意的是for循环中获取监听器集合方getApplicationListeners(event),由于传递的事件为ApplicationStartedEvent,因此该方法需要获取到ApplicationStartedEvent对应的监听器

    protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
Object source = event.getSource();
Class sourceType = source != null?source.getClass():null;
AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType);
AbstractApplicationEventMulticaster.ListenerRetriever retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey);
if(retriever != null) {
return retriever.getApplicationListeners();
} else if(this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader))) {
Object var7 = this.retrievalMutex;
synchronized(this.retrievalMutex) {
retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey);
if(retriever != null) {
return retriever.getApplicationListeners();
} else {
retriever = new AbstractApplicationEventMulticaster.ListenerRetriever(true);
Collection listeners = this.retrieveApplicationListeners(eventType, sourceType, retriever);
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
}
} else {
return this.retrieveApplicationListeners(eventType, sourceType, (AbstractApplicationEventMulticaster.ListenerRetriever)null);
}
}

retrieveApplicationListeners(event, sourceType, null)方法;

    private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, Class<?> sourceType, AbstractApplicationEventMulticaster.ListenerRetriever retriever) {
LinkedList allListeners = new LinkedList();
Object beanFactory = this.retrievalMutex;
LinkedHashSet listeners;
LinkedHashSet listenerBeans;
synchronized(this.retrievalMutex) {
listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans);
} Iterator beanFactory1 = listeners.iterator(); while(beanFactory1.hasNext()) {
ApplicationListener listener = (ApplicationListener)beanFactory1.next();
if(this.supportsEvent(listener, eventType, sourceType)) {
if(retriever != null) {
retriever.applicationListeners.add(listener);
} allListeners.add(listener);
}
} if(!listenerBeans.isEmpty()) {
BeanFactory beanFactory2 = this.getBeanFactory();
Iterator listener2 = listenerBeans.iterator(); while(listener2.hasNext()) {
String listenerBeanName = (String)listener2.next(); try {
Class listenerType = beanFactory2.getType(listenerBeanName);
if(listenerType == null || this.supportsEvent(listenerType, eventType)) {
ApplicationListener listener1 = (ApplicationListener)beanFactory2.getBean(listenerBeanName, ApplicationListener.class);
if(!allListeners.contains(listener1) && this.supportsEvent(listener1, eventType, sourceType)) {
if(retriever != null) {
retriever.applicationListenerBeans.add(listenerBeanName);
} allListeners.add(listener1);
}
}
} catch (NoSuchBeanDefinitionException var13) {
;
}
}
} AnnotationAwareOrderComparator.sort(allListeners);
return allListeners;
}

调用supportsEvent方法判断对应的监听器是否支持指定的事件

    protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, Class<?> sourceType) {
Object smartListener = listener instanceof GenericApplicationListener?(GenericApplicationListener)listener:new GenericApplicationListenerAdapter(listener);
return ((GenericApplicationListener)smartListener).supportsEventType(eventType) && ((GenericApplicationListener)smartListener).supportsSourceType(sourceType);
}

执行 GenericApplicationListenerAdapter#supportsEventType(eventType)

    public boolean supportsEventType(ResolvableType eventType) {
if(this.delegate instanceof SmartApplicationListener) {
Class eventClass = eventType.getRawClass();
return ((SmartApplicationListener)this.delegate).supportsEventType(eventClass);
} else {
return this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType);
}
}

GenericTypeResolver泛型解析工具类功能强大,我们在实际开发中同样可以利用。

至此getApplicationListeners(event)调用完成,大体思路为:遍历所有的监听器,如果该监听器监听的事件为传递的事件或传递事件的父类则表示该监听器支持指定事件。

获取完指定事件对应监听器后,通过Executor执行一个子线程去完成监听器listener.onApplicationEvent(event)方法。

(转)spring boot实战(第三篇)事件监听源码分析的更多相关文章

  1. Spring Boot JDBC:加载DataSource过程的源码分析及yml中DataSource的配置

    装载至:https://www.cnblogs.com/storml/p/8611388.html Spring Boot实现了自动加载DataSource及相关配置.当然,使用时加上@EnableA ...

  2. spring boot actuator工作原理之http服务暴露源码分析

    spring boot actuator的官方文档地址:https://docs.spring.io/spring-boot/docs/current/reference/html/productio ...

  3. spring boot实战(第二篇)事件监听

    http://blog.csdn.net/liaokailin/article/details/48186331 前言 spring boot在启动过程中增加事件监听机制,为用户功能拓展提供极大的便利 ...

  4. spring boot实战(第十三篇)自动配置原理分析

    前言 spring Boot中引入了自动配置,让开发者利用起来更加的简便.快捷,本篇讲利用RabbitMQ的自动配置为例讲分析下Spring Boot中的自动配置原理. 在上一篇末尾讲述了Spring ...

  5. Android View事件分发-从源码分析

    View事件分发-从源码分析 学习自 <Android开发艺术探索> https://blog.csdn.net/qian520ao/article/details/78555397?lo ...

  6. React事件杂记及源码分析

    前提 最近通过阅读React官方文档的事件模块,发现了其主要提到了以下三个点  调用方法时需要手动绑定this  React事件是一种合成事件SyntheticEvent,什么是合成事件?  事件属性 ...

  7. Java的三种代理模式&完整源码分析

    Java的三种代理模式&完整源码分析 参考资料: 博客园-Java的三种代理模式 简书-JDK动态代理-超详细源码分析 [博客园-WeakCache缓存的实现机制](https://www.c ...

  8. Android事件分发机制源码分析

    Android事件分发机制源码分析 Android事件分发机制源码分析 Part1事件来源以及传递顺序 Activity分发事件源码 PhoneWindow分发事件源码 小结 Part2ViewGro ...

  9. Spring Boot的自动配置原理及启动流程源码分析

    概述 Spring Boot 应用目前应该是 Java 中用得最多的框架了吧.其中 Spring Boot 最具特点之一就是自动配置,基于Spring Boot 的自动配置,我们可以很快集成某个模块, ...

随机推荐

  1. IC卡的传输协议(1)-字符传输协议T=0【转】

    转自:http://bbs.ednchina.com/BLOG_ARTICLE_172022.HTM 在异步半双工传输协议中,主要定义了终端为实现传输控制和特殊需要发出的命令及这些命令的处理过程. 在 ...

  2. SuSE Linux10.1 网络设置以及和主机通信end

    设置步骤如下: 1.首先判断VMware Bridge Protocol协议是否已经安装.在本地连接的属性中可以查看. 2.虚拟机设置为bridged 3. 虚拟机-Edit-Virtual Netw ...

  3. C#后台调用js方法无效果,未解决。

    this.Page.ClientScript.RegisterStartupScript(this.Page.GetType(), "", "<script> ...

  4. MySQL 的七种 join

    建表 在这里呢我们先来建立两张有外键关联的张表. CREATE DATABASE db0206; USE db0206; CREATE TABLE `db0206`.`tbl_dept`( `id` ...

  5. Selenium2+python自动化76-Chrome配置加载【转载】

    转至博客:上海-悠悠 一.加载Chrome配置 chrome加载配置方法,只需改下面一个地方,username改成你电脑的名字(别用中文!!!) '--user-data-dir=C:\Users\u ...

  6. SQLAlchemy技术文档(中文版)-下

    10.建立联系(外键) 是时候考虑怎样映射和查询一个和Users表关联的第二张表了.假设我们系统的用户可以存储任意数量的email地址.我们需要定义一个新表Address与User相关联. from ...

  7. Centos7源码编译安装tengine1.5.1

    安装依赖包 yum install pcre pcre-devel openssl openssl-devel gcc make zlib-devel wget -y 下载和创建用户 mkdir /t ...

  8. android9.0请求异常

    抛出异常:CLEARTEXT communication to not permitted by network security policy android 9开始默认不能使用http 1.在re ...

  9. 洛谷 P1583 魔法照片【二级结构体排序】

    题目描述 一共有n(n≤20000)个人(以1--n编号)向佳佳要照片,而佳佳只能把照片给其中的k个人.佳佳按照与他们的关系好坏的程度给每个人赋予了一个初始权值W[i].然后将初始权值从大到小进行排序 ...

  10. 洛谷P3926 SAC E#1 - 一道不可做题 Jelly【模拟/细节】

    P3926 SAC E#1 - 一道不可做题 Jelly [链接]:https://www.luogu.org/problem/show?pid=3926 题目背景 SOL君(炉石主播)和SOL菌(完 ...