spring boot 2.0 源码分析(二)
在上一章学习了spring boot 2.0启动的大概流程以后,今天我们来深挖一下SpringApplication实例变量的run函数。
先把这段run函数的代码贴出来:
/*** Run the Spring application, creating and refreshing a new* {@link ApplicationContext}.* @param args the application arguments (usually passed from a Java main method)* @return a running {@link ApplicationContext}*/public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();configureHeadlessProperty();SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);configureIgnoreBeanInfo(environment);Banner printedBanner = printBanner(environment);context = createApplicationContext();exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);prepareContext(context, environment, listeners, applicationArguments,printedBanner);refreshContext(context);afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}listeners.started(context);callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}return context;}
我们先来分析其中的第一个关键代码:SpringApplicationRunListeners listeners = getRunListeners(args);
这行代码是获取监听器,我们先跳转到getRunListeners中看一下:
private SpringApplicationRunListeners getRunListeners(String[] args) {Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));}
在这段代码中,我们看到获取监听器,是new出来了一个SpringApplicationRunListeners实例并返回。
再次跳转到SpringApplicationRunListeners的构造函数中,看到一下发生了什么:
SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {this.log = log;this.listeners = new ArrayList(listeners);}
在这个构造函数里,我们看到其只是把接收到的listeners参数,保存到实例变量里,没有过多的操作。
所以,重点是在listeners参数这里,而listeners是通过getSpringFactoriesInstances创建出来的,来看一下getSpringFactoriesInstances函数做了什么事情吧:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = Thread.currentThread().getContextClassLoader();// Use names and ensure unique to protect against duplicatesSet<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));List<T> instances = createSpringFactoriesInstances(type, parameterTypes,classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances;}
在这里我们看到,首先创建了一个classloader,然后用SpringFactoriesLoader.loadFactoryNames(type, classLoader),加载了SpringFactoriesLoader列表。我们来看一下loadFactoryNames里面的代码:
public static List<String> loadFactoryNames(Class<?> factoryClass,@Nullable ClassLoader classLoader) {String factoryClassName = factoryClass.getName();return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());}private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {MultiValueMap result = (MultiValueMap)cache.get(classLoader);if(result != null) {return result;} else {try {Enumeration ex = classLoader != null?classLoader.getResources("META-INF/spring.factories"):ClassLoader.getSystemResources("META-INF/spring.factories");LinkedMultiValueMap result1 = new LinkedMultiValueMap();while(ex.hasMoreElements()) {URL url = (URL)ex.nextElement();UrlResource resource = new UrlResource(url);Properties properties = PropertiesLoaderUtils.loadProperties(resource);Iterator var6 = properties.entrySet().iterator();while(var6.hasNext()) {Entry entry = (Entry)var6.next();List factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));result1.addAll((String)entry.getKey(), factoryClassNames);}}cache.put(classLoader, result1);return result1;} catch (IOException var9) {throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);}}}
通过这里我们看到了其首先加载了META-INF/spring.factories这个配置文件下的所有资源,并放入缓存,然后再获取了org.springframework.context.ApplicationListener定义的资源列表。
小发现:在这里我们发现spring boot自动装配文件的位置。
获取到META-INF/spring.factories这个配置文件下的资源名称列表以后,通过createSpringFactoriesInstances函数创建了SpringFactories的实例。
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {ArrayList instances = new ArrayList(names.size());Iterator var7 = names.iterator();while(var7.hasNext()) {String name = (String)var7.next();try {Class ex = ClassUtils.forName(name, classLoader);Assert.isAssignable(type, ex);Constructor constructor = ex.getDeclaredConstructor(parameterTypes);Object instance = BeanUtils.instantiateClass(constructor, args);instances.add(instance);} catch (Throwable var12) {throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name,var12);}}return instances;}
通过上面的这些代码流转,我们大概搞清楚了listeners是怎么创建出来的。
然后调用了listeners的starting方法。我们先大概地看一下EventPublishingRunListener里面的starting的实现:
public void starting() {this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application,this.args));}
关键代码在这里:
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {ResolvableType type = eventType != null?eventType:this.resolveDefaultEventType(event);Iterator var4 = this.getApplicationListeners(event, type).iterator();while(var4.hasNext()) {ApplicationListener listener = (ApplicationListener)var4.next();Executor executor = this.getTaskExecutor();if(executor != null) {executor.execute(() -> {this.invokeListener(listener, event);});} else {this.invokeListener(listener, event);}}}protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {ErrorHandler errorHandler = this.getErrorHandler();if(errorHandler != null) {try {this.doInvokeListener(listener, event);} catch (Throwable var5) {errorHandler.handleError(var5);}} else {this.doInvokeListener(listener, event);}}
在上面代码中我们看到,starting就是拿到META-INF/spring.factories中定义的资源的实例以后,然后再创建一个线程去启动起来。
通过上面的这些代码我们知道了spring boot会获取META-INF/spring.factories中的资源,并创建这些资源的实例(listeners监听器),然后为每一个监听器创建一个线程启动起来。
篇幅有限, 今天就写到这里吧。有希望一起学习spring boot 2.0源码的同学可以关注我,跟我一起分析spring boot 2.0 源码的实现方式。
作者:Lizongshen
出处:http://www.cnblogs.com/lizongshen/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。
相关文章:

