Analysis of the Spring IOC container startup process

XML and annotations are two of the most commonly used configurations when using Spring, and while they are completely different configurations, the difference for the IOC container is mainly in the parsing of BeanDefinition. The core container startup process is still consistent.

AbstractApplicationContext refresh method to realize the main logic of the IOC container start, start the process of the key steps in the source code can also be corresponding to an independent method. Next to AbstractApplicationContext implementation class ClassPathXmlApplicationContext is given priority to, and compared its another implementation class AnnotationConfigApplicationContext, Interpret the startup process of the IOC container.

AbstractApplicationContext.refresh


	@Override
	public void refresh(a) throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			// ...}}Copy the code

ApplicationContext and BeanFactory

ClassPathXmlApplicationContext and AnnotationConfigApplicationContext inheritance tree as shown below. Both inherited from AbstractApplicationContext.

ApplicationContext Inheritance tree (
High clearly the figure
)

BeanFactory Inheritance tree (
High clearly the figure
)

The ApplicationContext is the carrier of the IOC container, and the BeanFactory is the tool that operates on the container. The Refresh method implements the main process of collaboration between the ApplicationContext and the BeanFactory, The main difference in subclasses AbstractRefreshableApplicationContext and GenericApplicationContext implemented, Both use the BeanFactory for DefaultListableBeanFactory, DefaultListableBeanFactory are defined as follows:

DefaultListableBeanFactory:

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory.BeanDefinitionRegistry.Serializable
Copy the code

Visible DefaultListableBeanFactory implements ConfigurableListableBeanFactory means is configurable, traversal, as to why you can, let’s continue to look for to find the answer.

BeanDefinition access

Save all BeanDefinition DefaultListableBeanFactory used in Map structure information:

DefaultListableBeanFactory:

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
Copy the code

The parsing ClassPathXmlApplicationContext

Using BeanDefinitionDocumentReader (can see DefaultBeanDefinitionDocumentReader processBeanDefinition method) in the XML bean resolves to BeanDefinition, which is then registered in the BeanFactory by the BeanDefinitionRegistry. Entry: AbstractApplicationContext refreshBeanFactory (call) in the refresh

Parsing of AnnotationConfigApplicationContext

Bean declarations are scanned by BeanDefinitionScanner, resolved to BeanDefinition and registered with BeanFactory by BeanDefinitionRegistry. Entry: AnnotationConfigApplicationContext constructor.

Why is the entrance to the ClassPathXmlApplicationContext in refreshBeanFactory approach?

AbstractApplicationContext. RefreshBeanFactory are defined as follows:

AbstractApplicationContext:

protected abstract void refreshBeanFactory(a) throws BeansException, IllegalStateException
Copy the code

Visibility is an abstract method that is implemented in subclasses. Only “Refreshable” the BeanFactory can achieve specific operation in the method, such as AbstractRefreshableApplicationContext:

AbstractRefreshableApplicationContext:

@Override
	protected final void refreshBeanFactory(a) throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory; }}catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for "+ getDisplayName(), ex); }}Copy the code

Visible AbstractRefreshableApplicationContext. ` ` refreshBeanFactory method checks whether the BeanFactory already exists (hasBeanFactory), Destroy all existing beans (destoryBeans) and close (closeBeanFactory) BeanFactory before creating a new one (createBeanFactory). And GenericApplicationContext. RefreshBeanFactory will check whether it is in the first call, isn’t it throws an exception, don’t do other logic, Namely GenericApplicationContext not “Refreshable”.

Main process analysis

Refresh methods defined in AbstractApplicationContext obtainFreshBeanFactory of method calls the getBeanFactory method, this method is used to get the BeanFactory, Specific instructions are not here for DefaultListableBeanFactory, then most of the methods and variables are taken from AbstractApplicationContext and DefaultListableBeanFactory.

High clearly the figure

BeanPostProcessor

BeanPostProcessor interface for developers in the IOC container for Bean instantiation received callback (postProcessAfterInitialization and postProcessBeforeInitialization method). Spring framework inside many of the notification (Aware) is through the interface, such as ApplicationContextAwareProcessor ServletContextAwareProcessor, Their implementation in postProcessBeforeInitialization method for inspection, if it implements a specific interface, is called Aware callback methods, give notice:

ServletContextAwareProcessor:

@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if(getServletContext() ! =null && bean instanceof ServletContextAware) {
			((ServletContextAware) bean).setServletContext(getServletContext());
		}
		if(getServletConfig() ! =null && bean instanceof ServletConfigAware) {
			((ServletConfigAware) bean).setServletConfig(getServletConfig());
		}
		return bean;
	}
Copy the code

In postProcessBeanFactory approach, subclasses can pass the beanFactory. Add your own BeanPostProcessor addBeanPostProcessor method into the beanFactory, This will eventually be saved to beanPostProcessors in the BeanFactory (which is actually CopyOnWriteArrayList). PrepareBeanFactory and registerBeanPostProcessors method is instantiated and add these beans.

Spring BeanFactoryPostProcessor and BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistry is used to register beanDefinitions with a BeanFactory, GenericApplicationContext and DefaultListableBeanFactory implements this interface, implement the direct call the beanFactory in GenericApplicationContext.

Spring BeanFactoryPostProcessor and BeanDefinitionRegistryPostProcessor BeanPostProcessor similar, but can be seen from their name, will, for the different goals, BeanFactory and BeanDefinitionRegistry: The BeanFactoryPostProcessor callback gives the developer the opportunity to override some of the attributes of the BeanFactory if the BeanFactory has already been initialized. Or modify beanDefinitionDefinition in beanDefinitionMap. 2 BeanDefinitionRegistryPostProcessor let developers can continue to add to the BeanFactory BeanDefinition.

