One of the most exciting things about the Spring ecosystem over the past two or three years has been the Spring Boot framework. Perhaps the name suggests what the framework is designed to do: quickly launch Spring applications. Therefore, Spring Boot applications are essentially applications based on the Spring framework. It is the product of Spring’s best practice of “convention over configuration”, which can help developers build applications based on the Spring ecosystem more quickly and efficiently.


So what’s the magic of Spring Boot? Automatic configuration, startup dependence, Actuator, and CLI are the four most important core features of Spring Boot. Among them, CLI is an optional feature of Spring Boot. Although it is powerful, it also introduces a set of unconventional development model, so this series of articles only focus on the other three features. As the title suggests, this article is the first in a series that opens the door to Spring Boot, focusing on the startup process and how automatic configuration works. To master this core, understanding some of the basics of the Spring framework will help you a lot.


Explore the Spring IoC container


If you have seen the source code for the SpringApplication.run() method, Spring Boot’s lengthy startup process will drive you crazy. At its core, SpringApplication simply extends the startup process of a typical Spring application. A thorough understanding of the Spring container is the key that opens the door to Spring Boot.


1.1. Spring IoC container


The Spring IoC container can be likened to a restaurant. When you go to the restaurant, you usually ask the waiter: Order! As for the ingredients? How to make a dish with ingredients? Maybe you don’t even care. The same goes for the IoC container. You just tell it that you need a bean, and it throws you an instance. You don’t care how the bean is initialized or dependent on other components.


In the same way that restaurants want to make dishes and know the ingredients and recipes for their dishes, IoC containers want to manage individual business objects and their dependencies, and need some way to record and manage this information. The BeanDefinition object takes on this responsibility: Each bean in the container has a corresponding BeanDefinition instance that holds all the necessary information about the bean object, including its class type, whether it is an abstract class, constructors and parameters, other properties, and so on. When a client requests an object from the container, the container returns a full, usable bean instance to the client using this information.


So the ingredients are ready (look at the BeanDefinition of ingredients), start cooking, etc., you also need a recipe, BeanDefinitionRegistry and BeanFactory are this recipe, BeanDefinitionRegistry abstracts the bean registration logic, while BeanFactory abstracts the bean management logic, and the implementation classes of each BeanFactory specifically take on the bean registration and management. The relationship between them is shown below:



BeanFactory, BeanDefinitionRegistry diagram (from: Spring Revelations)

Java advanced learning Q group: 8515318105; Java advanced learning Q group: 8515318105 You can receive the 2019 Java Architect Advanced Learning Materials and BAT interview questions.

DefaultListableBeanFactory as a more general the BeanFactory implementation, it also realizes BeanDefinitionRegistry interface, so it will take the registration management of Bean. As can be seen from the figure, the BeanFactory interface mainly contains getBean, containBean, getType, getAliases and other bean management methods. The BeanDefinitionRegistry interface contains registerBeanDefinition, removeBeanDefinition, getBeanDefinition and other methods for registering and managing BeanDefinitions.


Here is a simple code to simulate how the bottom layer of the BeanFactory works:



While this code is intended to illustrate the underlying workflow of the BeanFactory, it can be more complex, such as bean dependencies defined in external configuration files (XML/Properties) or annotated. The overall workflow of the Spring IoC container can be roughly divided into two phases:


(1) Container startup stage


When the container starts, it loads ConfigurationMetaData in some way. In addition to being fairly straightforward in code, in most cases containers need to rely on some utility classes, such as: BeanDefinitionReader, which parses and analyzes the loaded ConfigurationMetaData and assembs the analyzed information into the corresponding BeanDefinition. Finally, these BeanDefinitions, which hold bean definitions, are registered with the appropriate BeanDefinitionRegistry, and container startup is complete. This stage mainly completes some preparatory work, focuses more on the collection of bean object management information, of course, some verification or auxiliary work is also completed in this stage.


As a simple example, in the past, all beans were defined in an XML configuration file. The following code emulates how BeanFactory loads the bean definition and dependencies from the configuration file:


Java advanced learning Q group: 8515318105; Java advanced learning Q group: 8515318105 You can receive the 2019 Java Architect Advanced Learning Materials and BAT interview questions.

(2) Bean instantiation stage