四月青少年编程组队学习(Python一级)Task01
电子学会 软件编程(Python)一级 组队学习 试题来源 青少年软件编程(Python)等级考试试卷(一级)【2020.06】青少年软件编程(Python)等级考试试卷(一级)【202…

hung-yi lee_p1_机器学习是什么
文章目录1.你想找什么样的函式2.怎么告诉机器你想找什么样的函式3.机器怎么找出你想要的函式机器学习就是自动找函式1.你想找什么样的函式 Regression(回归)——想找的函式输出是一个数值 Binary Classification——想找的函式输出是Yes or No(Pos or Neg) Multi-class Classi…

excel导入SQL脚本
exec sp_configure show advanced options,1 reconfigure exec sp_configure Ad Hoc Distributed Queries,1 reconfigure SELECT * INTO tmp_asset FROM OPENROWSET(Microsoft.Jet.OLEDB.4.0, Excel 8.0;Databased:\Excel数据源\资产印章.xls, SELECT * FROM [Sheet1$]) ; 转…

Hadoop hdfs完全分布式搭建教程
本文转载自:https://www.cnblogs.com/ysocean/p/6965197.html 1、安装环境 ①、四台Linux CentOS6.7 系统 hostname ipaddress subnet mask geteway 1、 master 192.168.146.200 255.255…

四月青少年编程组队学习(Python一级)Task02
电子学会 软件编程(Python)一级 组队学习 试题来源 青少年软件编程(Python)等级考试试卷(一级)【2020.06】青少年软件编程(Python)等级考试试卷(一级)【202…

软件测试知识概述
本篇内容关于【1】缺陷(bug)的类型【2】软件测试与SQA的关系【3】软件测试的七项基本原则【4】将软件测试按照不同标准进行分类【5】软件测试过程模型 缺陷(bug)类型 缺陷可能存在于程序文档(软件) 衡量缺陷的唯一标准是是否符合用户需求 ①功能未实现 ②功能实现了但性能有差异…

Hadoop基础-网络拓扑机架感知及其实现
Hadoop基础-网络拓扑机架感知及其实现 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任。 一.网络拓扑结构 在本地网络中,两个节点被称为“彼此近邻”是什么意思?在海量数据处理中,…

批量修改图片以及加水印
好久木有来写点什么了.. 前段时间挺忙的. 今天上来分享一个,这几天我给商城图片加水印的代码吧.因为产品编辑那边是先把图片都上传完成了,所以只能做批量修改图片来完成给所有图片加水印的效果. 类似DX、京东效果. 现在正在开发的B2C项目商城: www.oxozoom.com 也希望更多能…

计算机书集下载链接
http://nic.biti.edu.cn/china-pub/ 我在那下了一本:XML高级编程转载于:https://www.cnblogs.com/dyuan/archive/2004/03/12/2966.html

Microsoft PlayReady DRM
支持在 Web 浏览器中使用加密媒体扩展和 Microsoft PlayReady DRM 本文内容 简介实现方法万维网联合会 (W3C) HTML5 加密媒体扩展 (EME) 为网站引入了一项功能,可在不使用插件的情况下播放受数字版权管理 (DRM) 保护的内容。Windows 8.1 上的 Internet Explorer 11 …

Android Binder概述
背景知识为了更好的理解binder,我们要先澄清一下概念,因为Android 基于Linux内核,我们有必要了解相关知识。进程隔离进程隔离是为了保护操作系统进程之间互不干扰而设计的,这个技术是为了避免进程A写入进程B准备的,进程…

如何用Asp判断你的网站的虚拟物理路径
appath方法 < p align"center" > < font size"4" face"Arial" > < b > The Physical path to this virtual website is: < /b > < /font > < font color"#FF0000" size"6" face"Aria…

总结:SQL的优缺点及与NoSQL对比
SQL在这里指的是关系型数据库,NoSQL指元组存储?

