zoukankan      html  css  js  c++  java
  • 2. Spring Boot项目启动原理初探

    SpringBoot从宏观上说,就是对spring容器进行了一层包装。它内部的入口是利用 SpringApplication类的static的 run 方法进行启动的,调用的图:

      

    上图中的这些方法都位于org.springframework.boot.SpringApplication这个类中,由此可见SpringApplication这个类在springboot框架中的作用。

    //调用示例:

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

    SpringApplication类提供了两个static的run方法:

    public static ConfigurableApplicationContext run(Object source, String... args) {
            return run(new Object[] { source }, args);
    }
    
    
    public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
            return new SpringApplication(sources).run(args);
    }

    上面两个方法其实就是一个,最终都会创建一个SringApplication实例,在构造时会处理传入的 sources 参数,而且这souces类可以是多个,调用的方式还可以这样:

    public static void main(String[] args) throws Exception {

            Class<?>[] primarySources = new Class<?>[] { Examples.class , Examples1.class } ;
      SpringApplication.run( primarySources , args);
    }

    SpringApplication构造方法如下:

    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();
    
      //用来查找每个jar和类路径下的/META-INF/spring.factories文件,并获取其中的特定接口的配置的
      setInitializers((Collection) getSpringFactoriesInstances( 
      ApplicationContextInitializer.class)); //找出每个jar和类路径下的/META-INF/spring.factories文件中配置的ApplicationContextInitializer类
      setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    
      this.mainApplicationClass = deduceMainApplicationClass(); //推断出带有main方法的运行类 
    }

    上面的代码通过构造完成初始化之后,紧接着就是调用SpringApplication类的实例 run方法,代码如下:

    public ConfigurableApplicationContext run(String... args) {
        //StopWatch作用是用来统计spring实例运行时间
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            
            //ConfigurableApplicationContext接口提供了对Spring容器的配置功能
            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);
                // 1. 会执行ApplicationContextInitializer接口进行初始化工作
                // 2. 对外发布监听事件
                // 3. 优先创建有特定作用的单例bean
                // 4. 把带有main方法的主类作为bean的配置源,并从配置源中加载bean信息到容器中
                prepareContext(context, environment, listeners, applicationArguments,
                        printedBanner);
                //spring容器的生命周期处理,该方法完成后单例bean实例就创建了
                refreshContext(context);
                afterRefresh(context, applicationArguments);
                stopWatch.stop();
                if (this.logStartupInfo) {
                    new StartupInfoLogger(this.mainApplicationClass)
                            .logStarted(getApplicationLog(), stopWatch);
                }
                //对外发布监听事件
                listeners.started(context);
                //我们在开发中可能会有这样的情景。需要在容器启动的时候执行一些内容。比如读取配置文件,数据库连接之类的。SpringBoot给我们提供了两个接口来帮助我们实现这种需求。这两个接口分别为CommandLineRunner和ApplicationRunner。他们的执行时机为容器启动完成的时候。
                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;
        }

    至此,SpringApplication的实例run方法执行完成,该方法主要是完成spring容器的创建和启动

  • 相关阅读:
    BZOJ 3527: [Zjoi2014]力 [快速傅里叶变换]
    BZOJ 2194 [快速傅里叶变换 卷积]
    BZOJ 2179 [快速傅里叶变换 高精度乘法]
    [快速傅立叶变换&快速傅里叶变换]【旧 手写笔记】
    CF 235C. Cyclical Quest [后缀自动机]
    BZOJ 1396&&2865 识别子串[后缀自动机 线段树]
    BZOJ 2780: [Spoj]8093 Sevenk Love Oimaster [广义后缀自动机]
    BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡 [广义后缀自动机 Trie]
    BZOJ 2806: [Ctsc2012]Cheat [广义后缀自动机 单调队列优化DP 二分]
    BZOJ 3473: 字符串 [广义后缀自动机]
  • 原文地址:https://www.cnblogs.com/hzhuxin/p/7737945.html
Copyright © 2011-2022 走看看