After the first stage, all bean definitions are registered with BeanDefinitionRegistry as BeanDefinitions. When a request requests an object through the container’s getBean method, or because the dependency container needs to implicitly call getBean, The second-phase activity is triggered: the container first checks to see if the requested object has been instantiated before. If not, the requested object is instantiated and its dependencies are injected based on the information provided by the registered BeanDefinition. When the object is assembled, the container immediately returns it to the requesting method for use.


BeanFactory is simply an implementation of the Spring IoC container that, if not specified, uses a lazy initialization strategy: an object in the container is initialized and dependency injected only when it is accessed. In practical scenarios, we use another type of container more often: ApplicationContext, which is built on top of the BeanFactory. It is a more advanced container, and has all the capabilities of the BeanFactory, as well as support for event listening and internationalization. It manages beans that are all initialized and dependency injected when the container is started.


1.2. Spring container extension mechanism


The IoC container is responsible for managing the life cycle of all beans in the container, and Spring provides different extension points to change the fate of beans at different stages of the bean life cycle. At the start of the container, the BeanFactoryPostProcessor allows you to perform additional operations on the information held by the BeanDefinition registered with the container, such as modifying some properties of the bean definition or adding other information, before the container instantiates the object.


If you want to custom extensions class, usually need to implement org. Springframework. Beans. Factory. Config. The spring BeanFactoryPostProcessor interface, at the same time, Because the container may have more than one spring BeanFactoryPostProcessor, may also need to implement org. Springframework. Core. Ordered interface, to ensure that the spring BeanFactoryPostProcessor in accordance with the order. Spring provides a few Spring BeanFactoryPostProcessor implementation, we accomplished to illustrate the general workflow.


In the XML configuration files of Spring projects, it is common to see many configuration items with placeholder values, and the value represented by the placeholder is configured separately to a separate properties file. This allows centralized management of the configuration scattered in different XML files, and also facilitates operation and maintenance to configure different values for different environments. This very practical function is the accomplished is responsible for the implementation.


When BeanFactory loads all the configuration information in the first phase, the properties of the objects stored in the BeanFactory are still placeholders, such as ${jdbc.mysql.url}. When is accomplished as spring BeanFactoryPostProcessor being applied, it will use the properties in the values in the configuration file to replace the corresponding BeanDefinition placeholder attribute values. When the bean needs to be instantiated, the property values in the bean definition are replaced with the values we configured. Of course, its implementation is more complex than the above description, here only to explain its general working principle, more detailed implementation can refer to its source code.


Similarly, there is the BeanPostProcessor, which exists in the object instantiation phase. Like BeanFactoryPostProcessor, it handles all the qualified and instantiated objects in the container. In a simple comparison, BeanFactoryPostProcessor handles the definition of a bean, while BeanPostProcessor handles the object after the bean has been instantiated. BeanPostProcessor defines two interfaces:



To understand when these two methods execute, take a quick look at the bean lifecycle:



Bean instantiation process (from: Spring Reveal)


PostProcessBeforeInitialization () method with postProcessAfterInitialization () corresponding to figure in the pre processing and post processing method of two steps will be executed. Both methods pass in a reference to the bean object instance, which greatly facilitates the extension of the container’s object instantiation process, where you can do almost anything on the passed instance. Annotations, AOP, and other features are implemented using BeanPostProcessor heavily. For example, if you have a custom annotation, you can implement the BeanPostProcessor interface to determine whether the bean object has the annotation on its head, and if so, You can perform any operation on this bean instance. Isn’t that pretty simple?


As a more common example, it is common to see various Aware interfaces in Spring that inject dependencies specified in the Aware interface definition into the current instance once the object is instantiated. For the most common ApplicationContextAware interface, classes that implement this interface can get an ApplicationContext object. When a container of each object instantiation went down to the BeanPostProcessor pre-processing step, containers will be detected before ApplicationContextAwareProcessor registered to the container, Then call its postProcessBeforeInitialization () method, check and set up the Aware related dependency. Take a look at the code, isn’t it very simple:



In conclusion, this section reviews some of the core contents of the Spring container with you. There is no space to write more, but this section is enough to make it easy for you to understand the principle of The Spring Boot. If you encounter some difficult knowledge in the subsequent learning process, you can easily understand the Spring Boot. Going back to the core knowledge of Spring, it may have unexpected effects. There may be very few Spring Boot Chinese materials, but there are so many Spring Chinese materials and books that there is always something to inspire you.


2. Solid foundation: JavaConfig and common Annotations


2.1, JavaConfig


