SpringBoot(1)—启动原理之SpringApplication对象的创建

创建SpringApplication对象

SpringBoot版本为 2.1.1.RELEASE

@SpringBootApplication
public class SpringbootDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootDemoApplication.class, args);
    }

这是一个SpringBoot项目的启动类,在主方法内,调用了SpringApplication类的静态run( )方法,并且把启动类的字节码和主方法的参数作为函数入参。

我们以Debug方式来运行代码,可以发现SpringBoot项目在启动时会先创建SpringApplication对象。具体代码如下:

public static ConfigurableApplicationContext run(Class<?> primarySource,
            String... args) {
        return run(new Class<?>[] { primarySource }, args);
    }

public static ConfigurableApplicationContext run(Class<?>[] primarySources,
            String[] args) {
        return new SpringApplication(primarySources).run(args);
    }

public SpringApplication(Class<?>... primarySources) {
        this(null, primarySources);
    }

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }

可以发现,其实在创建SpringApplcation对象时就是把启动类的Class类作为入参调用了SpringApplication类的构造方法。

下面将会重点说明一下这个构造方法:

A: this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
这行代码是将启动类存储到SpringApplicationd对象的primarySources 属性中
B: this.webApplicationType = WebApplicationType.deduceFromClasspath();
这个方法是推断Web应用类型

static WebApplicationType deduceFromClasspath() {
        //存在DispatcherHander但是不存在DispatcherServlet时,推断为WebFlux类型

        if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
                && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
                && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
            return WebApplicationType.REACTIVE;
        }
        // 当Servlet和ConfigurableWebApplicationContext均不存在时,推断为非Web应用
        for (String className : SERVLET_INDICATOR_CLASSES) {
            if (!ClassUtils.isPresent(className, null)) {
                return WebApplicationType.NONE;
            }
        }
        return WebApplicationType.SERVLET;
    }

由于我们只引入了web依赖,所以返回为Servlet

C: setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));

这个方法是用来加载Spring应用上下文初始化器的。

我们debug进入getSpringFactoriesInstances() 中:

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
        return getSpringFactoriesInstances(type, new Class<?>[] {});
    }

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = getClassLoader();
        // Use names and ensure unique to protect against duplicates
        Set<String> names = new LinkedHashSet<>(
                SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

其实这个方法就是通过SpringFactoriesLoader类的loadFactoryNames()方法从类路径下的 "META-INF/spring.factories" 文件中找到所有的 "ApplicationContextInitializer",然后保存到 SpringApplication的initializers属性中。

在下图中,我们可以看到通过getSpringFactoriesInstances()方法,initializers属性中保存了6个初始化器

D: setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
和上个方法类似,只不过这个方法是加载Spring应用事件监听器,但是原理是 一样的,都是利用SpringFactoriesLoader类的loadFactoryNames()方法,只不过这个初始化的对象变成了ApplicationListener

E: this.mainApplicationClass = deduceMainApplicationClass();
这个方法的作用是从多个配置类中找到含有main方法的主配置类

其实这个方法设计的并不严谨,因为在SpringApplication.run(XXX.class)方法中,这个class对象并一定要传入其主配置类,因为我们知道@SpringBootApplication 元标注 @EnableAutoConfiguration,它们的作用基本相同,换言之,这里的class 对象我们可以传入任意标注了@EnableAutoConfiguration、@Configuration两个注解的类。

下一篇文章将会讲解SpringApplicaiton中run()方法的运行。

原文地址:https://www.cnblogs.com/it-cj/p/10909458.html

时间: 2024-08-30 18:10:39

SpringBoot(1)—启动原理之SpringApplication对象的创建的相关文章

springboot之启动原理解析及源码阅读

原文地址:https://www.cnblogs.com/shamo89/p/8184960.html 正文 我们开发任何一个Spring Boot项目,都会用到如下的启动类 @SpringBootApplication //Annotation(注解)定义了(@SpringBootApplication) public class Application { public static void main(String[] args) { //类定义(SpringApplication.run

springboot之启动原理解析

前言 SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏.所以这次博主就跟你们一起一步步揭开SpringBoot的神秘面纱,让它不在神秘. 正文 我们开发任何一个Spring Boot项目,都会用到如下的启动类 @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplica

程序启动原理(四大对象)

程序启动四大对象(UIApplication,AppDelegate) 一.UIApplication 1.什么是UIApplication? •UIApplication对象是应用程序的象征 •每一个应用都有自己的UIApplication对象,而且是单例的 •通过[UIApplication sharedApplication]可以获得这个单例对象 •一个iOS程序启动后创建的第一个对象就是UIApplication对象 •利用UIApplication对象,能进行一些应用级别的操作 2.U

Spring Boot启动原理解析

Spring Boot启动原理解析http://www.cnblogs.com/moonandstar08/p/6550758.html 前言 前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏.所以这次博主就跟你们一起一步步揭开SpringBoot的神秘面纱,让它不在神秘. 正文 我们开发任何一个Spring Boot项目,都会用到如下的启动类 从上面代码可以看出,Annotation定义(@Sp

Spring Boot干货系列:(三)启动原理解析

Spring Boot干货系列:(三)启动原理解析 2017-03-13 嘟嘟MD 嘟爷java超神学堂 前言 前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏.所以这次博主就跟你们一起一步步揭开SpringBoot的神秘面纱,让它不在神秘. 正文 我们开发任何一个Spring Boot项目,都会用到如下的启动类 从上面代码可以看出,Annotation定义(@SpringBootApplicat

【转】Spring Boot干货系列:(三)启动原理解析

前言 前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏.所以这次博主就跟你们一起一步步揭开SpringBoot的神秘面纱,让它不在神秘. 正文 我们开发任何一个Spring Boot项目,都会用到如下的启动类 @SpringBootApplication public class Application { public static void main(String[] args) { Spri

spring boot 启动原理剖析

准备 SpringBoot为我们做的自动配置,确实方便快捷,若不大明白SpringBoot内部启动原理,以后难免会吃亏,所以这次博主就跟你们一起一步步揭开SpringBoot的神秘面纱,让它不再神秘. 旅程开始 开发任何一个SpringBoot项目,都会用到如下启动类: @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(A

微服务 SpringBoot 2.0(四):启动剖析之SpringApplication.run

我以为只是运行了个main方法,可却启动了服务 -- Java面试必修 引言 前一章我们讲解了启动原理的@SpringBootApplication部分,仔细跟着看代码还是很好理解,若需观看@SpringBootApplication注解部分请点击,接下来这章主要讲解run方法运行部分,run方法运行这里很枯燥乏味,所以请带好你的精气神,准备好水,因为实在是太干了. 运行启动 工具 SpringBoot版本:2.0.4 开发工具:IDEA 2018 Maven:3.3 9 JDK:1.8 我们继

SpringBoot启动原理解析

1. 启动任何一个Spring Boot项目,都会用到如下类 @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } 从上面代码可以看出,Annotation定义@SpringBootApplication和类定义SpringApplication.run是关键所在.