Spring boot source code in-depth study | startup process analysis


The previous article talked about the general startup process of springboot:
[1] Get listener
[2] Prepare the environment
[3] Console print Banner
[4] Create containers, and create different containers according to different types
[5] Instantiate an exception reporting period instance to record errors during startup.
[6] Prepare the container and do some initialization for the container just created
[7] This step is crucial to refresh the container. Analyze later
[8] Some operations after refreshing the container. Here is an empty method
Here's a detailed analysis.

Instantiation of spring application

In the process of calling the run method, a SpringApplication object will be instantiated. There are several steps, which are described in detail here.

[1] Set the startup environment: non web environment, web environment and reactive environment
[2] Load spring Factories file, get container initializer ApplicationContextInitializer
[3] Load spring Factories file, get listener
[4] Get the class where the main method is currently executed from the current stack

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		// Determine whether the startup class is null
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		// [1] Set the startup environment: non web environment, web environment and reactive environment
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		// [2] The startup process loads spring for the first time Factories file, get container initializer ApplicationContextInitializer
		setInitializers((Collection) getSpringFactoriesInstances(
		// [3] Load spring Factories file, get listener
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		// [4] Get the class where the main method is currently executed from the current stack
		this.mainApplicationClass = deduceMainApplicationClass();

Set the startup environment webapplicationtype deduceFromClasspath()
It determines the current environment according to the existence of relevant bytecode files

	// Judge the project startup environment and set
	static WebApplicationType deduceFromClasspath() {
		// If the DispatcherHandler bytecode file does not exist, and the dispatcherservlet and servletcontainer bytecode files exist, it is a REACTIVE environment
		if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
				&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
				&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		// If the Servlet and ConfigurableWebApplicationContext do not exist in the class file, set the environment to NONE
		for (String className : SERVLET_INDICATOR_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
		// Set the environment to SERVLET
		return WebApplicationType.SERVLET;

Get ApplicationContextInitializer and listener
Read spring.inf in META-INF directory Configuration information in the factories file: ApplicationContextInitializer and listener. This is the first and second reading. The whole spring boot process reads spring Factories use the following three methods

	// From spring General method of obtaining value in factories
	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	// From spring General method of obtaining value in factories
	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		return instances;
	// From spring A general method for obtaining values in factories to instantiate various objects
	private <T> List<T> createSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
			Set<String> names) {
		List<T> instances = new ArrayList<>(names.size());
		for (String name : names) {
			try {
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				Assert.isAssignable(type, instanceClass);
				Constructor<?> constructor = instanceClass
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
			catch (Throwable ex) {
				throw new IllegalArgumentException(
						"Cannot instantiate " + type + " : " + name, ex);
		return instances;

Read spring There are 4 Initializers in factories, plus 2 automatically configured ones, a total of 6

# Application Context Initializers

Plus 2:

Read spring There are 9 listeners in factories, plus 1 automatically configured listener, a total of 10

# Application Listeners

There's another one: org springframework. boot. autoconfigure. BackgroundPreinitializer

Get listener getRunListeners(args) from the core run method

Get spring Listener EventPublishingRunListener corresponding to SpringApplicationRunListener in factories

	// Get the current listener from the core run method
	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));

Tags: Java Spring Boot

Posted by php4om on Tue, 17 May 2022 17:53:28 +0300