Springboot version 2.1.1

What does the SpringApplication instance do?

public SpringApplication(ResourceLoader resourceLoader, Class<? >... PrimarySources) {// Loader, usually null this.resourceLoader = resourceLoader; Assert.notNull(primarySources,"PrimarySources must not be null"); This. primarySources = new LinkedHashSet<>(arrays.asList (primarySources)); / / web environment is a servlet or reactive or none enclosing webApplicationType = webApplicationType. DeduceFromClasspath (); / / get all springboot projects below the meta-inf/spring. ApplicationContextInitializer factoriessetInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		setApplicationListener for meta-INF/Spring.Factories under all Springboot projects getSpringFactoriesInstances(ApplicationListener.class)); / / this practice is a little meaning, springboot create an exception, through the exception stack to implement this. The main method of class mainApplicationClass = deduceMainApplicationClass (); }Copy the code

The above Outlines what SpringBoot instantiation does, so let’s break it down a little bit

How to determine whether the current Web environment is servlet, Reactive or None

Web projects are often servlet-based, and this is one of the new features of spring5: reactive does not rely on servlets. The package structure of reactive is similar to that of springmvc

WebApplicationType.deduceFromClasspath
Copy the code
static WebApplicationType deduceFromClasspath() {/ / if the project have orgspringframework. Web. Reactive. DispatcherHandler class / / and no org. Anyone. The jersey. The servlet. The ServletContainer and / / org. Springframework. Web. Servlet. DispatcherServlet it as an environment that is reactive current web environmentif(ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && ! ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && ! ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {returnWebApplicationType.REACTIVE; } / /"Javax.mail. Servlet. Servlet and org. Springframework. Web. Context. ConfigurableWebApplicationContext as long as there is a class does not exist as none, Not web project for (String className: SERVLET_INDICATOR_CLASSES) {if (! ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; }} / / web environment is servlet return WebApplicationType. Servlet. }Copy the code

The summary is to determine whether reactive and servlet-related classes are dependent on the project

Obtain all springboot projects below the meta-inf/spring. ApplicationContextInitializer factories
// Springboot initialization codesetInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
Copy the code
	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<? >[] parameterTypes, Object... Args) {// getClassLoader ClassLoader ClassLoader = getClassLoader(); // Use names and ensure unique to protect against duplicates To load spring. Factories Set < String > names = new LinkedHashSet < > (SpringFactoriesLoader. LoadFactoryNames (type, classLoader)); / / in the spring. The factories to get to the full name of the class instantiation object List < T > instances = createSpringFactoriesInstances (type, parameterTypes, classLoader, args, names); / / sorting AnnotationAwareOrderComparator. Sort (instances);return instances;
	}
Copy the code
How do I load Spring.Factories
private static Map<String, List<String>> loadSpringFactories(@nullable ClassLoader ClassLoader) { MultiValueMap<String, String> result = cache.get(classLoader);if(result ! = null) {returnresult; } try {// Load data in meta-INF /spring.factories, "Spring.factories <URL> urls = (classLoader! = null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); Result = new LinkedMultiValueMap<>(); result = new LinkedMultiValueMap<>();while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for(Map.Entry<? ,? > entry : properties.entrySet()) { String factoryClassName = ((String) entry.getKey()).trim(); // Use commas to separate multiple lines.for(String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { result.add(factoryClassName, factoryName.trim()); Cache. put(classLoader, result);returnresult; }}Copy the code

So the key interface is loaded with spring.factories, and the value is the implementation class

/ / instantiate ApplicationContextInitializer in this list after private list < ApplicationContextInitializer <? >> initializers; Private list <ApplicationListener<? >> listeners;Copy the code

Above is a rough instantiation of SpringBoot

What does the run method do?

public ConfigurableApplicationContext run(String... args) { ..... / / get the listener SpringApplicationRunListeners listeners = getRunListeners (args); // Execute listeners. Starting (); . }Copy the code

What does the getRunListeners do

private SpringApplicationRunListeners getRunListeners(String[] args) { Class<? >[] types = new Class<? >[] { SpringApplication.class, String[].class }; / / from spring. Factories take SpringApplicationRunListener only EventPublishingRunListener (actually is not real listener, looks down)return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
	}
Copy the code
Listeners. Starting () is invoked the EventPublishingRunListener# startingCopy the code
public EventPublishingRunListener(SpringApplication application, String[] args) { this.application = application; this.args = args; / / EventPublishingRunListener instantiation, will create a radio apparatus, ran and put real listening in to radio / /, when these listening are SpringApplicaition instantiated from the spring. The fac / / tories out, Need to notify the listeners behind the radio apparatus is used when notice this. InitialMulticaster = new SimpleApplicationEventMulticaster ();for(ApplicationListener<? > listener : application.getListeners()) { this.initialMulticaster.addApplicationListener(listener); } } public voidstarting() {/ / direct call radio, enclosing initialMulticaster. MulticastEvent (new ApplicationStartingEvent (enclosing application, enclosing the args)); }Copy the code

Look at the next SimpleApplicationEventMulticaster# multicastEvent

	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type= (eventType ! = null ? eventType : resolveDefaultEventType(event)); // Use getApplicationListeners to obtain qualified listenersfor(final ApplicationListener<? > listener : getApplicationListeners(event,type)) {
			Executor executor = getTaskExecutor();
			if(executor ! = null) { executor.execute(() -> invokeListener(listener, event)); }else{// Execute the listener onApplicationEvent method invokeListener(listener, event); }}}Copy the code

GetApplicationListeners obtain qualified listener is invoked GenericApplicationListener# supportsEventType to judge, so generally write spring listener, Is to implement GenericApplicationListener# supportsEventType method, to determine their own listening interest in what event

To be continued……….