
earlier, I introduced the core process of SpringBoot startup. This article begins to introduce the details of the specific implementation of SpringBoot startup.

Spring application constructor
first, let's look at how the spring application construction method helps us complete these four core operations.

@SuppressWarnings({ "unchecked", "rawtypes" }) public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { // The passed resourceLoader is null this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); // Record the configuration class name of the main method this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // Record the type of the current project this.webApplicationType = WebApplicationType.deduceFromClasspath(); // Load configuration in spring The type corresponding to the ApplicationContextInitializer in the factories file and instantiate it // The loaded data is stored in the initializers member variable. setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // Initialize the listener and store the loaded listener instance object in the listeners member variable setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // The Class object where the main method is located is pushed back and recorded in the mainApplicationClass object this.mainApplicationClass = deduceMainApplicationClass(); }
1.webApplicationType
first, let's look at how webApplicationType deduces the type of the currently started project. It can be seen from the code that it is derived from the ClassPath through the deduceFromClassPath() method.
this.webApplicationType = WebApplicationType.deduceFromClasspath();
track in to see the code
static WebApplicationType deduceFromClasspath() { if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; } for (String className : SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } } return WebApplicationType.SERVLET; }
before looking at the overall implementation logic, let's look at two contents respectively. The first is that the relevant static variables are used in the above code.

these static variables are actually the full Class paths of some bound Java classes. The second is classutils Ispresent () method. The logic of this method is also very simple, that is, it obtains the Class object of the corresponding type through reflection. If it exists, it returns true, otherwise it returns false

so the logic of this derivation is very clear

2.setInitializers
then let's look at how to implement the loading initializer.
// Load configuration in spring The type corresponding to the ApplicationContextInitializer in the factories file and instantiate it // The loaded data is stored in the initializers member variable. setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
first, all initializers implement the ApplicationContextInitializer interface, that is, load the relevant implementation classes according to this type.
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> { void initialize(C var1); }
the key method for loading is the getspringfactoryesinstances () method. This method loads spring The key in the factories file is org springframework. context. The value of applicationcontextinitializer.
Spring boot project
# Application Context Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ org.springframework.boot.context.ContextIdApplicationContextInitializer,\ org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\ org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
Spring boot autoconfigure project
# Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

the specific loading method is getspringfactiesinstance(). Let's go to view it
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { // Gets the current context class loader ClassLoader classLoader = getClassLoader(); // The obtained extension class name is stored in the set collection to prevent duplication Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // Create extension point instance List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }
first enter springfactoriesloader See the process of loading files in loadfactorynames (type, classloader)

then let's look at the loadSpringFactories method

it will be clearer to check through Debug

through the loadSpringFactories method, we see that spring All the information in the factories file has been loaded into memory, but now we only need to load the data of ApplicationContextInitializer type. At this time, we can check it through the getOrDefault() method.

enter the method to view

then the corresponding instance object will be obtained according to the reflection.


well, in fact, we know that the function of the getspringfactoryesinstances method is to help us get the definitions in meta-inf / spring The in the factories file can be the value of ApplicationContextInitializer. And obtain the instance object by reflection. Then the object information of the instance is stored in the initializers attribute of spring application.

3.setListeners
after the function of setInitializers() method is clear, it is very simple to look at setListeners() method. getSpringFactoriesInstances method is called, but the types passed in are different. That is, meta-inf / spring Different information defined in the factories file.

that is, loading is defined in meta-inf / spring All listeners declared in the factories file, and the obtained listeners are stored in the listeners attribute of spring application.

the default loaded listeners are:

4.mainApplicationClass
finally, let's take a look at how the durucemainapplicaitonclass () method deduces the Class object where the main method is located. Through the source code, we can see that it is implemented through StackTrace.
StackTrace: when learning function calls, we all know that each function has its own stack space. When a function is called, a new stack space is created. Then a function call stack is finally formed through the nested calls of functions
StackTrace is actually a link that records the execution of program methods. It can be presented more intuitively through Debug.

then we can get the relevant call links. For the rest, we only need to get each link to judge whether the executed method name is main.

!