We know that beans are a very core concept in Spring IOC, and the Spring container is responsible for managing the life cycle of beans. At first, Spring used XML configuration files to describe the definition of beans and their dependencies, but as Spring grew, more and more people complained about this approach because all the business classes of Spring projects were configured in XML files as beans, resulting in a large number of XML files. Making projects complex and difficult to manage.


Later, Guice, a dependency injection framework based on pure Java Annotations, was born. Its performance is significantly better than That of XmL-based Spring, and some people even believe that Guice can completely replace Spring (Guice is only a lightweight IOC framework, which is far from replacing Spring). It was this sense of crisis that prompted Spring and the community to launch and continue to refine the JavaConfig subproject, which describes dependent binding relationships between beans based on Java code and Annotation annotations. For example, here is the definition of a bean using XML configuration:



The Javaconfig.based configuration looks like this:



If there is a dependency between two beans, it would look like this in the XML configuration:



In JavaConfig it looks like this:



You may have noticed that in this example, both beans depend on dependencyService, that is, when bookService is initialized, dependencyService() is called, DependencyService () is also called when initializing otherService. Is there one dependencyService instance or two in the IOC container? I’ll leave that for you to think about and I won’t repeat it here.


2.2, @ ComponentScan


The @ComponentScan annotation corresponds to the < Context: Component-scan > element in the XML configuration form, indicating that component scanning is enabled. Spring automatically scans all beans configured by the annotation and registers them with the IOC container. We can specify the scope that @ComponentScan automatically scans by using properties such as basePackages. If not, the default is to scan from the package of the class that declares @ComponentScan. Because of this, SpringBoot’s boot classes are all in SRC /main/ Java by default.


2.3, @ Import


The @import annotation is used to Import configuration classes, as a simple example:



Now you have another configuration class, for example: MoonUserConfiguration. This configuration class has a bean that depends on the bookService in MoonBookConfiguration. How do you combine the two beans? Use @import:



Note that before 4.2, the @import annotation only supported importing configuration classes, but after 4.2, it supported importing normal classes and registering this class as the definition of a bean in the IOC container.


2.4, @ Conditional


The @Conditional annotation indicates that a bean is not initialized or some configuration is enabled until certain conditions are met. It is typically used on classes identified by @Component, @Service, @Configuration, etc., or on methods marked by @Beans. If an @Configuration class marks @Conditional, then all methods in that class that identify @Bean and related classes imported by the @import annotation will comply with these conditions.


It’s easy to write your own Condition class in Spring. All you have to do is implement the Condition interface and override its matches() method. For example, the following simple conditional class indicates that the JdbcTemplate class is valid only if it exists in the Classpath:



When declaring beans in Java, you can use this custom condition class:



In this example, the MyService bean is created only if the JdbcTemplateCondition class condition is true. That is, MyService is created only if the JdbcTemplate is in the classpath, otherwise the declaration of the bean is ignored.


SpringBoot defines a number of interesting conditions and applies them to the configuration classes that form the basis of SpringBoot’s automatic configuration. SpringBoot uses conditional configuration by defining multiple special conditional annotations and applying them to configuration classes. Some of the conditional annotations provided by SpringBoot are listed below:



2.5, @ ConfigurationProperties and @ EnableConfigurationProperties


When the Value of some property needs to be configured, we typically create a new configuration item in the application.properties file and use the @Value annotation in the bean to obtain the configured Value, as shown in the following code for configuring the data source.



Properties injected with the @Value annotation are generally simple, and can be difficult to maintain if the same configuration is used in multiple places (think: if a configuration is used in dozens of places and you want to change the name, how do you do it?). . For more complex configurations, Spring Boot provides a more elegant implementation with the @ConfigurationProperties annotation. We can rewrite the above code in the following way:



ConfigurationProperties is also handy for more complex configurations, such as the following configuration files:



You can define the following configuration classes to receive these attributes



@ EnableConfigurationProperties annotation built-in support for @ ConfigurationProperties said, the default will correspond to the Properties of the Class as a bean into the IOC container, That is, there is no @Component annotation on the corresponding Properties class. “Spring Boot Configuration loading sequence details” to understand.


Three, cut iron like mud: SpringFactoriesLoader details


The JVM provides three types of loaders: BootstrapClassLoader, ExtClassLoader, and AppClassLoader, which load Java core libraries, extension libraries, and libraries in the application’s CLASSPATH respectively. The JVM loads classes through the parent delegate model, and we can implement our own classloader by inheriting java.lang.classloader.


