This is the 31st day of my participation in The August Wenwen Challenge.

ApplicationContextInitializer running processes

Initialization process

(1) initialize ApplicationContextInitializer (flow chart)

1. Initialize the SpringApplication instance

SpringApplication springApplication =new SpringApplication(Application.class);
Copy the code
public SpringApplication(Class
       ... primarySources) {
		this(null, primarySources);
	}

public SpringApplication(ResourceLoader resourceLoader, Class
       ... primarySources) {
    
		this.resourceLoader = resourceLoader;
    
		Assert.notNull(primarySources, "PrimarySources must not be null");
    
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // Call setInitializers to instantiate initializers
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    
		this.mainApplicationClass = deduceMainApplicationClass();
	}
Copy the code

2.setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); Initialize Initializers and put them in the list

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, newClass<? > [] {}); }Copy the code

Use getSpringFactoriesInstances loadFactoryNames realized ApplicationContextInitializer class for the search, Through createSpringFactoriesInstances for each instantiated, and use AnnotationAwareOrderComparator. Sort sorting

private <T> Collection<T> getSpringFactoriesInstances(Class
       
         type, Class
        [] parameterTypes, Object... args)
        {
ClassLoader classLoader = getClassLoader();
		
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    
AnnotationAwareOrderComparator.sort(instances);
return instances;
	}
Copy the code

SpringFactoriesLoader loadFactoryNames concrete implementation is as follows

  public static List<String> loadFactoryNames(Class<? > factoryClass,@Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if(result ! =null) {
            return result;
        } else {
            try{ Enumeration<URL> urls = classLoader ! =null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
 LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) { Entry<? ,? > entry = (Entry)var6.next(); String factoryClassName = ((String)entry.getKey()).trim(); String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());int var10 = var9.length;
   for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryName = var9[var11];
                            result.add(factoryClassName, factoryName.trim());
                        }
                    }
                }
                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13); }}}Copy the code

Register into result and return it by reading the configuration in meta-INF/Spring.Factories

CreateSpringFactoriesInstances concrete implementation is as follows

@SuppressWarnings("unchecked")
	private <T> List<T> createSpringFactoriesInstances(Class
       
         type, Class
        [] parameterTypes, ClassLoader classLoader, Object[] args, Set
        
          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;
	}
Copy the code

Major. It can be seen through the BeanUtils instantiateClass instantiate () method and returns

For the second type of initializer, adding containers is done directly in the startup class

The call is added directly to the initializer’s container

** Note: ** For the second initializer declaration and the third, adding containers is done directly in the startup class

Due to the use in the configuration file (the resource/application. The properties) set in the initialization of the location of the class.

As you can see pictures in DelegatingApplicationContextInitializer startup of the application. The properties in the configuration of the initializer for the call

In the initialize method of DelegatingApplicationContextInitializer first call getInitializeClasses methods

  1. In the properties file to read the context), initializer) classes is pointing to the field

  2. Call getInitializeClass in the loop to cast the package name to Class type by ClassUtils and use ** assert.isAssignable (type, instanceClass); ** performs type verification, adds it to the classes list, and returns

In the initialize method of DelegatingApplicationContextInitializer from classes into applyInitializeClasses getInitializeClasses returns

  1. The instantateInitializer method is called in applyInitializeClasses to first iterate through the classes passed in: instantiate the package name using BeanUtils and return the corresponding instantiated object

  2. ApplyInitializeClasses adds objects returned from instantateInitializer to the Initializers list

  3. Initializers into applyInitializers: Iterate through initializers and implement the Initialize method

Note: since DelegatingApplicationContextInitializer Order to zero compared with the previous two initializer to write faster

DelegatingApplicationContextInitializer execution

Call the process

The main code
run()
	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
	    stopWatch.start();	// The Spring timer starts
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();// Start the listener
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}
Copy the code
prepareContext()
	private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
		applyInitializers(context);
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if(printedBanner ! =null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		// Load the sources
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[0]));
		listeners.contextLoaded(context);
	}
Copy the code
applyInitializers()
	protected void applyInitializers(ConfigurableApplicationContext context) {
		for(ApplicationContextInitializer initializer : getInitializers()) { Class<? > requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context,"Unable to call initializer."); initializer.initialize(context); }}Copy the code