Spring Boot(五)启动流程分析

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

学习过springboot的都知道,在Springboot的main入口函数中调用SpringApplication.run(DemoApplication.class,args)函数便可以启用SpringBoot应用程序,跟踪一下SpringApplication源码可以发现,最终还是调用了SpringApplication的动态run函数。

下面以SpringBoot2.0.3.RELEASE为例简单分析一下运行过程。

SpringApplicatiton部分源码:

    1 public static ConfigurableApplicationContext run(Class<?>[] primarySources,
    2       String[] args) {
    3   //创建springapplication对象,调用函数run(args)
    4    return new SpringApplication(primarySources).run(args);
    5 }

上面的源码可以发现还是先创建SpringApplication实例,再调用run方法

第一步 分析 SpringApplication构造函数

SpringApplication构造函数代码如下:

20191017100372\_1.png

     1  public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
     2    this.resourceLoader = resourceLoader;
     3    Assert.notNull(primarySources, "PrimarySources must not be null");
     4    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
     5 
     6   //1:判断web环境
     7    this.webApplicationType = deduceWebApplicationType();
     8 
     9   //2:加载classpath下META-INF/spring.factories中配置的ApplicationContextInitializer
    10    setInitializers((Collection) getSpringFactoriesInstances(
    11          ApplicationContextInitializer.class));
    12   //3:加载classpath下META-INF/spring.factories中配置的ApplicationListener
    13   
    14    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    15   //4:推断main方法所在的类
    16    this.mainApplicationClass = deduceMainApplicationClass();
    17 }

20191017100372\_2.png

具体逻辑分析:

  1. deduceWebApplicationType(), SpringApplication构造函数中首先初始化应用类型,根据加载相关类路径判断应用类型,具体逻辑如下:

20191017100372\_3.png

     1   private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."
     2       + "web.reactive.DispatcherHandler";
     3 
     4   private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."
     5       + "web.servlet.DispatcherServlet";
     6 
     7   private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
     8       "org.springframework.web.context.ConfigurableWebApplicationContext" };
     9 
    10 
    11 
    12    private WebApplicationType deduceWebApplicationType() {
    13   //当类路径中存在REACTIVE_WEB_ENVIRONMENT_CLASS并且不存在MVC_WEB_ENVIRONMENT_CLASS时
    14    if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
    15          && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
    16       return WebApplicationType.REACTIVE;
    17    }
    18   //当加载的类路径中不包含WEB_ENVIRONMENT_CLASSES中定义的任何一个类时,返回标准应用
    19    for (String className : WEB_ENVIRONMENT_CLASSES) {
    20       if (!ClassUtils.isPresent(className, null)) {22          return WebApplicationType.NONE;
    23       }
    24    }
    25   //加载的类路径中包含了WEB_ENVIRONMENT_CLASSES中定义的所有类型则判断为web应用
    26    return WebApplicationType.SERVLET;
    27 }

20191017100372\_4.png

  2. setInitializers初始化属性initializers,加载classpath下META-INF/spring.factories中配置的ApplicationContextInitializer,此处getSpringFactoriesInstances方法入参type=ApplicationContextInitializer.class

20191017100372\_5.png

     1   private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
     2         Class<?>[] parameterTypes, Object... args) {
     3      ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
     4      // Use names and ensure unique to protect against duplicates
     5     // SpringFactoriesLoader.loadFactoryNames()方法将会从calssptah下的META-INF/spring.factories中读取key为//org.springframework.context.ApplicationContextInitializer的值,并以集合形式返回
     6      Set<String> names = new LinkedHashSet<>(
     7            SpringFactoriesLoader.loadFactoryNames(type, classLoader));
     8      //根据返回names集合逐个实例化,也就是初始化各种ApplicationContextInitializer,这些Initializer实际是在Spring上下文ApplicationContext执行refresh前调用
     9      List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
    10          classLoader, args, names);
    11      AnnotationAwareOrderComparator.sort(instances);
    12      return instances;
    13   }

20191017100372\_6.png

  1. setListeners 初始化属性listeners,加载classpath下META-INF/spring.factories中配置的ApplicationListener,此处入参为getSpringFactoriesInstances方法入参type= ApplicationListener.class

20191017100372\_7.png

     1    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
     2         Class<?>[] parameterTypes, Object... args) {
     3      ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
     4      // Use names and ensure unique to protect against duplicates
     5     // SpringFactoriesLoader.loadFactoryNames()方法将会从calssptah下的META-INF/spring.factories中读取key为//org.springframework.context.ApplicationListener的值,并以集合形式返回
     6      Set<String> names = new LinkedHashSet<>(
     7          SpringFactoriesLoader.loadFactoryNames(type, classLoader));
     8     //根据配置,初始化各种ApplicationListener,作用是用来监听ApplicationEvent
     9      List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
    10          classLoader, args, names);
    11      AnnotationAwareOrderComparator.sort(instances);
    12      return instances;
    13   }