What is the parental delegation model? When a class loader receives a class loading task, it will first hand it to its parent loader to complete it. Therefore, the final loading task will be passed to the top-level BootstrapClassLoader. Only when the parent loader fails to complete the loading task, it will try to load itself.


One of the benefits of using the parent delegate model is to ensure that different class loaders end up with the same Object, thus ensuring the type safety of the Java core library. For example, loading the java.lang.Object class in the Rt.jar package, regardless of which loader loads the class, The load is ultimately delegated to the top-level BootstrapClassLoader, which ensures that any class loader will end up with the same Object. See the ClassLoader source code for a more intuitive understanding of the parent delegate model:



But the parent delegation model does not solve all classloader problems. For example, Java provides a number of ServiceProvider Interfaces (SPI) that allow third parties to provide implementations for these interfaces. Common SPIs include JDBC, JNDI, JAXP, etc. The interfaces of these SPIs are provided by the core class library, but implemented by a third party. Thus, there is a problem: the interfaces of SPI are part of the Java core library and loaded by BootstrapClassLoader; Java classes implemented by SPI are typically loaded by AppClassLoader. The BootstrapClassLoader cannot find the SPI implementation class because it only loads Java’s core libraries. It also cannot be proxied to AppClassLoader because it is the top-level classloader. In other words, the parental delegation model does not solve this problem.


The ContextClassLoader solves this problem. The name might be mistaken for a new class loader, but it’s actually just a variable of Thread, This object can be set and obtained by setContextClassLoader(ClassLoadercl) and getContextClassLoader(). The default context classloader for Java application threads is AppClassLoader without any Settings. When the core library uses the SPI interface, the class loader passed through uses the thread-context class loader, which can be successfully loaded into the CLASS implemented by SPI. Thread context classloaders are used in many IMPLEMENTATIONS of SPI. In JDBC, however, you might see a more straightforward implementation, such as the loadInitialDrivers() method in JDBC Driver management java.sql.driver, where you can directly see how the JDK loads the Driver:



Thread.currentthread ().getClassLoader() and Thread.currentThread().getContextClassLoader(). The two are the same in most business scenarios, as long as you know what problem it is there to solve, except that the ClassLoader may be different in many of the underlying frameworks.


GetResources (Stringname) is used to read resources from jar files. The following code is used to read resources from jar files: classLoader.getResources (Stringname)



BootstrapClassLoader: BootstrapClassLoader: BootstrapClassLoader: BootstrapClassLoader: BootstrapClassLoader: BootstrapClassLoader: BootstrapClassLoader: BootstrapClassLoader Different class loaders scan jar packages in different paths, just like loading classes, and eventually scan all jar packages to find the resource files that match the conditions.


The class loader’s findResources(name) method iterates through all the JARS it is responsible for loading to find the resource file named name in the JAR, where the resource can be any file, even a.class file, as in the following example, to find array.class:



After running, the following results can be obtained:



Based on the URL of the resource file, the corresponding file can be constructed to read the content of the resource.


You might be surprised to learn that you want to explain the SpringFactoriesLoader. A bunch of classloaders. Take a look at its source code and you will know:



Now that you know about classLoaders, it’s easy to understand this code: Search for all meta-INF/Spring.Factories configuration files from each Jar package in your CLASSPATH, and then parse the properties file to find the configuration with the specified name and return. Note that it’s not just going to the ClassPath path, it’s going to scan all the jars in the ClassPath path, but only in the Jar in the ClassPath path. Take a quick look at the contents of the Spring.Factories file:



Perform loadFactoryNames (EnableAutoConfiguration. Class, after this), get the corresponding to a set of @ the Configuration class, we can through the reflection to instantiate the class and then injected into the IOC container, Finally, the container has a set of Configuration classes in the form of JavaConfig labeled @Configuration.

This is the SpringFactoriesLoader, which is essentially a proprietary extension solution of the Spring framework, similar to SPI. Many of Spring Boot’s core functions based on Spring are based on this.


Another weapon: the Spring container’s event listening mechanism


In the past, the event monitoring mechanism for the graphical interface programming, such as: click on the button, in the text box input operation is called the event, and when the event is triggered when the application to a certain response is applied to monitor the events, and on the server side, event surveillance mechanism more for asynchronous notification and monitoring and exception handling. Java provides two basic classes that implement the event listening mechanism: custom event types extended from java.util.eventobject and listeners of events extended from java.util.EventListener. Consider a simple example: simply monitoring the time spent on a method.


