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
-
In the properties file to read the context), initializer) classes is pointing to the field
-
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
-
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
-
ApplyInitializeClasses adds objects returned from instantateInitializer to the Initializers list
-
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