springboo流程分析

作者: 二月_春风 | 来源:发表于2017-08-12 17:54 被阅读178次

    首先加入依赖,

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>1.5.4.RELEASE</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <dependencies>
        <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>
    

    书写启动类,

    @SpringBootApplication
    public class Application {
        public static void main(String[] args) {
            //实例化SpringApplication对象,然后调用run方法
            SpringApplication application = new SpringApplication(Application.class);
            ConfigurableApplicationContext context = application.run(args);
    
            //直接调用静态的run方法(内部转换成第一种调用方法)
            //ConfigurableApplicationContext context =SpringApplication.run(Application.class, args);
        }
    }
    

    我们知道启动类启动有二种方式第一种就是
    实例化SpringApplication对象,然后调用run方法

    SpringApplication application = new SpringApplication(Application.class);
    ConfigurableApplicationContext context = application.run(args);
    

    第二种就是

    ConfigurableApplicationContext context =SpringApplication.run(Application.class, args);
    

    然后我们进入第二种启动的run方法中,

    再跟入run方法中

    发现第二种方式就是第一种启动方式。

    然后我们进入SpringApplication的构造函数中,分析一下SpringApplication的构造函数

    /**
       * Create a new {@link SpringApplication} instance. The application context will load
       * beans from the specified sources (see {@link SpringApplication class-level}
       * documentation for details. The instance can be customized before calling
       * {@link #run(String...)}.
       * @param sources the bean sources
       * @see #run(Object, String[])
       * @see #SpringApplication(ResourceLoader, Object...)
       */
    public SpringApplication(Object... sources) {
        initialize(sources);
    }
    

    initialize方法

    private void initialize(Object[] sources) {
       if (sources != null && sources.length > 0) {
           //将启动源加入到一个set集合中
           this.sources.addAll(Arrays.asList(sources));
        }
       //判断是否是web环境
        this.webEnvironment = deduceWebEnvironment();
        //加载所有classpath下面的META-INF/spring.factories的ApplicationContextInitializer
         setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));
        //加载所有classpath下面的META-INF/spring.factories的ApplicationListener
         setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        //推断main方法所在的类,一般是启动类
         this.mainApplicationClass = deduceMainApplicationClass();
    }
    

    sources的定义,将启动源加入到一个set集合中

    private final Set<Object> sources = new LinkedHashSet<Object>();
    

    判断当前的spring项目是否是web环境,判断依据是当前项目中是否存在和加载Servlet和ConfigurableWebApplicationContext

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

    以上是SpringApplication构造函数要做的事情。

    加载所有classpath下面的META-INF/spring.factories的ApplicationContextInitializer调试结果(ApplicationContextInitializer接口是在spring容器刷新之前执行的一个回调函数)


    加载所有classpath下面的META-INF/spring.factories的ApplicationListener(事件监听器)


    run函数的源码分析

    /**
       * Run the Spring application, creating and refreshing a new
       * {@link ApplicationContext}.
       * @param args the application arguments (usually passed from a Java main method)
       * @return a running {@link ApplicationContext}
       */
    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        FailureAnalyzers analyzers = null;
        //设置java.awt.headless系统变量
        configureHeadlessProperty();
        //加载所有classpath下面的META-INF/spring.factories   SpringApplicationRunListener(不同的时间点发送事件通知)
        SpringApplicationRunListeners listeners = getRunListeners(args);
       //执行所有SpringApplicationRunListener的started方法
        listeners.starting();
        try {
            //根据启动args实例化ApplicationArguments对象
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
           //创建environment
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
            applicationArguments);
             //打印Banner,执行到这一步的时候打印banner
            Banner printedBanner = printBanner(environment);
            //初始化applicationContext, 如果是web环境,则实例化AnnotationConfigEmbeddedWebApplicationContext对象,
            //否则实例化AnnotationConfigApplicationContext对象
            context = createApplicationContext();
            analyzers = new FailureAnalyzers(context);
            //进入prepareContext方法中
            prepareContext(context, environment, listeners, applicationArguments,
                printedBanner);
            //执行context的refresh方法,并且调用context的registerShutdownHook方法(这一步执行完成之后,spring容器就完全初始化好了)
            refreshContext(context);
            //回调,获取容器中所有的ApplicationRunner、CommandLineRunner接口,然后排序,依次调用
            afterRefresh(context, applicationArguments);
            //执行所有SpringApplicationRunListener的finished方法
            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);
        }
    }
    
    getRunListeners方法调试

    因为我这边是web环境,所以environment是webenvironment


    配置environment,主要是把run方法的参数配置到environment

    private ConfigurableEnvironment prepareEnvironment(
            SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
      //Create and configure the environment
      ConfigurableEnvironment environment = getOrCreateEnvironment();
      //配置environment,主要是把run方法的参数配置到environment
      configureEnvironment(environment, applicationArguments.getSourceArgs());
      //执行所有SpringApplicationRunListener的environmentPrepared方法
      listeners.environmentPrepared(environment);
      if (!this.webEnvironment) {
        environment = new EnvironmentConverter(getClassLoader())
        .convertToStandardEnvironmentIfNecessary(environment);
       }
     return environment;
    }
    
    private ConfigurableEnvironment getOrCreateEnvironment() {
        if (this.environment != null) {
            return this.environment;
        }
        if (this.webEnvironment) {
            return new StandardServletEnvironment();
        }
            return new StandardEnvironment();
    }
    

    初始化applicationContext, 如果是web环境,则实例化AnnotationConfigEmbeddedWebApplicationContext对象,否则实例化AnnotationConfigApplicationContext对象

    /**
       * Strategy method used to create the {@link ApplicationContext}. By default this
       * method will respect any explicitly set application context or application context
       * class before falling back to a suitable default.
       * @return the application context (not yet refreshed)
       * @see #setApplicationContextClass(Class)
       */
    protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                contextClass = Class.forName(this.webEnvironment
                    ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                    "Unable create a default ApplicationContext, "
                            + "please specify an ApplicationContextClass",
                    ex);
            }
        }
        return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
    }
    

    进入prepareContext方法中

    private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
          //如果beanNameGenerator不为空,就把beanNameGenerator对象注入到context里面去
          postProcessApplicationContext(context);
          //回调所有的ApplicationContextInitializer方法
          applyInitializers(context);
          //执行所有SpringApplicationRunListener的contextPrepared方法
          listeners.contextPrepared(context);
          if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
         }
    
          // Add boot specific singleton beans
          //依次往spring容器中注入:ApplicationArguments,Banner
          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");
         //加载所有的源到context里面去
         load(context, sources.toArray(new Object[sources.size()]));
         //执行所有SpringApplicationRunListener的contextLoaded方法
        listeners.contextLoaded(context);
       }
    

    如果beanNameGenerator不为空,就把beanNameGenerator对象注入到context里面去

    postProcessApplicationContext方法

    回调所有的ApplicationContextInitializer方法

    applyInitializers方法

    执行所有SpringApplicationRunListener的contextPrepared方法

    contextPrepared方法

    加载所有的源到context里面去


    load方法

    执行context的refresh方法,并且调用context的registerShutdownHook方法(这一步执行完成之后,spring容器就完全初始化好了),refresh完成之后容器就启动好了


    图片.png

    回调,获取容器中所有的ApplicationRunner、CommandLineRunner接口,然后排序,依次调用

    afterRefresh方法

    从上面的分析总结运行流程:

    1. 判断是否是web环境
    2. 加载所有classpath下面的META-INF/spring.factories ApplicationContextInitializer
    3. 加载所有classpath下面的META-INF/spring.factories ApplicationListener
    4. 推断main方法所在的类
    5. 开始执行run方法
    6. 设置java.awt.headless系统变量
    7. 加载所有classpath下面的META-INF/spring.factories SpringApplicationRunListener(不同的时间点发送事件通知)
    8. 执行所有SpringApplicationRunListener的started方法
    9. 根据启动args实例化ApplicationArguments对象
    10. 创建environment
    11. 配置environment,主要是把run方法的参数配置到environment
    12. 执行所有SpringApplicationRunListener的environmentPrepared方法
    13. 如果不是web环境,但是是web的environment,则把这个web的environment转换成标准的environment
    14. 打印Banner
    15. 初始化applicationContext, 如果是web环境,则实例化AnnotationConfigEmbeddedWebApplicationContext对象,否则实例化AnnotationConfigApplicationContext对象
    16. 如果beanNameGenerator不为空,就把beanNameGenerator对象注入到context里面去
    17. 回调所有的ApplicationContextInitializer方法
    18. 执行所有SpringApplicationRunListener的contextPrepared方法
    19. 依次往spring容器中注入:ApplicationArguments,Banner
    20. 加载所有的源到context里面去
    21. 执行所有SpringApplicationRunListener的contextLoaded方法
    22. 执行context的refresh方法,并且调用context的registerShutdownHook方法(这一步执行完成之后,spring容器就完全初始化好了)
    23. 回调,获取容器中所有的ApplicationRunner、CommandLineRunner接口,然后排序,依次调用
    24. 执行所有SpringApplicationRunListener的finished方法

    相关文章

      网友评论

        本文标题:springboo流程分析

        本文链接:https://www.haomeiwen.com/subject/hdsikxtx.html