You define the event type first, which is usually done by extending EventObject. As the event occurs, the corresponding state is usually encapsulated in this class:



We can issue a BEGIN event before the method starts executing and an End event after the method ends. Accordingly, the event listener needs to provide methods to handle events received in either case:



The event listener interface actually provides the corresponding handler definition for different event publications. Most importantly, its methods only receive the MethodMonitorEvent parameter, indicating that the listener class is only responsible for listening to and handling the corresponding event. With events and listeners, all that is left is to publish events and let the appropriate listeners listen and process them. Typically, we have an event publisher that acts as an event source and publishes the corresponding event to the corresponding event listener when appropriate:



There are two common concerns for event publishers (event sources) :


  1. Post events when appropriate. The methodMonitor() method in this example is the source of event publication, publishing MethodMonitorEvent events at two points in time before and after the method is executed, and each point in time the published event is passed to the appropriate listener for processing. In the implementation, it is important to note that event publishing is executed sequentially, so that the event listener processing logic should be as simple as possible in order not to affect processing performance.

  2. Management of event listeners. The Publisher class provides methods to register and remove event listeners so that clients can decide if they need to register new listeners or remove one. If there are no provide the remove method, then the registered listener sample will always be MethodMonitorEventPublisher references, even if has been abandoned, is still in the publisher of the list of listeners, which leads to implicit memory leaks.

Event listening mechanism in the Spring container


Spring ApplicationContext container inside of all event types are inherited from org. Springframework. Context. AppliationEvent, In a container all listeners org. Springframework. Context. ApplicationListener interface, and registered in the form of beans in the container. Once applicationEvents and events of their subtypes are published within the container, the ApplicationListener registered with the container processes these events.


You can probably guess what’s going on.


ApplicationEvent inherits from EventObject, and Spring provides some default implementations such as: ContextClosedEvent represents the event type published when the container is about to close, and ContextRefreshedEvent represents the event type published when the container is initialized or refreshed……

The container internally uses ApplicationListener as the EventListener interface definition, which inherits from EventListener. The ApplicationContext container automatically recognizes and loads beans of type EventListener when it is started, and notifies those registered with the container of EventListener once an event is published in the container.


ApplicationContext interface inherits the ApplicationEventPublisher interface, this interface provides voidpublishEvent (ApplicationEventevent) method is defined, it is not hard to see, The ApplicationContext container acts as the event publisher. If they are interested in can check AbstractApplicationContext. PublishEvent (ApplicationEventevent) method source code: ApplicationContext event publishing and management of the listener entrusted to ApplicationEventMulticaster interface implementation class. The container starts, will check the container whether there is called applicationEventMulticaster applicationEventMulticaster object instance. If there is used with the implementation of, without the default initialization of an SimpleApplicationEventMulticaster as implementation.


Finally, if the business we need to publish events within the container, you just need to inject ApplicationEventPublisher rely for it: Implement ApplicationEventPublisherAware interface or ApplicationContextAware interface (Aware interface related content, please review above).


Five, brilliant: reveal the principle of automatic configuration


Typical Spring Boot applications have Boot classes in the SRC /main/ Java root, such as the MoonApplication class:



Where @SpringBootApplication enables component scanning and automatic configuration, springApplication.run is responsible for starting the boot application. @SpringBootApplication is a composite Annotation that combines three useful annotations:



@SpringBootConfiguration is @Configuration, which is a Spring framework annotation that indicates that this class is a JavaConfig Configuration class. While @ComponentScan enables component scanning, which has been explained in detail in the previous section, this section focuses on @EnableAutoConfiguration.


The @enableAutoConfiguration annotation enables Spring Boot to automatically configure the beans you need based on application dependencies, custom beans, whether or not you have a class in your classpath, and so on. Then register with the IOC container. So how does @enableAutoConfiguration figure out your requirements? Let’s start with its definition:



You should focus on @ Import (EnableAutoConfigurationImportSelector. Class), remember, @ Import annotations used to Import the classes, and the definition of the class as a bean registered into the container, Here it will EnableAutoConfigurationImportSelector as the beans into the container, and this class will all eligible @ Configuration Configuration is loaded into the container, see the code:



The “META INF/ Spring. factories” file looks like this:



DataSourceAutoConfiguration, for example, look at how Spring Boot automatically configure:


