springboo流程分析

首先加入依赖,


    
        
            org.springframework.boot
            spring-boot-dependencies
            1.5.4.RELEASE
            import
            pom
        
    



    
    org.springframework.boot
    spring-boot-starter
    

书写启动类,

@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方法中,

springboo流程分析_第1张图片

再跟入run方法中

springboo流程分析_第2张图片

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

然后我们进入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 sources = new LinkedHashSet();
 
 

判断当前的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容器刷新之前执行的一个回调函数)


springboo流程分析_第3张图片

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


springboo流程分析_第4张图片

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);
    }
}
springboo流程分析_第5张图片
getRunListeners方法调试

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


springboo流程分析_第6张图片

配置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 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里面去

springboo流程分析_第7张图片
postProcessApplicationContext方法

回调所有的ApplicationContextInitializer方法

springboo流程分析_第8张图片
applyInitializers方法

执行所有SpringApplicationRunListener的contextPrepared方法

contextPrepared方法

加载所有的源到context里面去


springboo流程分析_第9张图片
load方法

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


springboo流程分析_第10张图片
图片.png

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

springboo流程分析_第11张图片
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流程分析)