SpringBoot series Introduction
SpringBoot auxiliary source read articles:
Design and implementation IoC container Spring application context and
SpringBoot start the process source code analysis:
- SpringBoot start process analysis (a): SpringApplication class initialization process
- SpringBoot start process analysis (B): SpringApplication run method
- SpringBoot start process analysis (III): prepareContext run method of SpringApplication of () method
- SpringBoot start process analysis (D): initialization process IoC container
- SpringBoot start process analysis (V): SpringBoot implement the principle of automatic assembly
- 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
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();方法。
原创不易,转载请注明出处。
如有错误的地方还请留言指正。