SpringBoot启动过程原理

最近这两年springboot突然火起来了,那么我们就来看看springboot的运行原理。

一。springboot的三种启动方式:

1.运行带有main方法的
2.通过命令 Java -jar命令
3.通过spring-boot-plugin的方式

二。springboot 启动时执行方法,有两种方式

第一种方式是用启动时的main方法加载静态方法。

另一种是用初始化注解@postconstruct 执行。(注意点必须void并且参数)。

注意点:【1.@PostConstruct会先被执行,静态方法后被执行。2.如果需要参数的话,只能用静态方法的方式

SpringBoot启动过程原理

从上面代码看,调用了SpringApplication的静态方法run。这个run方法会构造一个SpringApplication的实例,然后再调用这里实例的run方法就表示启动SpringBoot。

具体对象处理流程看下边时序图:

概述:

1.构造SpringApplication的实例(时序图步骤1-2)
2.调用SpringApplication.run()方法(时序图步骤3)
3.构造SpringApplicationRunListeners 实例(时序图步骤3.1.1)
4.发布ApplicationStartedEvent事件(时序图步骤3.1.2)
5.SpringApplicationRunListeners 实例准备环境信息(时序图步骤3.1.3)
6.创建ApplicationContext对象(时序图步骤3.1.4)
7.ApplicationContext实例准备环境信息(时序图步骤3.1.5)
8.刷新的上下文(时序图步骤3.1.6)

2.启动加载过程分析

1.2.1 构造SpringApplication的实例(时序图步骤1-2)
代码

public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
        // 步骤1
        return new SpringApplication(sources).run(args);
}
public SpringApplication(Object... sources) {
        // 步骤1.1
        initialize(sources);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
    private void initialize(Object[] sources) {
        if (sources != null && sources.length > 0) {
            this.sources.addAll(Arrays.asList(sources));
        }
        this.webEnvironment = deduceWebEnvironment();
        //加载META-INF/spring.factories路径ApplicationContextInitializer.class
        getSpringFactoriesInstances(
                ApplicationContextInitializer.class));
        setListeners((Collection)
        //加载META-INF/spring.factories路径ApplicationListener.class
        getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }

分析
⑴.通过ClassLoader.getResources加载META-INF/spring.factories路径下的
文件信息,从中找key为ApplicationContextInitializer.class,并实例化。
⑵.通过ClassLoader.getResources加载META-INF/spring.factories路径下的
文件信息ApplicationListener.class对应类,并实例化。

1.2.2 调用SpringApplication.run()方法(时序图步骤3)
代码:

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        FailureAnalyzers analyzers = null;
        configureHeadlessProperty();
        //  步骤3.1.1
        SpringApplicationRunListeners listeners = getRunListeners(args);
        // 步骤3.1.2
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            // 步骤 3.1.3
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            Banner printedBanner = printBanner(environment);
            // 步骤3.1.4
            context = createApplicationContext();
            analyzers = new FailureAnalyzers(context);
            // 步骤3.1.5
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
            // 步骤3.1.6
            refreshContext(context);
            // 步骤3.1.7
            afterRefresh(context, applicationArguments);
            // 步骤3.1.8
            listeners.finished(context, null);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
            return context;
        }
        catch (Throwable ex) {
            handleRunFailure(context, listeners, analyzers, ex);
            throw new IllegalStateException(ex);
        }
    }
1.2.2 步骤3.1.1:
代码

private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
        // (1)
        return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
                SpringApplicationRunListener.class, types, this, args));
    }
1
2
3
4
5
6
分析
(1). 通过ClassLoader.getResources加载META-INF/spring.factories路径下的
文件信息,从中找key为SpringApplicationRunListener对应类,并实例化。
1.2.3 步骤3.1.2:
代码

public void starting() {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.starting();
        }
    }
    @Override
    @SuppressWarnings("deprecation")
    public void starting() {
        this.initialMulticaster
                .multicastEvent(new ApplicationStartedEvent(this.application, this.args));
    }

分析 
:发布ApplicationStartedEvent事件。

1.2.4 步骤3.1.3:
代码

private ConfigurableEnvironment prepareEnvironment(
            SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        // Create and configure the environment
        // ⑴. 得到环境对象ConfigurableEnvironment
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        // ⑵. 并配置环境信息;对listeners初始化环境属性
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        // ⑶. 发布ApplicationEnvironmentPreparedEvent事件。
        listeners.environmentPrepared(environment);
        if (isWebEnvironment(environment) && !this.webEnvironment) {
            environment = convertToStandardEnvironment(environment);
        }
        return environment;
    }

分析 
⑴. 得到环境对象ConfigurableEnvironment 
⑵. 并配置环境信息;对listeners初始化环境属性。 
⑶. 发布ApplicationEnvironmentPreparedEvent事件。

步骤3.1.4:
分析
创建ApplicationContext对象 ,其中在实例化ApplicationContext子类
AnnotationConfigApplicationContext时,如代码:

