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

review

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(
				ApplicationContextInitializer.class));
		// [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);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
	
	// From spring A general method for obtaining values in factories to instantiate various objects
	@SuppressWarnings("unchecked")
	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
						.getDeclaredConstructor(parameterTypes);
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				instances.add(instance);
			}
			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
spring.factories

# 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.web.context.ServerPortInfoApplicationContextInitializer

Plus 2:
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener


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

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

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