An overview of the

Spring is a very basic and core framework for Java development. After some development experience, reading source code can improve our coding ability and make us understand it better. As the saying goes, you can win a hundred battles if you know your enemy. Once you’re comfortable with Spring, there’s nothing stopping you on your development path.

IOC generally has two most important areas: creating Bean containers and initializing them. In this article, we mainly explain the IOC Bean container creation process. The initialization section will be covered later.

In order to maintain the seriousness of the article, if readers find me wrong, please do not hesitate to point out, I would like to hear the voice of readers. At the same time, they can correct their own misunderstandings.

This article mainly uses ClassPathXmlApplication as the Spring IOC container, and analyzes the process of container creation from ClassPathXmlApplication. First, let’s look at the dependencies of ClassPathXmlApplication:

First let’s look at the core trunk:

We can through to the ClassPathXmlApplicationContext parent class name, understand its main functions:

  • DefaultResourceLoader: provides the method getResource () to get the configuration file and returns Resource information
  • AbstractApplicationContext: provides the main create containers, initialize object method refresh ()
  • AbstractRefreshableApplicationContext: provide refresh refreshBeanFactory () method, the BeanFactory initialization.
  • AbstractRefreshableConfigApplicationContext: save the configuration file information.
  • AbstractXmlApplicationContext: provide loadBeanDefinitions () reads BeanDefinitions method, converts resource configuration.
  • ClassPathXmlApplicationContext: specific implementation class, used to locate the resources file.

From the above analysis of the main classes, I believe you have a general idea of the initialization of Spring IOC.

In a nutshell, the process for creating a Spring IOC container is as follows:

We will map the picture to the call of the class by the following steps:

1, the ClassPathXmlApplicationContext – > by the constructor, reads the XML configuration file address information

2, AbstractApplicationContext – > refresh () initializes the container

3, AbstractRefreshableApplicationContext – > the BeanFactory initialization

4, AbstractXmlApplicationContext – > loadBeanDifinition read resource information (loading beans)

XmlBeanDefinitionReader -> Parses the resource file to BeanDefinition

6, DefaultBeanDefinitionDocumentReader – > to BeanDefinition registered into the BeanFactory

Because Spring IOC part of the source code mainly includes: container creation and Bean initialization two parts. In this article, the main introduction, container creation process!

1. Container instance

Applicationcontext.xml configuration file

<? xml version="1.0" encoding="UTF-8"? > <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id="User" class="com.charles.business.model.User">
        <property name="username" value="jaycekon"/>
        <property name="phone" value="1881412 * * *"/>
    </bean>
</beans>
Copy the code

Code startup entry:

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        User user = (User) applicationContext.getBean("User");
        Assert.notNull(user, "Container initialization exception!");
        logger.info("Initialization result: {}", JSONObject.toJSONString(user));
    }
Copy the code

Let’s take a look at each process one by one, based on the ClassPathXmlApplication’s dependency graph.

2, ClassPathXmlApplicationContext

Core approach:

org.springframework.context.support.ClassPathXmlApplicationContext#ClassPathXmlApplicationContext(java.lang.String[], boolean, org.springframework.context.ApplicationContext)
Copy the code

As can be seen from the above, the ClassPathXmlApplicationContext class does not provide any special method, in addition to the constructor, Only a method to obtain the Resource (similar AbstractRefreshableConfigApplicationContext class provides access to resources in positioning method), is mainly used to save the resources information.

The main structure in the ClassPathXmlApplicationContext method:

public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @nullable ApplicationContext parent) throws BeansException {// Call the superclass constructor super(parent); / / AbstractRefreshableConfigApplicationContext concrete realization, save resources locate informationsetConfigLocations(configLocations);
		if(refresh) {/ / AbstractApplicationContext concrete realization, initialize the container with Bean refresh (); }}Copy the code

As you can see, the ClassPathXmlApplicationContext this class is quite simple, main effect:

  • Resource[] configResources: Stores configuration files as resources in this array
  • SetConfigLocations () : save the configuration file location information (AbstractRefreshableConfigApplicationContext)
  • Refresh () : start the container initialization core method (AbstractApplicationContext)

3, AbstractApplicationContext

Core approach:

org.springframework.context.support.AbstractApplicationContext#refresh
Copy the code

AbstractApplicationContext is core classes in the Spring IOC container, the parent class, interface provides the specific implementation, the method is very rich, here we mainly introduce the core method the refresh (). Here’s a quick explanation of why refresh() is used instead of a method named init(). After the ApplicationContext is created, you can actually rebuild it by calling refresh(), which destroys the original ApplicationContext and then re-initializes it.

