SpringBoot start process analysis (a): SpringApplication class initialization process

SpringBoot series Introduction

SpringBoot auxiliary source read articles:

  Design and implementation IoC container Spring application context and

SpringBoot start the process source code analysis:

  1. SpringBoot start process analysis (a): SpringApplication class initialization process
  2. SpringBoot start process analysis (B): SpringApplication run method
  3. SpringBoot start process analysis (III): prepareContext run method of SpringApplication of () method
  4. SpringBoot start process analysis (D): initialization process IoC container
  5. SpringBoot start process analysis (V): SpringBoot implement the principle of automatic assembly
  6. SpringBoot Start Process Analysis (VI): IoC dependency injection container

The author comments edition SpringBoot source Spring Framework and git Portal: please do not mean little stars

  1. spring-framework-5.0.8.RELEASE
  2. SpringBoot-2.0.4.RELEASE

A, SpringApplication initialization process

  1.1, SpringBoot project mian function

  The main routine of class as shown below, so we usually go to write.

 

  In this class we need to focus on

  • @SpringBootApplication
  • SpringApplication.run()

  About  @SpringBootApplication  notes, later analysis SpringBoot automatic assembly sections will start to analyze.

  We need to focus in this section is  SpringApplication.run ()  method.

  View achieve run () method, as shown in the following code, we find that it is first created  SpringApplication  instance, then call the  SpringApplication  the run () method, we are concerned that this chapter is  SpringApplication  the process of creating the instance.

/**
     * Static helper that can be used to run a {@link SpringApplication} from the
     * specified sources using default settings and user supplied arguments.
     *
     * @param primarySources the primary sources to load
     * @param args           the application arguments (usually passed from a Java main method)
     * @return the running {@link ApplicationContext}
     */
    public static ConfigurableApplicationContext run(Class<?>[] primarySources,
                                                     String[] args) {
        return new SpringApplication(primarySources).run(args);
    }

   

  1.2,  SpringApplication ()  Constructor

  Continue to view source code,  SpringApplication  instantiation process, but first of all is to enter the constructor parameter, and ultimately back to the constructor two parameters.

 1 public SpringApplication(Class<?>... primarySources) {
 2     this(null, primarySources);
 3 }
 4 
 5 @SuppressWarnings({"unchecked", "rawtypes"})
 6 public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
 7     this.resourceLoader = resourceLoader;
 8     Assert.notNull(primarySources, "PrimarySources must not be null");
 9     this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
10     // inferred application type, initializing the corresponding type will later depending on the environment. Are generally used servlet environment 
. 11      the this .webApplicationType = deduceWebApplicationType (); // 2.2.1
 12 is      // initialize ApplicationContextInitializer META-INF / spring.factories configured in the CLASSPATH 
13 is      . SetInitializers ((Collection) getSpringFactoriesInstances (ApplicationContextInitializer class )); 2.2.2 //
 14      // initializes all configured classpath the ApplicationListener 
15      setListeners ((Collection) getSpringFactoriesInstances (the ApplicationListener. class )); 2.2.3 //
 16      // the call stack, the main method of estimation class name 
. 17      the this .mainApplicationClass = deduceMainApplicationClass();
18 }

 

   The method of application of type inference; 1.2.1, deduceWebApplicationType (). SERVLET REACTIVE NONE 

 1 //常量值
 2 private static final String[] WEB_ENVIRONMENT_CLASSES = {"javax.servlet.Servlet",
 3             "org.springframework.web.context.ConfigurableWebApplicationContext"};
 4 
 5 private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."
 6         + "web.reactive.DispatcherHandler";
 7 
 8 private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."
 9         + "web.servlet.DispatcherServlet";
10 
11 Private  static  Final String JERSEY_WEB_ENVIRONMENT_CLASS = "org.glassfish.jersey.server.ResourceConfig" ;
 12 is  
13 is  / ** 
14  * determines the type of application
 15  * NONE: the application is not a web application, the web server should not be used to start the
 16  * SERVLET : the application should run as a servlet-based web application, and should start the embedded servlet web (tomcat) server.