20191017100372\_8.png

第二步 分析 SpringApplication中 run方法

SpringApplication的run方法代码如下:

20191017100372\_9.png

     1 public ConfigurableApplicationContext run(String... args) {
     2    StopWatch stopWatch = new StopWatch();
     3    stopWatch.start();
     4    ConfigurableApplicationContext context = null;
     5    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
     6     //设置系统变量java.awt.headless
     7    configureHeadlessProperty();
     8     //1:加载classpath下面的META-INF/spring.factories SpringApplicationRunListener
     9    SpringApplicationRunListeners listeners = getRunListeners(args);
    10     //2:执行所有runlistener的starting方法,实际上发布一个【ApplicationStartingEvent】事件
    11    listeners.starting();
    12    try {
    13       //3:实例化ApplicationArguments对象
    14       ApplicationArguments applicationArguments = new DefaultApplicationArguments(
    15             args);
    16       //4: 创建Environment (web环境 or 标准环境)+配置Environment,主要是把run方法的参数配置到Environment  发布【ApplicationEnvironmentPreparedEvent】事件
    17       ConfigurableEnvironment environment = prepareEnvironment(listeners,
    18             applicationArguments);
    19           configureIgnoreBeanInfo(environment);
    20     //打印banner,SpringBoot启动时,控制台输出的一个歪歪扭扭的很不清楚的Spring几个大字母,也可以自定义,参考博客:http://majunwei.com/view/201708171646079868.html
    21       Banner printedBanner = printBanner(environment);
    22     //5: 根据不同environment实例化context
    23       context = createApplicationContext();
    24     // 异常处理
    25       exceptionReporters = getSpringFactoriesInstances(
    26             SpringBootExceptionReporter.class,
    27             new Class[] { ConfigurableApplicationContext.class }, context);
    28     //6: 上下文相关预处理                  发布【ApplicationPreparedEvent】事件
    29       prepareContext(context, environment, listeners, applicationArguments,
    30             printedBanner);
    31     //7: 执行context的refresh,并且调用context的registerShutdownHook方法
    32       refreshContext(context);
    33     //8:空方法
    34       afterRefresh(context, applicationArguments);
    35       stopWatch.stop();
    36       if (this.logStartupInfo) {
    37          new StartupInfoLogger(this.mainApplicationClass)
    38                .logStarted(getApplicationLog(), stopWatch);
    39       }
    40      //9:执行所有runlisteners的started方法,发布【ApplicationStartedEvent】事件
    41       listeners.started(context);
    42      //10: 遍历执行CommandLineRunner和ApplicationRunner
    43      //如果需要在SpringBoot应用启动后运行一些特殊的逻辑,可以通过实现ApplicationRunner或CommandLineRunner接口中的run方法,该自定义类的run方法会在此处统一调用
    44       callRunners(context, applicationArguments);
    45    }
    46    catch (Throwable ex) {
    47       handleRunFailure(context, ex, exceptionReporters, listeners);
    48       throw new IllegalStateException(ex);
    49    }
    50 
    51    try {
    52       listeners.running(context);
    53    }
    54    catch (Throwable ex) {
    55       handleRunFailure(context, ex, exceptionReporters, null);
    56       throw new IllegalStateException(ex);
    57    }
    58    return context;
    59 }

20191017100372\_10.png

具体分析:

  1. getRunListeners(args) 加载各种SpringApplicationRunListener实例,内部实现也还是通过SpringFactoriesLoader.loadFactoryNames(type, classLoader))实现,加载META-INF/spring.factories中key为org.springframework.boot.SpringApplicationRunListener的值,生成对应实例。

  2. listeners.starting() 执行所有SpringApplicationRunListener的stating方法,发布ApplicationStartedEvent事件,该事件被ApplicationListener类型的listener监听

  3. 实例化ApplicationArguments对象

  4 . 配置环境并发布ApplicationEnvironmentPreparedEvent事件