public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}

会创建AnnotatedBeanDefinitionReader对象检测是否需要将一下对象放到Spring上下文中

// 用户配置Configuration注解,实现了BeanDefinitionRegistryPostProcessor接口
ConfigurationClassPostProcessor
// 用于配置Autowired注解,实现了MergedBeanDefinitionPostProcessor接口
AutowiredAnnotationBeanPostProcessor
// 用于配置Required注解,实现了MergedBeanDefinitionPostProcessor接口
RequiredAnnotationBeanPostProcessor
// 用于配置JSR-250注解,实现了InstantiationAwareBeanPostProcessor接口
CommonAnnotationBeanPostProcessor
// 用于配置JPA注解
PersistenceAnnotationBeanPostProcessor
// 用于配置EventListener注解,实现了SmartInitializingSingleton接口
EventListenerMethodProcessor
// EventListener工厂
DefaultEventListenerFactory
步骤3.1.5:
代码

private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        // ⑴.对ApplicationContext设置环境变量;
        context.setEnvironment(environment);
        // ⑵.配置属性ResourceLoader和ClassLoader属性;
        postProcessApplicationContext(context);
        // ⑶.循环初始化继承了
        applyInitializers(context);
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }

        // Add boot specific singleton beans
        context.getBeanFactory().registerSingleton("springApplicationArguments",
                applicationArguments);
        if (printedBanner != null) {
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
        }

        // Load the sources
        Set<Object> sources = getSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        load(context, sources.toArray(new Object[sources.size()]));
        listeners.contextLoaded(context);
    }

分析: 
⑴.对ApplicationContext设置环境变量; 
⑵.配置属性ResourceLoader和ClassLoader属性; 
⑶.调用步骤1查询出来ApplicationContextInitializer子类,循环调用initialize()方法。

@SuppressWarnings({ "rawtypes", "unchecked" })
    protected void applyInitializers(ConfigurableApplicationContext context) {
        for (ApplicationContextInitializer initializer : getInitializers()) {
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
                    initializer.getClass(), ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            initializer.initialize(context);
        }
    }

⑷.发布ApplicationPreparedEvent事件。

