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)); }