Java advanced learning Q group: 8515318105; Java advanced learning Q group: 8515318105 You can receive the 2019 Java Architect Advanced Learning Materials and BAT interview questions.

Say it separately:


  • @ ConditionalOnClass ({DataSource. Class, EmbeddedDatabaseType class}) : This configuration is only enabled when the DataSource or EmbeddedDatabaseType class exists in the Classpath, otherwise it is ignored.

  • @ EnableConfigurationProperties (DataSourceProperties. Class) : will the default DataSource configuration class into the IOC container, DataSourceProperties defined as:



@ Import ({Registrar. Class, DataSourcePoolMetadataProvidersConfiguration class}) : Import other additional configuration, take for example DataSourcePoolMetadataProvidersConfiguration:



DataSourcePoolMetadataProvidersConfiguration is a configuration, database connection pool providers that exist in the Classpath org.. Apache tomcat. JDBC. Pool. The DataSource. The class, Tomcat-jdbc connection pools are used, or HikariDataSource. Class is used if you have HikariDataSource in the Classpath.


Here only describes DataSourceAutoConfiguration the tip of the iceberg, but enough to explain the Spring Boot how to make use of condition configuration to realize the automatic configuration. In retrospect, @ EnableAutoConfiguration import EnableAutoConfigurationImportSelector class, The selectImports() of this class gets a large number of configuration classes through the SpringFactoriesLoader, and each configuration class makes decisions based on conditional configuration to implement automatic configuration.


The process is clear, but one big problem is missing:


When to perform EnableAutoConfigurationImportSelector. SelectImports ()? Actually this method can be carried in the process of container startup: AbstractApplicationContext. Refresh (), more details in the next section.


Vi. Boot Boot: The secret of Spring Boot


6.1 SpringApplication Initialization


The whole SpringBoot startup process is divided into two steps: initializing a SpringApplication object and executing the run method of the object. Initialize (Object[] sources); initialize(Object[] sources);


Java advanced learning Q group: 8515318105; Java advanced learning Q group: 8515318105 You can receive the 2019 Java Architect Advanced Learning Materials and BAT interview questions.

The initialization process. The most important thing is to find the spring through SpringFactoriesLoader factories ApplicationContextInitializer and configured in the file ApplicationListener Implementation class names of two interfaces for later construction of corresponding instances. The main purpose of ApplicationContextInitializer is before ConfigurableApplicationContext do refresh, Do further Settings or with ConfigurableApplicationContext instance. ConfigurableApplicationContext inherited from ApplicationContext, its main offer the ability to set the ApplicationContext.


Implement a ApplicationContextInitializer is very simple, because it is only one way, but in most cases we don’t need to customize a ApplicationContextInitializer, even Spring Boot framework, It only registers two implementations by default, since the Spring container is so mature and stable that you don’t have to change it.


The purpose of ApplicationListener is less clear. It is a framework implementation of the Spring framework’s Java event listener mechanism, explained in detail in the Spring Event Listener section above. If you want to add a listener to your Spring Boot application, how do you do it?


Spring Boot provides two ways to add custom listeners:


  • Through SpringApplication. AddListeners (ApplicationListener <? >… Listeners) or SpringApplication. SetListeners (Collection <? extendsApplicationListener<? >> Listeners) two methods to add one or more custom listeners

  • Now that the implementation class for the ApplicationListener has been retrieved from the Spring.Factories in the SpringApplication initialization process, “> < font style =” box-type: none; box-type: none; box-type: none;



So much for the initialization of SpringApplication.


6.2 Spring Boot Startup Process


The whole process of Spring Boot application is wrapped in the springApplication. run method. The whole process is really too long, but essentially it is based on the Spring container startup to do a lot of extensions, according to this idea to look at the source code:


Java advanced learning Q group: 8515318105; Java advanced learning Q group: 8515318105 You can receive the 2019 Java Architect Advanced Learning Materials and BAT interview questions.

(1) through SpringFactoriesLoader find and load all SpringApplicationRunListeners, by calling the starting () method to notify all SpringApplicationRunListeners: The application starts. SpringApplicationRunListeners it is essentially a event publishers, it released at the start of application of different SpringBoot time points different application event type (ApplicationEvent), If any event listeners are interested in these events, they can be received and processed. Remember that during the initialization process, SpringApplication loads a set of ApplicationListeners? The startup process have not found a publish event code, actually have been here in SpringApplicationRunListeners implements.


