Springboot boot source code details, springboot source code details
We will use the following startup classes to develop any Spring Boot project:
@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}
The above Code shows that Annotation (@ SpringBootApplication) and spring application. run) is the most dazzling, so we have to start from the two to unveil the secrets of SpringBoot.
Secrets behind SpringBootApplication
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {...}
Although multiple annotations are used for original information Annotation, only three annotations are important:
- @ Configuration (@ SpringBootConfiguration click it to check whether @ Configuration is applied)
- @ EnableAutoConfiguration
- @ ComponentScan
Therefore, if the following SpringBoot startup class is used, the entire SpringBoot application can still be equivalent to the previous startup class:
@Configuration@EnableAutoConfiguration@ComponentScanpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}
Every time I write these three files, it is quite difficult to write a @ SpringBootApplication. Next we will introduce the three Annotation.
@ Configuration
The @ Configuration here is no stranger to us. It is the @ Configuration used by the Configuration class of Spring Ioc containers in the form of JavaConfig. The SpringBoot community recommends the JavaConfig-based Configuration form. Therefore, the startup class is marked with @ Configuration, which is actually a Configuration class of the IoC container.
Let's take a few simple examples to review the differences between XML and config configuration methods:
-
Expression Level
The XML-based configuration method is as follows:
<? Xml version = "1.0" encoding = "UTF-8"?> <Beans xmlns = "http://www.springframework.org/schema/beans" xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi: schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" default-lazy-init = "true"> <! -- Bean definition --> </beans>
The configuration method based on JavaConfig is as follows:
@ Configurationpublic class MockConfiguration {// bean definition}
Any Java class definition labeled @ Configuration is a JavaConfig Configuration class.
-
Register bean definition Layer
The XML-based configuration format is as follows:
<bean id="mockService" class="..MockServiceImpl"> ...</bean>
The configuration format based on JavaConfig is as follows:
@Configurationpublic class MockConfiguration{ @Bean public MockService mockService(){ return new MockServiceImpl(); }}
The return value of any method labeled @ Bean is registered to the IoC container of Spring as a bean definition. The method name defaults to the id defined by this bean.
-
Express dependency injection Link Layer
To express the dependency between bean and bean, the XML format is generally like this:
<bean id="mockService" class="..MockServiceImpl"> <propery name ="dependencyService" ref="dependencyService" /></bean><bean id="dependencyService" class="DependencyServiceImpl"></bean>
The configuration format based on JavaConfig is as follows:
@Configurationpublic class MockConfiguration{ @Bean public MockService mockService(){ return new MockServiceImpl(dependencyService()); } @Bean public DependencyService dependencyService(){ return new DependencyServiceImpl(); }}
If the definition of a bean depends on other beans, you can directly call the creation method of bean dependencies in the corresponding JavaConfig class.
@ ComponentScan
@ ComponentScan: This annotation is very important in Spring. It corresponds to elements in XML configuration. @ ComponentScan is used to automatically scan and load qualified components (such as @ Component and @ Repository) or bean definition, and finally load these bean definitions into the IoC container.
We can use attributes such as basePackages to fine-grained customization of the scope of @ ComponentScan automatic scanning. If not specified, the default Spring framework implementation will scan the package of the class where @ ComponentScan is declared.
Note: Therefore, the SpringBoot startup class should be placed under the root package, because basePackages is not specified by default.
@ EnableAutoConfiguration
I personally think that @ EnableAutoConfiguration is the most important Annotation. So I will explain it at the end. Do you still remember the Annotation definitions provided by the Spring framework that start with @ Enable? For example, @ EnableScheduling, @ EnableCaching, @ EnableMBeanExport, and so on, the concept of @ EnableAutoConfiguration and the way of doing things are in the same line. To put it simply, with the support of @ Import, collect and register bean definitions related to specific scenarios.
- @ EnableScheduling loads bean definitions related to the Spring scheduling framework to the IoC container through @ Import.
- @ EnableMBeanExport loads the bean definitions related to JMX to the IoC container through @ Import.
@ EnableAutoConfiguration also loads all bean definitions that meet the automatic configuration conditions to the IoC container with the help of @ Import. That's all!
@ EnableAutoConfiguration, as a composite Annotation, defines the key information as follows:
@SuppressWarnings("deprecation")@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(EnableAutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration { ...}
Among them, the most critical is @ Import (EnableAutoConfigurationImportSelector. class), with the help of EnableAutoConfigurationImportSelector, @ EnableAutoConfiguration can help the SpringBoot application load all qualified @ Configuration configurations to the IoC container created and used by the current SpringBoot. Just like a "Octopus"
With the support of Spring framework's original tool class SpringFactoriesLoader, @ EnableAutoConfiguration can achieve smart automatic configuration!
Automatically configure behind-the-scenes hero: SpringFactoriesLoader details
SpringFactoriesLoader is a private extension of the Spring framework. Its main function is to load the configuration from the specified configuration file META-INF/spring. factories.
public abstract class SpringFactoriesLoader { //... public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) { ... } public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { .... }}
When used with @ EnableAutoConfiguration, it provides support for configuration search, that is, according to the complete Class Name of @ EnableAutoConfiguration org. springframework. boot. autoconfigure. enableAutoConfiguration is used as the search Key to obtain the corresponding @ Configuration class.
It is a part of content extracted from the META-INF/spring. factories configuration file in SpringBoot's autoconfigure dependency package, which can be a good description of the problem.
So @ EnableAutoConfiguration automatically configures the magic knight to: search for all the META-INF/spring from classpath. factories configuration file, where org. springframework. boot. autoconfigure. the Configuration items corresponding to EnableutoConfiguration are instantiated as the IoC container Configuration class in the form of JavaConfig labeled @ Configuration through reflection (Java Refletion), and then summarized as one and loaded to the IoC container.
Deep Exploration of SpringApplication Execution Process
The implementation of SpringApplication's run method is the main line of our journey. The main process of this method can be summarized as follows:
1) if we are using the static run method of SpringApplication, first create a SpringApplication object instance in this method, and then call the instance method of the created SpringApplication. When the SpringApplication instance is initialized, it will do a few things in advance:
- Determine whether to create an ApplicationContext type for web applications based on whether a feature class (org. springframework. Web. context. ConfigurableWebApplicationContext) exists in classpath.
- Use SpringFactoriesLoader to search for and load all available ApplicationContextInitializer in the application classpath.
- Use SpringFactoriesLoader to search for and load all available ApplicationListener in the application classpath.
- Deduce and set the definition class of the main method.
2) After the SpringApplication instance Initialization is complete and the settings are complete, the logic of the run method is started. At the beginning of the method execution, it traverses and executes all SpringApplicationRunListener that can be searched and loaded through SpringFactoriesLoader. Call their started () method and tell these SpringApplicationRunListener, "Hey, the SpringBoot application is about to start executing !".
3) Create and configure the Environment to be used by the current Spring Boot application (including configuring PropertySource and Profile to be used ).
4) traverse and call the environmentPrepared () method of all SpringApplicationRunListener and tell them: "The Environment used by the SpringBoot application is ready !".
5) if the showBanner attribute of spring application is set to true, print the banner.
6) determine the type of ApplicationContext to be created for the current SpringBoot application based on whether the user has explicitly set the applicationContextClass type and the inference result of the initialization phase, and then determine whether to add ShutdownHook based on the conditions, determine whether to use the custom BeanNameGenerator and whether to use the custom ResourceLoader. Of course, most importantly, set the prepared Environment to the created ApplicationContext.
7) after ApplicationContext is created, SpringApplication will use Spring-FactoriesLoader again to find and load all available ApplicationContext-Initializer in classpath, and then traverse the initialize (applicationContext) that calls these ApplicationContextInitializer) to further process the created ApplicationContext.
8) traverse and call the contextPrepared () method of all SpringApplicationRunListener.
9) load all the configurations obtained through @ EnableAutoConfiguration and other IoC container configurations to the ready ApplicationContext.
10) traverse and call the contextLoaded () method of all SpringApplicationRunListener.
11) Call the refresh () method of ApplicationContext to complete the last operation available for the IoC container.
12) Check whether CommandLineRunner is registered in the current ApplicationContext. If yes, traverse and execute them.
13) normally, the finished () method of SpringApplicationRunListener is traversed. (If an exception occurs throughout the process, the finished () method of all SpringApplicationRunListener is still called, in this case, the exception information will be passed in for processing)
After the event notification point is removed, the entire process is as follows:
Summary
At this point, the core components of SpringBoot have completed basic parsing. In summary, most of them are some concepts and practices behind the Spring framework, springBoot only solidified and sublimated specific scenarios in advance in terms of these concepts and practices. It is precisely because these solidification makes it easier and more efficient for us to develop applications based on the Sping framework.