20191017100372\_11.png

     1    private ConfigurableEnvironment prepareEnvironment(
     2       SpringApplicationRunListeners listeners,
     3       ApplicationArguments applicationArguments) {
     4      // Create and configure the environment
     5    ConfigurableEnvironment environment = getOrCreateEnvironment();
     6   //configureEnvironment配置properties和profiles
     7    configureEnvironment(environment, applicationArguments.getSourceArgs());
     8   // 执行EventPublishingRunListener发布ApplicationEnvironmentPreparedEvent事件,将会被ApplicationListener监听到
     9    listeners.environmentPrepared(environment);
    10   //
    11    bindToSpringApplication(environment);
    12    if (this.webApplicationType == WebApplicationType.NONE) {
    13       environment = new EnvironmentConverter(getClassLoader())
    14             .convertToStandardEnvironmentIfNecessary(environment);
    15    }
    16    ConfigurationPropertySources.attach(environment);
    17    return environment;
    18 }

20191017100372\_12.png

备注:实际上载spring-boot-2.0.3.RELEASE.jar包中,可以发现spring.factories中只配置了一个RunListener: org.springframework.boot.context.event.EventPublishingRunListener

截取EventPublishingRunListener.java部分代码:

20191017100372\_13.png

     1 public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
     2     
     3 
     4      public EventPublishingRunListener(SpringApplication application, String[] args) {
     5        this.application = application;
     6        this.args = args;
     7        this.initialMulticaster = new SimpleApplicationEventMulticaster();
     8       //将SpringApplication实例中的ApplicationListener类型的listeners添加到initialMulticaster,后续执行监听
     9      for (ApplicationListener<?> listener : application.getListeners()) {
    10         this.initialMulticaster.addApplicationListener(listener);
    11      }
    12   }
    13 
    14   // 发布一个ApplicationEnvironmentPreparedEvent事件
    15     @Override
    16     public void environmentPrepared(ConfigurableEnvironment environment) {
    17         //所有被添加到initialMulticaster中的listener都将监听ApplicationEnvironmentPreparedEvent事件
    18         this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
    19                 this.application, this.args, environment));
    20     }
    21 
    22 }

20191017100372\_14.png

  5. 根据environment类型创建ApplicationContext

  6. 上下文相关处理:

20191017100372\_15.png

     1 private void prepareContext(ConfigurableApplicationContext context,
     2       ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
     3       ApplicationArguments applicationArguments, Banner printedBanner) {
     4    context.setEnvironment(environment);
     5   //配置beanNameGenerator和资源加载器
     6    postProcessApplicationContext(context);
     7   //回调所有的ApplicationContextInitializer
     8    applyInitializers(context);
     9   //执行所有SpringApplicationRunListener的contextPrepared方法,触发事件,实际上EventPublishingRunListener中contextPrepared是一个空方法,什么都没执行
    10    listeners.contextPrepared(context);
    11    if (this.logStartupInfo) {
    12       logStartupInfo(context.getParent() == null);
    13       logStartupProfileInfo(context);
    14    }
    15 
    16   //向Spring容器注入springApplicationArguments和springBootBanner
    17    // Add boot specific singleton beans
    18    context.getBeanFactory().registerSingleton("springApplicationArguments",
    19          applicationArguments);
    20    if (printedBanner != null) {
    21       context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
    22    }
    23 
    24    // Load the sources
    25    Set<Object> sources = getAllSources();
    26    Assert.notEmpty(sources, "Sources must not be empty");
    27    load(context, sources.toArray(new Object[0]));
    28   //执行所有SpringApplicationRunListener的contextLoaded方法,下面是EventPublishingRunListener中的contextLoaded
    29    listeners.contextLoaded(context);
    30 }

20191017100372\_16.png

EventPublishingRunListener.java中contextLoaded方法具体实现

20191017100372\_17.png

     1 public void contextLoaded(ConfigurableApplicationContext context) {
     2    for (ApplicationListener<?> listener : this.application.getListeners()) {
     3       if (listener instanceof ApplicationContextAware) {
     4          ((ApplicationContextAware) listener).setApplicationContext(context);
     5       }
     6       context.addApplicationListener(listener);
     7    }
     8   //触发ApplicationPreparedEvent事件,ApplicationListener负责监听
     9    this.initialMulticaster.multicastEvent(
    10          new ApplicationPreparedEvent(this.application, this.args, context));
    11 }

20191017100372\_18.png

  7. 执行context的refresh,并且调用context的registerShutdownHook方法

  8. afterRefresh空方法

  9. 执行所有runlisteners的started方法,发布ApplicationStartedEvent事件

  10. 遍历执行CommandLineRunner和ApplicationRunner

以上。

来源:https://www.cnblogs.com/ashleyboy/p/9563565.html

郑州好的男科医院

郑州不孕不育医院哪家好

郑州男科医院哪里好

郑州妇科医院


来源:[]()

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring Boot(五)启动流程分析

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