Simply analyze the implementation process, first look at the source of the SpringApplicationRunListener:



Only one SpringApplicationRunListener implementation class: EventPublishingRunListener. (1) the code can only access to a EventPublishingRunListener instance, let’s take a look at starting () method:



Follow this logic, you can be in (2) the prepareEnvironment () method found in the source of listeners. The environmentPrepared (environment); Namely SpringApplicationRunListener interface of the second method, it is not out you might expect, environmentPrepared () and ApplicationEnvironmentPreparedEvent issued another event. I don’t need to tell you what will happen next.


Create and configure the Environment to be used by the current application. The Environment is used to describe the current operating Environment of the application. It abstractions two aspects of the content: profile and properties. Different environments (eg: production environment, pre-release environment) can use different configuration files, and attributes can be obtained from configuration files, environment variables, command line parameters, and so on. Therefore, when the Environment is ready, resources can be retrieved from the Environment at any time throughout the application.


To sum up, the two lines of code in ② mainly accomplish the following things:


  • Determine the existence of the Environment and does not exist is created (if it is a web project will create StandardServletEnvironment, otherwise create StandardEnvironment)

  • Configure Environment: Configure profile and properties

  • Call SpringApplicationRunListener environmentPrepared () method, notify the event listener: application of the Environment has been ready


③ The SpringBoot application will output something like this when it starts:



If you want to make this your own doodle, you can explore the implementation of the following Banner. I’ll leave that to you.


Create different ApplicationContext containers depending on whether they are Web projects.


5. Create a series of FailureAnalyzer. The process of creating FailureAnalyzer is to obtain all the classes that implement the FailureAnalyzer interface through the SpringFactoriesLoader, and then create the corresponding instances. FailureAnalyzer analyzes faults and provides diagnosis information.


(6) Initialize ApplicationContext.


  • Set the prepared Environment to ApplicationContext

  • Traversal call all ApplicationContextInitializer initialize () method to already created good ApplicationContext for further processing

  • Call SpringApplicationRunListener contextPrepared () method, inform all listeners: ApplicationContext has been ready

  • Load all the beans into the container

  • Call SpringApplicationRunListener contextLoaded () method, inform all listeners: ApplicationContext has finished loading


Call the Refresh () method of the ApplicationContext to complete the final process available to the IoC container. What is a refresh container? To start the container, refer to section 1. So how do you refresh? Look at the following code:



Look at the implementation of this method:



Get all the BeanFactoryPostProcessors to do some extra operations on the container. The BeanFactoryPostProcessor allows us to do some additional operations on the information held by the BeanDefinition registered to the container before the container instantiates the corresponding object. The getBeanFactoryPostProcessors here () method can get 3 Processor:



There aren’t so many BeanFactoryPostProcessor implementation classes. Why are there only three? Because the initialization process access to various ApplicationContextInitializer and ApplicationListener, only the above three made similar to the following:



And then you can enter to PostProcessorRegistrationDelegate. InvokeBeanFactoryPostProcessors () method. This method in addition to traverse the above three spring BeanFactoryPostProcessor processing, can also obtain type for BeanDefinitionRegistryPostProcessor bean: Org. Springframework. Context. The annotation. InternalConfigurationAnnotationProcessor, The corresponding Class for ConfigurationClassPostProcessor. ConfigurationClassPostProcessor for analytical processing various annotations, including: @Configuration, @ComponentScan, @import, @propertysource, @importResource, @Bean. When dealing with @ import annotations, is called “automatic configuration > EnableAutoConfigurationImportSelector. In this section selectImports () to complete the function of automatic configuration. I won’t go into more details here, but if you’re interested, you can refer to Reference 6.


Find out if CommandLineRunner and ApplicationRunner are registered in the current context. If so, run through them.


Pet-name ruby, perform all SpringApplicationRunListener finished () method.


This is the whole startup process of Spring Boot. The core is to add various extension points on the basis of the initialization and startup of the Spring container. These extension points include: ApplicationContextInitializer, ApplicationListener and various spring BeanFactoryPostProcessor and so on. You don’t have to pay too much attention to the details of the process, or even understand them, as long as you understand when and how these extension points work and make them work for you.


The whole startup process is really very complicated, you can check some of the chapters and content in resources, compare the source code, have a look, I think you can figure it out eventually. In short, Spring is the core, understand the Spring container startup process, then the Spring Boot startup process is not a problem.


(after)