1 package com.microservice.framework;
2
3 import org.springframework.boot.SpringApplication;
4 import org.springframework.boot.autoconfigure.SpringBootApplication;
5
6 @SpringBootApplication
7 public class MySpringAplication {
8
9 public void run(String[] args) {
10 SpringApplication sa = new SpringApplication(MySpringAplication.class);
11 sa.run(args);
12 }
13
14 }

SpringBoot启动过程:

1、构建SpringApplication对象

2、执行run()

一、构建SpringApplication对象

1     /**
2 * The application context will load beans from the specified sources
3 */
4 public SpringApplication(Object... sources) {
5 initialize(sources);
6 }

说明:

  • 实例化该类的时候会加载bean到applicationContext中去
  • 这里的入参是MySpringApplication.class这样一个Class<com.microservice.framework.MySpringApplication>对象
    private final Set<Object> sources = new LinkedHashSet<Object>();
private boolean webEnvironment;
private Class<?> mainApplicationClass; private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}

步骤:

  • 将传入的MySpringApplication.class对象放入Set集合
  • 判断是否是web环境
  • 创建ApplicationInitializer列表
  • 初始化ApplicationListener列表
  • 初始化主类mainApplicationClass

1.1、将传入的MySpringApplication.class对象放入Set集合

1.2、判断是否是web环境:

    private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" }; private boolean deduceWebEnvironment() {
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return false;
}
}
return true;
}

说明:通过在classpath中查看是否存在WEB_ENVIRONMENT_CLASSES这个数组中所包含的所有类(实际上就是2个类),如果存在那么当前程序即是一个Web应用程序,反之则不然。

1.3、创建ApplicationContextInitializer列表

 1     private List<ApplicationContextInitializer<?>> initializers;
2
3 public void setInitializers(
4 Collection<? extends ApplicationContextInitializer<?>> initializers) {
5 this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
6 this.initializers.addAll(initializers);
7 }
8
9 private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
10 return getSpringFactoriesInstances(type, new Class<?>[] {});
11 }
12
13 private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
14 Class<?>[] parameterTypes, Object... args) {
15 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
16
17 // Use names and ensure unique to protect against duplicates
18 Set<String> names = new LinkedHashSet<String>(
19 SpringFactoriesLoader.loadFactoryNames(type, classLoader));
20 List<T> instances = new ArrayList<T>(names.size());
21
22 // Create instances from the names
23 for (String name : names) {
24 try {
25 Class<?> instanceClass = ClassUtils.forName(name, classLoader);
26 Assert.isAssignable(type, instanceClass);
27 Constructor<?> constructor = instanceClass.getConstructor(parameterTypes);
28 T instance = (T) constructor.newInstance(args);
29 instances.add(instance);
30 }
31 catch (Throwable ex) {
32 throw new IllegalArgumentException(
33 "Cannot instantiate " + type + " : " + name, ex);
34 }
35 }
36
37 AnnotationAwareOrderComparator.sort(instances);
38 return instances;
39 }

步骤:

  • 调用SpringFactoriesLoader.loadFactoryNames(type, classLoader)来获取所有Spring Factories的名字,(这里是获取了四个ApplicationContextInitializer实现类的全类名,见下边)
  • 为每一个Spring Factories根据读取到的名字创建其对象。(这里创建了4个对象)
  • 将创建好的对象列表排序并返回。

其中,SpringFactoriesLoader.loadFactoryNames(type, classLoader)如下:

 1     /**
2 * The location to look for factories.
3 * <p>Can be present in multiple JAR files.
4 */
5 public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
6
7 /**
8 * Load the fully qualified class names of factory implementations of the
9 * given type from {@value #FACTORIES_RESOURCE_LOCATION}, using the given
10 * class loader.
11 */
12 public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
13 String factoryClassName = factoryClass.getName();
14 try {
15 Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
16 ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
17 List<String> result = new ArrayList<String>();
18 while (urls.hasMoreElements()) {
19 URL url = urls.nextElement();
20 Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
21 String factoryClassNames = properties.getProperty(factoryClassName);
22 result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
23 }
24 return result;
25 }
26 catch (IOException ex) {
27 throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
28 "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
29 }
30 }