Specific logic is realized in invokeBeanFactoryPostProcessors, here first will all realized BeanFactoryPostProcessors Bean instantiation, Then call the callback method (postProcessBeanDefinitionRegistry or postProcessBeanFactory method).

There are priority rules for the instantiation and callback of this part of the Bean. PriorityOrdered inherited from Ordered interface, realized the PriorityOrdered BeanDefinitionRegistryPostProcessor will be instantiated first and call, The same rules are then called back and forth to the beans that implement the BeanFactoryPostProcessor: PriorityOrdered > Ordered > unordered

In registerBeanPostProcessors approach to BeanPostProcessor instantiation of this priority rules: PriorityOrdered > Ordered > > of unrealized Ordered MergedBeanDefinitionPostProcessor

ApplicationEventMulticaster

In initApplicationEventMulticaster initialized to ApplicationEventMulticaster: The first checks whether there has been a ApplicationEventMulticaster BeanDefinition (check in beanDefinitionMap), have let container instantiated, No use the framework to the default ApplicationEventMulticaster (namely SimpleApplicationEventMulticaster), first instantiation, It is then registered to the container (MessageSource is initialized in the same way in the initMessageSource method).

Events will start sending place packaging for ApplicationEvent, and submit to ApplicationEventMulticaster through ApplicationEventPublisher, ApplicationEventMulticaster event will be broadcast to ApplicationListener, dealing with the final distribution.

In AbstractApplicationEventMulticaster applicationListeners (LinkedHashSet < ApplicationListener >) variable to hold all of the radio receiver, The registerListeners method adds all applicationListeners to the collection.

The finishRefresh method has a broadcast of the ContextRefreshedEvent event as a reference, and the final event is handled by the multicastEvent method:

SimpleApplicationEventMulticaster.multicastEvent

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

So how to get this in our own Bean ApplicationEventPublisher? ApplicationContext is defined as follows:

ApplicationContext:

public interface ApplicationContext extends EnvironmentCapable.ListableBeanFactory.HierarchicalBeanFactory.MessageSource.ApplicationEventPublisher.ResourcePatternResolver {
Copy the code

Visible ApplicationContext inherited ApplicationEventPublisher, which means AbstractApplicationContext is also a ApplicationEventPublisher. In our own beans by implementing ApplicationEventPublisherAware, we can get ApplicationEventPublisher through setApplicationEventPublisher callback.

We mentioned above many of the spring is Aware by BeanPostProcessor, ApplicationEventPublisherAware is no exception:

ApplicationContextAwareProcessor:

@Override
	@Nullable
	public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
		// ...
        if (bean instanceof Aware) {
			if (bean instanceof EnvironmentAware) {
				((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
			}
			if (bean instanceof EmbeddedValueResolverAware) {
				((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
			}
			if (bean instanceof ResourceLoaderAware) {
				((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
			}
			if (bean instanceof ApplicationEventPublisherAware) {
				((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
			}
			if (bean instanceof MessageSourceAware) {
				((MessageSourceAware) bean).setMessageSource(this.applicationContext);
			}
			if (bean instanceof ApplicationContextAware) {
				((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); }}// ...
	}
Copy the code

The IOC container in instantiate our Bean called when ApplicationContextAwareProcessor. PostProcessBeforeInitialization method, this method will check our Bean, Our Bean if realized ApplicationEventPublisherAware, Will callback setApplicationEventPublisher method will applicationContext (namely ApplicationEventPublisher) to us, we will be able to publish events.

BeanFactory.getBean

The BeanFactory’s overloaded getBean methods are where the Bean is finally instantiated, registerBeanPostProcessors, InvokeBeanFactoryPostProcessors and finishBeanFactoryInitialization method calls to the getBean method on some specific Bean instantiation.

FinishBeanFactoryInitialization by calling in the BeanFactory preInstantiateSingletons on singleton Bean instantiation. BeanFactory and BeanDefinition both have a parent-child concept, and if the child cannot find the specified Bean, it will look up (the parent) and instantiate it when it finds it

conclusion

The startup steps of the Spring IOC container can be summarized as follows: 1 initialize the initialization and validation of the ApplicationContext environment properties, set the startup time logging and associated flags, and initialize the application events and listeners.

2. Prepare BeanDefinition (eagle-initializing beans) resolution, scanning and registration of Beandefinitions in the container. BeanDefinition scanning and registration can be roughly divided into XML and annotations. Each method uses different components, and this step can be done first.

3 Initialize the BeanFactory Prepare the BeanFactory for use by ApplicationContext, instantiate the Bean to be used, prepare the resources, and set the properties.

BeanPostProcessors are key components that need to be registered in this step. There are two types of BeanPostProcessors: those provided by the users of the framework for specific business functions, and those provided by the developers of the framework to extend the functionality of the framework.

5 call BeanDefinitionRegistryPostProcessor BeanDefinitionRegistryPostProcessor is a kind of enhancements, You can add a new BeanDefinition to the BeanFactory in this step.

Call BeanFactoryPostProcessor BeanFactoryPostProcessor is an enhancement that allows you to override the attributes of a BeanFactory that has been initialized. Or modify a BeanDefinition already registered with a BeanFactory.

7 initializes the MessageSource and ApplicationEventMulticaster MessageSource to handle international resources, ApplicationEventMulticaster application event broadcast, Used to distribute application events to listeners.

Initialization of other beans and other context initializations are mainly used for extension

9 Register ApplicationListene Register ApplicationListene with the BeanFactory for subsequent event distribution

10 Instantiate the remaining Bean singleton Steps 4 through 9 instantiate some special beans, where all remaining singleton beans need to be instantiated

11 Start the resource reclamation task and send the Refresh completed event.