springboot源码解析 - 构建SpringApplication

 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

时间: 2024-10-24 02:27:57

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

&gt;&gt;&gt;&gt;&gt; 附3 springboot源码解析 - 构建SpringApplication

package com.microservice.framework; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MySpringAplication { public void run(String[] args) { Spri

附3 spring源码解析 - 构建SpringApplication

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(Str

果子学院Springboot源码解析视频教程

目录: 第1节Spring Boot介绍,源码阅读环境搭建,插件安装[免费观看]00:13:12分钟 第2节Spring源码阅读环境搭建[免费观看]00:19:58分钟 第3节SpringApplication初始化[免费观看]00:20:47分钟 % h8 p; L% a2 b& u' S第4节SpringApplication run方法解析(1)--前3步00:01:29:14:00分钟 第5节SpringApplication run方法解析(2)--第4步(上)00:01:53:39:

【spring-boot 源码解析】spring-boot 依赖管理

关键词:spring-boot 依赖管理.spring-boot-dependencies.spring-boot-parent 问题 maven 工程,依赖管理是非常基本又非常重要的功能,现在的工程越来越庞大,依赖越来越多,各种二方包.三方包太多太多,依赖冲突处理起来真是让人头疼,经常需要涉及到多个地方需要调整. 微信公众号:逸飞兮(专注于java知识领域的源码分析,从源码中理解框架/工具原理.验证CS专业知识) 解决方案 使用统一的依赖管理模块来管理工程中的所有依赖. spring-boot

SpringBoot 源码解析 (五)----- Spring Boot的核心能力 - 自动配置源码解析

在上一篇博客中分析了springBoot启动流程,大体的轮廓只是冰山一角.今天就来看一下springBoot的亮点功能:自动化装配功能. 先从@SpringBootApplication开始.在启动流程章节中,我们讲述了SpringBoot2大致的启动步骤,并进行了源码详解.但是在刷新容器这块并未展开,refreshContext(context);简单的一行代码,背后却做了太多事情.所以为了不喧宾夺主,本篇也尽量选取和注解@SpringBootApplication有关的方法讲解. sprin

附4 springboot源码解析-run

%E5%85%B3%E4%BA%8E%E7%BA%BF%E6%80%A7%E6%A8%A1%E5%9E%8B%E4%BD%A0%E5%8F%AF%E8%83%BD%E8%BF%98%E4%B8%8D%E7%9F%A5%E9%81%93%E7%9A%84%E4%BA%8C%E4%B8%89%E4%BA%8B%E4%BA%8C%E3%80%81%E4%B9%9F%E8%B0%88%E6%B0%91%E4%B8%BB http://auto.315che.com/qichenr50/qa2375806

SpringBoot源码解析:tomcat启动分析

>> spring与tomcat的启动分析:war包形式 tomcat:xml加载规范 1.contex-param: 初始化参数 2.listener-class: contextloaderlister上下文监听 3.servlet-class: 4.filter-class 加载顺序:context - listener - filter - servlet

[SpringBoot]源码分析SpringBoot的异常处理机制

微信号:GitShare微信公众号:爱折腾的稻草如有问题或建议,请在公众号留言[1] 前续 为帮助广大SpringBoot用户达到"知其然,更需知其所以然"的境界,作者将通过SpringBoot系列文章全方位对SpringBoot2.0.0.RELEASE版本深入分解剖析,让您深刻的理解其内部工作原理. 正文 在SpringBoot启动时,会查找并加载所有可用的SpringBootExceptionReporter,其源码如下: //7 使用SpringFactoriesLoader在

SpringApplication对象是如何构建的? SpringBoot源码(八)

注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 本篇接 SpringBoot的启动流程是怎样的?SpringBoot源码(七) 1 温故而知新 温故而知新,我们来简单回顾一下上篇的内容,上一篇我们分析了SpringBoot的启动流程,现将关键步骤再浓缩总结下: 构建SpringApplication对象,用于启动SpringBoot: 从spring.factories配置文件中加载EventPublishingRunListener对象用于在不同的启动阶段发射不同的生命