17  * REACTIVE: The application should run as a reactive web application, and should start the embedded reactive web server.
18 is  * @return 
. 19   * / 
20 is  Private WebApplicationType deduceWebApplicationType ({)
 21 is      // must org.springframework.web.reactive.DispatcherHandler presence CLASSPATH 
22 is      IF (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
23             && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)
24             && !ClassUtils.isPresent(JERSEY_WEB_ENVIRONMENT_CLASS, null)) {
25         return WebApplicationType.REACTIVE;
26     }
27     for (String className : WEB_ENVIRONMENT_CLASSES) {
28         if (!ClassUtils.isPresent(className, null)) {
29             return WebApplicationType.NONE;
30         }
31     }
32     //classpath ambient javax.servlet.Servlet presence or org.springframework.web.context.ConfigurableWebApplicationContext 
33 is      return WebApplicationType.SERVLET;
 34 is }

  The return type is WebApplicationType enumerated types,  WebApplicationType  three enumerated, as explained enumeration wherein three annotations

  Specific determination logic is as follows:

  • WebApplicationType.REACTIVE  classpath下存在org.springframework.web.reactive.DispatcherHandler

  • WebApplicationType.SERVLET classpath下存在javax.servlet.Servlet或者org.springframework.web.context.ConfigurableWebApplicationContext

  • WebApplicationType.NONE does not meet the above conditions.

  

  1.2.2、 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); 

  Initialization of the classpath ApplicationContextInitializer META-INF / spring.factories already configured.

. 1  Private <T> Collection <T> getSpringFactoriesInstances (Class <T> type) {
 2      return getSpringFactoriesInstances (type, new new Class <?> [] {});
 . 3  }
 . 4  
. 5  / ** 
. 6  * specified by the META classloader -INF / spring.factories Spring acquire the specified instance of the factory
 . 7  * @param type
 . 8  * @param the parameterTypes
 . 9  * @param args
 10  * @param <T>
 . 11  * @return 
12 is   * / 
13 is  Private<T> Collection <T> getSpringFactoriesInstances (Class <T> type,
 14                                                        Class <?> [] The parameterTypes, ... Object args) {
 15      ClassLoader classLoader = Thread.currentThread () getContextClassLoader ();.
 16      // the Use names UNIQUE to Protect Against Ensure® and Duplicates
 . 17      // , from the META-INF / resource file specified by the spring.factories classLoader
 18 is      // read key is type.getName () of the value 
. 19      the Set <String> = names new new a LinkedHashSet <> (SpringFactoriesLoader.loadFactoryNames (type, classLoader));
 20 is      // Create instance Spring plant
21 is      List <T> = instances createSpringFactoriesInstances (type, The parameterTypes,
 22 is              classLoader, args, names);
 23 is      // (org.springframework.core.annotation.Order order specified annotation) for instance sorting plant Spring 
24      AnnotationAwareOrderComparator.sort (instances );
 25      return instances;
 26 is }

 

  Look  getSpringFactoriesInstances  anything done, to see the source code, there is a very important method  loadFactoryNames ()  This method is very important, this method is provided in the spring-core taken from the META-INF / spring.factories specified class (key) is the same entry method.

Here, access is key to  org.springframework.context.ApplicationContextInitializer  class.

  debug all get to look at what

 

  Said above, is obtained from the META-INF / spring.factories the classpath, we verify:

  发现在上图所示的两个工程中找到了debug中看到的6条结果。 ApplicationContextInitializer 是Spring框架的类, 这个类的主要目的就是在   ConfigurableApplicationContext 调用refresh()方法之前,回调这个类的initialize方法。通过  ConfigurableApplicationContext 的实例获取容器的环境Environment,从而实现对配置文件的修改完善等工作。

  关于怎么实现自定义的 ApplicationContextInitializer 请看我的另一篇专门介绍该类的博客

 

  1.2.3、 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); 

  初始化classpath下 META-INF/spring.factories中已配置的 ApplicationListener。

   ApplicationListener 的加载过程和上面的 ApplicationContextInitializer 类的加载过程是一样的。不多说了,至于 ApplicationListener 是spring的事件监听器,典型的观察者模式,通过 ApplicationEvent 类和 ApplicationListener 接口,可以实现对spring容器全生命周期的监听,当然也可以自定义监听事件。为了梳理springboot的启动流程在这里先不说这个了。后面有时间的话再介绍。

   关于ApplicationContextInitializer的详细介绍请看<SpringBoot之ApplicationContextInitializer的理解和使用>

 二、总结

  关于 SpringApplication 类的构造过程,到这里我们就梳理完了。纵观 SpringApplication 类的实例化过程,我们可以看到,合理的利用该类,我们能在spring容器创建之前做一些预备工作,和定制化的需求。

比如,自定义SpringBoot的Banner,比如自定义事件监听器,再比如在容器refresh之前通过自定义 ApplicationContextInitializer 修改配置一些配置或者获取指定的bean都是可以的。。。

  下一节开始分析SpringBoot容器的构建过程,也就是那个大家多少都看过的run();方法。

   

  原创不易,转载请注明出处。

  如有错误的地方还请留言指正。

Guess you like

Origin www.cnblogs.com/hello-shf/p/10976646.html