Public void refresh() throws BeansException, IllegalStateException {// Locks container initialization to avoid repeated operations during container creation. Synchronized (enclosing startupShutdownMonitor) {/ / set the container to initialize the world, said container isActive now, initialize any placeholder attribute the source of the context prepareRefresh (); // The core steps are: Class BeanFactory () {BeanFactory (); BeanFinition (); Only the configuration information is extracted ConfigurableListableBeanFactory the beanFactory = obtainFreshBeanFactory (); // Set the BeanFactory class loader, add a few BeanPostProcessors, and manually register a few special beans prepareBeanFactory(BeanFactory); Try {// The next steps will be analyzed next time, the main core of this article is the above steps... } catch (BeansException ex) {if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); }}}Copy the code

From AbstractApplicationContext the refresh () we can roughly figured out that the core of the Spring IOC process, basic completed here, from a container to create, resource analysis, Bean creation and a series of steps. It’s all controlled by this method.

One of our main concerns in this article is:

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
Copy the code

In the figure above, we can intuitively understand the relationship between ApplicationContext and BeanFactory. Here to create ConfigurableListableBeanFactory actually contains the BeanFactory three branches of the vast majority of functions.

ApplicationContext inherits the ListableBeanFactory interface, which means that we can fetch multiple beans through this interface. The top-level BeanFactory interface methods fetch a single Bean.

HierarchicalBeanFactory is hierarchicalContextHierarchicalBeanFactory. Hierarchical words themselves speak for themselves, meaning that we can have multiple BeanFactories in our applications. You can then set the individual BeanFactories to parent-child relationships.

3, the Autowire AutowireCapableBeanFactory this name is familiar to everyone, it is used for automatic assembly Bean to use, but look at above, ApplicationContext didn’t inherit it, but don’t worry, don’t use inheritance, Do not represent can not use a combination, if you see ApplicationContext last method in the interface definition of getAutowireCapableBeanFactory ().

4, ConfigurableListableBeanFactory is also a special interface, see figure, is special in it inherited the second all three interfaces, while the ApplicationContext. We’re going to need that later.

Let’s look at the main content of the obtainFreshBeanFactory () method:

	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {/ / AbstractRefreshableApplicationContext implemented, is mainly used to refresh the BeanFactory, loading Bean definitions, registered Bean and so on refreshBeanFactory (); / / get the steps above To create a good the BeanFactory ConfigurableListableBeanFactory the BeanFactory = getBeanFactory ();if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ":" + beanFactory);
		}
		return beanFactory;
	}
Copy the code

4, AbstractRefreshableApplicationContext

Core approach:

org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory
Copy the code

Actually in the process of reading the source code, read the class name can provide great help for us, for example AbstractRefreshableApplicationContext this class, It can be seen that she inherited AbstractApplicationContext and mainly realize the function of the refresh, of course, the refresh does not mean that the refresh () method. RefreshBeanFactory ()

@override protected final void refreshBeanFactory() throws BeansException {// Check whether ApplicationContext already has a BeanFactory, If so, destroy all beans and close the BeanFactoryif(hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } to try {/ / initializes a DefaultListableBeanFactory DefaultListableBeanFactory the beanFactory = createBeanFactory (); beanFactory.setSerializationId(getId()); // Set two configuration properties of BeanFactory: whether Bean overrides are allowed, and whether circular references to customizeBeanFactory(BeanFactory) are allowed; LoadBeanDefinitions (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

You might think of ApplicationContext as inheriting from BeanFactory, but in practice it should not be understood as an implementation of BeanFactory, The ApplicationContext holds an instance of the BeanFactory, and all subsequent BeanFactory-related operations are actually handled by this instance.

A brief introduction to the customizeBeanFactory method:

  • Whether allowBeanDefinitionOverriding: set the Bean can be covered
  • AllowCircularReferences: Sets whether circular dependencies can be used
	protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
		if(this.allowBeanDefinitionOverriding ! = null) { beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); }if (this.allowCircularReferences != null) {
			beanFactory.setAllowCircularReferences(this.allowCircularReferences);
		}
	}
Copy the code

5, AbstractXmlApplicationContext

Core approach:

org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)
Copy the code

The XML -> Resource -> BeanDefinition step finally arrived:

@Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// Instantiate an XmlBeanDefinitionReader beanfactory.xmlBeandefinitionReader beanDefinitionReader for this BeanFactory = new XmlBeanDefinitionReader(beanFactory); / / set the default environment configuration beanDefinitionReader. SetEnvironment (enclosing getEnvironment ()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Initialize BeanDefinitionReader initBeanDefinitionReader(BeanDefinitionReader); // Define bebeandefinitions loadBeanDefinitions(beanDefinitionReader); }Copy the code

This method is simple, so let’s go straight down to the loadBeanDefinitions () method:

	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		Resource[] configResources = getConfigResources();
		if(configResources ! = null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations();if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
	}
Copy the code

As you can see, there are two main steps: one is through Resource and the other is through configLocations (this step is more about the process of grabbing the Resource locator and changing it to Resource).

Subsequent Bean parsing will be done in the following way:

org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.support.EncodedResource)
Copy the code

6, summary

Due to space reasons, this article mainly introduces the source code process for the creation of the Spring IOC container. The Bean parsing and the source code analysis for the following steps will be covered later. Finally, let’s review the main process:

  • Initialize the ClassPathXmlApplicationContext. ClassPathXmlApplicationContext ()
  • Core AbstractApplicationContext. Refresh () method
  • Initialize the BeanFactory AbstractRefreshableApplicationContext. RefreshBeanFactory ()
  • AbstractXmlApplicationContext. LoadBeanDefinitions analytical Resource ()
  • To be continued…

References:

  • https://docs.spring.io/spring/docs/5.0.5.BUILD-SNAPSHOT/spring-framework-reference/core.html#spring-core
  • http://www.importnew.com/27469.html
  • http://www.importnew.com/19243.html