关于成功的因素-----谨记
引导语:一个人生活的环境,对他树立理想和取得成就有着重要的影响。坚忍,是成大事者的共同特征。没有足够的知识储备,一个人难以在工作和事业中取得突破性进展,难以向更高地位发展。 【意志力】 意志力是一种…

最常用的Linux命令
基础命令: (一)cd:进入文件目录 cd / #进入Linux根目录 cd ~ #进入当前用户Home目录,例如root用户 cd .. #进入上一层目录(根目录下没有上一层),…

Delphi数据库开发之TTable篇1
既然是说Delphi中的SQL使用,肯定离不开TDataSet派生出来的DataSet控件(应该说类比较确切些),这里我说的DataSet只是一个大类的称呼,并不是特指实际的TDataSet。在众多控件中其实可以根据如何操作数据分为两类。 其中一…

大型数据库入门
本文介绍大型数据库的概念及其性能决定因素,以及如何优化性能。 什么是大型数据库 -没有一个标准定义 -包含非常多元组(数据库行)的数据库,或者占用非常大的物理文件系统存储空间的数据库。 -占据TB量级的磁盘存储,包含数十亿表行。为什么需…

php安装pear和phpunit
php安装pear和phpunit http://hi.baidu.com/zjutxujie/item/7b08761f922df7476926bb2c 安装pear 下载go-pear.phar,放到phproot/pear目录下,地址http://pear.php.net/go-pear.phar。 管理员身份运行cmd,打开phproot,运行php -d p…

ResNets和Inception的理解
ResNets和Inception的理解 ResNet解析

软件体系结构风格(第5-8课时)
摘要:本文给出软件体系结构风格的定义,并介绍几种常用风格:管道过滤器、数据抽象和面向对象组织,基于事件的隐式调用,分层系统,仓库系统,过程控制环路 软件体系结构风格是什么 描述特定系统组织…

C#中调用Windows API时的数据类型对应关系
C#中调用Windows API时的数据类型对应关系 原文 C#中调用Windows API时的数据类型对应关系 BOOLSystem.Int32 BOOLEANSystem.Int32 BYTESystem.UInt16 CHARSystem.Int16 COLORREFSystem.UInt32 DWORDSystem.UInt32 DWORD32System.UInt32 DWORD64System.UInt64 …

linux下安装db2
最近研究了一下在 ubuntu下安装db2的过程,很快就完成安装,特贴出来供大家讨论,如有错误请多多指教。 注意:安装过程请使用root用户,否则会出现安装失败的情况; 安装过程: 准备工作: …

使用 SAX 解析器简化文档处理程序的编写
http://www-900.ibm.com/developerWorks/cn/xml/x-dochan.shtml有时候 SAX 文档处理程序的代码可能变得非常麻烦、结构性差而且难以维护,尤其是对于那些包含多种不同元素的复杂 XML 结构。本文介绍了应对这种问题的设计策略,从而有助于改进代码的质量和可…

软件体系结构风格之C/S,三层C/S,与BS
C/S的物理结构,其发展历程为(1)->(3)->(2),本文接下来要介绍的C/S为(3),即胖客户端瘦服务器,服务器只管数据库,接下来要介绍的三层C/S为(2),即客户端不胖不瘦。 C/S软件体系结构 背景:基于资源不对等࿰…

HDU-2020
绝对值排序 Problem Description输入n(n<100)个整数,按照绝对值从大到小排序后输出。题目保证对于每一个测试实例,所有的数的绝对值都不相等。 Input输入数据有多组,每组占一行,每行的第一个数字为n,接着是n个整数,…

Java归去来第2集:利用Eclipse创建Maven Web项目
一、前言 如果还不了解剧情,请返回第一集的剧情 Java归去来第1集:手动给Eclipse配置Maven环境 二、利用Eclipse创建Maven Web项目 选择File-New-Project 然后选择Maven-Maven Project 选择项目所在的工作空间目录,然后下一步 选择模…

vs2005什么时候能出正式版
2005试用版本出了很久了,不知道什么时候能出正式版,不会真得要推迟到2005年吧。企盼中…… 转载于:https://www.cnblogs.com/playboy2005/archive/2004/09/22/45563.html

人工神经网络是如何实现存算一体的
摘要 本文内容如题。 下图是一个神经元模型 可以将其抽象为一个数学函数yf(w1x1w2x2…wn*xnb)。也就是这个模型同时涵盖输入输出和进行计算。

编码能力的提升?_20131228
我在编程过程中发现,编码也是一很重要的能力,故花一点时间对其进行思考。 现将思考的成果与各位同行分享;我希望大家在看到以后,能提供宝贵的意见,先谢之! 转载于:https://www.cnblogs.com/uestc999/p/3495…