步骤3.1.6
代码:

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // ⑴.准备刷新的上下文环境
            prepareRefresh();

            // ⑵.初始化BeanFactory
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // ⑶.对BeanFactory进行各种功能填充
            prepareBeanFactory(beanFactory);

            try {
                // ⑷.子类覆盖方法做额外的处理
                postProcessBeanFactory(beanFactory);

                // ⑸.激活各种BeanFactory处理器
                invokeBeanFactoryPostProcessors(beanFactory);

                // ⑹.注册拦截Bean创建的Bean处理,这里只是注册,真正调用是再拿去Bean的时候
                registerBeanPostProcessors(beanFactory);

                // ⑺.为上下文初始化Message源,即不同语言的消息体,国际化处理
                initMessageSource();

                // ⑻.初始化应用消息广播器,并放到applicationEventMulticaster bean中
                initApplicationEventMulticaster();

                // ⑼.留给子类来初始化其他bean
                onRefresh();

                // ⑽.在所有注册的bean中查找Listener bean,注册到消息广播中
                registerListeners();

                // ⑾.初始化剩下的单实例(非惰性)
                finishBeanFactoryInitialization(beanFactory);

                // ⑿.完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset ‘active‘ flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring‘s core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

分析:

⑴.准备刷新的上下文环境
⑵.初始化BeanFactory
⑶.对BeanFactory进行各种功能填充
⑷.子类覆盖方法做额外的处理
⑸.激活各种BeanFactory处理器
⑹.注册拦截Bean创建的Bean处理,这里只是注册,真正调用是再拿去Bean的时候
⑺.为上下文初始化Message源,即不同语言的消息体,国际化处理
⑻.初始化应用消息广播器,并放到applicationEventMulticaster bean中
⑼.留给子类来初始化其他bean
⑽.在所有注册的bean中查找Listener bean,注册到消息广播中
⑾.初始化剩下的单实例(非惰性)
⑿.完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人

总结:

Spring 是一个“引擎” 
Spring MVC 是基于 Spring 的一个 MVC 框架 
Spring Boot 是基于 Spring4 的条件注册的一套快速开发整合包 

Spring 最初利用“工厂模式”( DI )和“代理模式”( AOP )解耦应用组件,并构建了一些列功能组件。大家觉得挺好用,于是按照 MVC 框架模式,(用Spring 解耦的组件)搞了一个MVC用来开发 web 应用也就是( SpringMVC )。然后有发现每次开发都要搞很多依赖,写很多样板代码很麻烦,于是搞了一些懒人整合包( starter ),这套就是 Spring Boot 。  
spring 框架有超多的延伸产品例如 boot security jpa etc... 但它的基础就是 spring 的 ioc 和 aop ioc 提供了依赖注入的容器 aop 解决了面向横切面的编程 然后在此两者的基础上实现了其他延伸产品的高级功能 Spring MVC 呢是基于 Servlet 的一个 MVC 框架 主要解决 WEB 开发的问题 因为 Spring 的配置太复杂了 各种 XML JavaConfig hin 麻烦 于是懒人改变世界推出了 Spring boot 约定优于配置 简化了 spring 的配置流程 简单谈下自己的理解   以上来自度娘,感觉和自己的理解相当。直接拿来用,占个坑。以后完善。

springApplication可以读取不同种类的源文件:

  • 类- java类由AnnotatedBeanDefinitionReader加载。
  • Resource - xml资源文件由XmlBeanDefinitionReader读取, 或者groovy脚本由GroovyBeanDefinitionReader读取
  • Package - java包文件由ClassPathBeanDefinitionScanner扫描读取。
  • CharSequence - 字符序列可以是类名、资源文件、包名,根据不同方式加载。如果一个字符序列不可以解析程序到类,也不可以解析到资源文件,那么就认为它是一个包。

原文地址:https://www.cnblogs.com/huojg-21442/p/10489792.html

时间: 2024-10-26 08:16:42

SpringBoot启动过程原理的相关文章

Tomcat启动过程原理详解 -- 非常的报错:涉及了2个web.xml等文件的加载流程

Tomcat启动过程原理详解 发表于: Tomcat, Web Server, 旧文存档 | 作者: 谋万世全局者 标签: Tomcat,原理,启动过程,详解 基于Java的Web 应用程序是 servlet.JSP 页面.静态页面.类和其他资源的集合,它们可以用标准方式打包,并运行在来自多个供应商的多个容器(诸如tomcat).Web 应用程序存在于结构化层次结构的目录中,该层次结构是由 Java Servlet 规范定义的.Web 应用程序的根目录包含直接存储或存储在子文件夹中的所有公共资源

springboot启动过程(1)-初始化

1   springboot启动时,只需要调用一个类前面加了@SpringBootApplication的main函数,执行SpringApplication.run(DemoApplication.class, args)即可,这里初始化了一个SpringApplication实例,然后调用run启动springboot.run方法中,调用了initialize,如下 @SuppressWarnings({ "unchecked", "rawtypes" }) p

springboot启动过程(3)-refresh方法

1  springboot在启动的时候,会调用run方法,创建环境设置spring容器,其中包含refresh方法,完成配置类解析,各种beanFactoryPostProcess和beanPostProcessor注册,web内置容器构造,国际化配置初始化等,refresh调用了父类AbstractApplicationContext的refresh方法如下. public void refresh() throws BeansException, IllegalStateException

Tomcat启动过程原理详解

基于Java的Web 应用程序是 servlet.JSP 页面.静态页面.类和其他资源的集合,它们可以用标准方式打包,并运行在来自多个供应商的多个容器.Web 应用程序存在于结构化层次结构的目录中,该层次结构是由 Java Servlet 规范定义的.Web 应用程序的根目录包含直接存储或存储在子文件夹中的所有公共资源,比如图像.HTML 页面等.构成:Web应用由Web组件(一组Java类库).html文件,静态资源文件(如图像).帮助类和库组成. 1 – Tomcat Server的组成部分

springboot启动过程(2)-run方法

1 springApplication的run run方法主要是用于创造spring容器ConfigurableApplicationContext对象. public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); // 构造一个任务执行观察器 stopWatch.start(); // 开始执行,记录开始时间 ConfigurableApplicationC

springboot启动配置原理之二(运行run方法)

public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; configureHeadlessProperty(); //获取SpringApplication

linux启动过程原理

启动第一步--加载BIOS 当你打开计算机电源,计算机会首先加载BIOS信息,BIOS信息是如此的重要,以至于计算机必须在最开始就找到它.这是因为BIOS中包含了CPU的相关信息.设备启动顺序信息.硬盘信息.内存信息.时钟信息.PnP特性等等.在此之后,计算机心里就有谱了,知道应该去读取哪个硬件设备了. 启动第二步--读取MBR 众所周知,硬盘上第0磁道第一个扇区被称为MBR,也就是Master Boot Record,即主引导记录,它的大小是512字节,别看地方不大,可里面却存放了预启动信息.

(七)SpringBoot启动配置原理

几个重要的事件回调机制 ApplicationContextInitializer SpringApplicationRunListener ApplicationRunner CommandLineRunner 启动流程 1.创建SpringApplication对象 1 initialize(sources); 2 private void initialize(Object[] sources) { 3 //保存主配置类 4 if (sources != null && source

SpringBoot启动过程:

SpringApplication 的run()方法探秘 原文:https://juejin.im/post/5b8f05a5f265da43296c6102 原文地址:https://www.cnblogs.com/lyqf/p/11100364.html