META-INF/spring-factories

1 # Application Context Initializers
2 org.springframework.context.ApplicationContextInitializer=\
3 org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
4 org.springframework.boot.context.ContextIdApplicationContextInitializer,\
5 org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
6 org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer

说明:

  • 从所有jar获取所有的META-INF/spring-factories文件。(这里只有spring-boot-1.3.0.RELEASE.jar下有一个)
  • 遍历每一个spring-factories文件,并获取其下key为factoryClass.getName()(这里是入参

    org.springframework.context.ApplicationContextInitializer)的value(这里有以上四个ApplicationContextInitializer实现类)

以上四个类的作用:

至此,设置ApplicationContextInitialize就完成了。

总结:整个setInitializers实际上就是初始化了SpringApplication的属性List<ApplicationContextInitializer<?>> initializers为一个ArrayList列表,该列表中有四个实例:

  • ConfigurationWarningsApplicationContextInitializer的实例
  • ContextIdApplicationContextInitializer的实例
  • DelegatingApplicationContextInitializer实例
  • ServerPortInfoApplicationContextInitializer实例

1.4、初始化ApplicationListener列表

 1     private List<ApplicationListener<?>> listeners;
2
3 /**
4 * Sets the {@link ApplicationListener}s that will be applied to the SpringApplication
5 * and registered with the {@link ApplicationContext}.
6 * @param listeners the listeners to set
7 */
8 public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
9 this.listeners = new ArrayList<ApplicationListener<?>>();
10 this.listeners.addAll(listeners);
11 }

META-INF/spring-factories

 1 # Application Listeners
2 org.springframework.context.ApplicationListener=\
3 org.springframework.boot.builder.ParentContextCloserApplicationListener,\
4 org.springframework.boot.context.FileEncodingApplicationListener,\
5 org.springframework.boot.context.config.AnsiOutputApplicationListener,\
6 org.springframework.boot.context.config.ConfigFileApplicationListener,\
7 org.springframework.boot.context.config.DelegatingApplicationListener,\
8 org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\
9 org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
10 org.springframework.boot.logging.LoggingApplicationListener

以上八个listener的作用如下:

至此,整个setListeners方法结束,初始化了一个包含以上8个ApplicationListener实例的List集合。

1.5、初始化主类mainApplicationClass

 1     private Class<?> mainApplicationClass;
2
3 private Class<?> deduceMainApplicationClass() {
4 try {
5 StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
6 for (StackTraceElement stackTraceElement : stackTrace) {
7 if ("main".equals(stackTraceElement.getMethodName())) {
8 return Class.forName(stackTraceElement.getClassName());
9 }
10 }
11 }
12 catch (ClassNotFoundException ex) {
13 // Swallow and continue
14 }
15 return null;
16 }

说明:获取main()方法所在的主类Class对象,并赋值给SpringApplication的mainApplicationClass属性。

至此,SpringApplication对象初始化完成了。

总结:整个SpringApplication初始化的过程,就是初始化了

  • 一个包含入参MySpringApplication.class的sources的Set<Object>
  • 一个当前环境是否是web环境的boolean webEnvironment
  • 一个包含4个ApplicationContextInitializer实例的List
  • 一个包含8个ApplicationListener实例的List
  • 一个main方法所在的主类的Class对象。

注意:

本文基本参照http://zhaox.github.io/java/2016/03/22/spring-boot-start-flow完成,该文的作者已经解析的很好了,我这里再抄一遍,只是为了加深记忆!!!

http://www.cnblogs.com/java-zhao/p/5540309.html

springboot源码解析 - 构建SpringApplication的更多相关文章

  1. 【附3】springboot源码解析 - 构建SpringApplication

    package com.microservice.framework; import org.springframework.boot.SpringApplication; import org.sp ...

  2. 附3 springboot源码解析 - 构建SpringApplication

    package com.microservice.framework; import org.springframework.boot.SpringApplication; import org.sp ...

  3. SpringBoot源码解析:创建SpringApplication对象实例

    上篇文章SpringBoot自动装配原理解析中,我们分析了SpringBoot的自动装配原理以及@SpringBootApplication注解的原理,本篇文章则继续基于上篇文章中的main方法来分析 ...

  4. SpringBoot源码解析系列文章汇总

    相信我,你会收藏这篇文章的 本篇文章是这段时间撸出来的SpringBoot源码解析系列文章的汇总,当你使用SpringBoot不仅仅满足于基本使用时.或者出去面试被面试官虐了时.或者说想要深入了解一下 ...

  5. springboot源码解析-管中窥豹系列之总体结构(一)

    一.简介 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  6. springboot源码解析-管中窥豹系列之项目类型(二)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  7. springboot源码解析-管中窥豹系列之Runner(三)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  8. springboot源码解析-管中窥豹系列之Initializer(四)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  9. springboot源码解析-管中窥豹系列之aware(六)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

随机推荐

  1. 细究UTF-8,GB2312及ISO-8859-1区别

    各个国家和地区所制定的不同 ANSI 编码标准中,都只规定了各自语言所需的“字符”.比如:汉字标准(GB2312)中没有规定韩国语字符怎样存储.这些 ANSI 编码标准所规定的内容包含两层含义:1. ...

  2. jquery实现select下拉框可输入+联想关联option

    下面代码摘自http://www.oschina.net/question/96791_12832 <script language="javascript" src=&qu ...

  3. 增强学习贪心算法与Softmax算法

    (一) 这个算法是基于一个概率来对探索和利用进行折中:每次尝试时,以概率进行探索,即以均匀概率随机选取一个摇臂,以的概率进行利用,即以这个概率选择当前平均奖赏最高的摇臂(如有多个,则随机选取). 其中 ...

  4. 【BZOJ】【1911】【APIO2010】特别行动队commando

    DP/斜率优化 嗯……第三道斜率优化的题目了. 定义 $s[i]=\sum_{k=1}^{i} x[k] $ 方程:$f[i]=max\{ f[j]+a*(s[i]-s[j])^2+b*(s[i]-s ...

  5. rivers ioi2005 树形dp

    说句实话,写完这道题,很想吐一口血出来,以示我心情的糟糕: 题目很简单,树形dp,正常做30分钟,硬是做了好几个小时,真是伤心. 题解不写了,只是吐个槽,网上没有用背包写的dp,全是左儿子右兄弟写法, ...

  6. MAC下搭建web开发环境

    具体做法,参照此链接:http://mallinson.ca/osx-web-development/ Mac系统本身自带apache和PHP,MySQL可以安装也可以不安装 web开发的IDE可以是 ...

  7. .NET设计模式(8):适配器模式(Adapter Pattern)(转)

    概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就 ...

  8. UML概述(转载)

    UML是一种标准语言,用于指定,可视化,构造和文档的软件系统. UML是OMG在1997年1月提出了创建由对象管理组织(OMG)和UML1.0规范草案. OMG不断努力,使一个真正的行业标准. UML ...

  9. IT架构之IT架构标准——思维导图

    参考: [日] 野村综合研究所系统咨询事业本部. 图解CIO工作指南. 周自恒译 人民邮电出版社,2014

  10. ISIN编码

    国际证券识别编码(ISIN编码)是由国际标准化组织(ISO)制定的证券编码标准,并在<证券及相关金融工具-国际证券识别编码体系>(ISO6166)中正式发布.ISO6166主要规定了ISI ...