I didn’t realize the importance of reading excellent framework source code before, until I finished reading mybatis, Spring IOC, AOP, springMVC source code, from which I learned a lot of low-level knowledge, such as Java reflection introspection, JDK dynamic proxy, Cglib dynamic proxy, It was only when I realized that the source code used a variety of design patterns, making the framework very powerful and extensible, that I found the framework is also very beautiful. Without further ado, let’s start our tour of SpringIOC source code.

The source code version used in this article is 5.2.x. In order to better understand springIOC, we use XML, and most of the actual development is done in annotations. My experience has taught me that XML configuration is best for understanding the source code.

Read the source code: go to the Spring website to download the latest source code and compare it with it, otherwise you can’t read it at all. I have suffered the disadvantage of thinking that I can understand the source code by reading a book. I was naive and gave up after reading a few pages because I couldn’t understand it.

This article assumes that the reader already knows the basics of Spring-related use, such as how to build projects, introduce Spring-related dependencies, and use unit tests.

The introduction

The biggest difficulty in reading source code is the entrance is difficult to find, experience tells us that we usually use the source code is to read the entrance, and we usually develop are closely related.

Build a Maven project, add dependencies, and use unit tests to test the process of getting beans.

Here’s how we use springIOC:

Here is the raw way we usually get a bean:

public class TestSpring {
    @Test
    public void testSpring() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");
        Student student = (Student) ctx.getBean("student"); System.out.println(student); }}Copy the code

Create a new application. XML file under the resource folder, usually called application. XML or application-xxx. XML, and configure it as follows:

<? xml version="1.0" encoding="UTF-8"? > <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="Http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <bean id="student" class="com.sjc.spring.po.Student"> <! -- String --> <property name="name" value="jiangcong"></property> <! -- Integer Type --> <property name="age" value="18"></property> <! -- Reference type --> <property name="course" ref="course"></property> </bean> <! This class has an initialization method --> <bean id="course" class="com.sjc.spring.po.Course"
          init-method="init"> <! -- String --> <property name="name" value="spring"></property>
    </bean>
</beans>

Copy the code

Student class

public class Student {

	private String name;
	private Integer age;

	private Course course;
  / /... Omit getter/setter methods
}
Copy the code

Course class

public class Course {

	private String name;
	/ /... Omit getter/setter methods
}
Copy the code

The example is simple, but enough to get us to the point of this article, exploring how the Spring container installs configuration files and instantiates beans for us so that we can get an instance of the Student class using getBean(“student”) to understand the core IOC and DI in Spring.

Before you start reading the source code, let’s introduce the important interface of Spring. This is not required for you to master, but when you enter the source code reading section, you will have an impression in your mind, and then look up this part of the knowledge.

Introduction to important Spring interfaces

BeanFactory inheritance

Looking at these intricate class diagrams, we can’t help but wonder how big Spring is. So why does Spring define so many interfaces? Because each interface has its use occasion, each interface has certain responsibility, but does not interfere with each other, this is the principle of interface isolation in design pattern. If you think about it, it wouldn’t be a mess if you implemented all of this functionality in one or two interfaces.

Here are the main functions of the main classes:

BeanFactory:

The interface mainly defines the basic behavior of the IOC container, such as fetching beans based on various conditions. The factory pattern is used here.

ListableBeanFactory:

As the name suggests, the interface features the ability to produce a list of instances, such as getting Bean instances by type instead of list Bean instances

HierarchicalBeanFactory:

The main implementation is the layering of Bean factories.

AutowireCapableBeanFactory:

An auto-assembly Bean factory

This factory interface inherits from the BeanFacotory, which extends the autowiring capabilities to assemble beans, pre-execution, post-execution handlers, and so on from the BeanDefinition class.

ConfigurableBeanFactory

Complex configuration Bean factories

ConfigurableListableBeanFactory

This class is huge. The factory interface has 83 interfaces in total, and contains all the methods of the BeanFactory architecture so far.

BeanDefinitionRegistry

Used to manipulate BeanDefinition objects defined inside the factory. For example, register a BeanDefinition to get a BeanDefinition

BeanDefinition inheritance system

ApplicationContext inherits the architecture

Source code analysis

Creating an IOC container

Having introduced the main interfaces, we move on to source code analysis

AbstractApplication#refresh()

The entire container initialization process can be roughly divided into 12 steps, and readers who are interested in each step are free to use it as a branch entry to learn how it works. Here I examine steps 2 and 11, which are the most critical IOC processes: the process of creating the BeanFactory and the process of Bean initialization. Related interferences, such as try/catch blocks, have been omitted to save space.

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context forRefreshing. // 1: refreshing preprocessing // Setting the boot time of the Spring container, deactivating the closed state and activating the active state. // Initialize the Property source information (Property) // Validate some mandatory properties in the environment information prepareRefresh(); // Tell the subclass to refresh the internal bean factory. // 2: / / a) to create the IOC container loading (DefaultListableBeanFactory) / / b) to parse the XML documents stored in (final Document object) / / c) read the Document object, And finish the work load and registered ConfigurableListableBeanFactory BeanDefinition the beanFactory = obtainFreshBeanFactory (); // Prepare the bean factoryfor use inPrepareBeanFactory (beanFactory); prepareBeanFactory(beanFactory); // 4: // Allows post-processing of the bean factoryincontext subclasses. postProcessBeanFactory(beanFactory); // Invoke Factory Processors registered as beansinthe context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. // 6: Registered BeanPostProcessor registerBeanPostProcessors post processor (the beanFactory); // 7: Initialize some message sources (such as i18N message resources that handle internationalization) // Initialize Messagesource for this context.
				initMessageSource();

				// Initialize event multicaster forThis context. / / 8: initialize the application events broadcaster initApplicationEventMulticaster (); // 9: Initialize other special beansinspecific context subclasses. onRefresh(); // 10: register some listeners // Checkforlistener beans and register them. registerListeners(); // 11: instantiate the remaining singleton bean (non-lazy loading) // Note: The IOC, ID and AOP of the Bean are all Instantiate all Remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. FinishRefresh (); } / /... Omit the try/catch blockCopy the code

Step 2 obtainFreshBeanFactory(), which parsed the XML file (eventually stored in the Document object), read the Document object, and load and register the BeanDefinition. Returns a Bean factory DefaultListableBeanFactory, readers can contrast with the UML class diagram above, find DefaultListableBeanFactory position, experience the function of a class.

We then entered the AbstractRefreshableApplicationContext# refreshBeanFactory

Here will create a more important container, the IOC container factory DefaultListableBeanFactory, our profile information in the form of BeanDefinition object stored here, LoadBeanDefinitions (beanFactory); This line of code, here is to load our configuration file encapsulation to BeanDefinition to DefaultListableBeanFactory logic implementation, here only defines a hook method, implementation is mainly composed of a subclass to implement, a bit like a kind of abstract template method design pattern.

Protected final void refreshBeanFactory() throws BeansException {// If there was an IOC container before, destroy itif(hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } / / create the IOC container, namely DefaultListableBeanFactory DefaultListableBeanFactory the beanFactory = createBeanFactory (); beanFactory.setSerializationId(getId()); // Set factory properties: Whether to allow BeanDefinition overrides and whether to allow loop dependencies on customizeBeanFactory(beanFactory); // Call the BeanDefinition method. The loadBeanDefinitions method is abstract in the current class. The concrete implementation calls the subclass container. loadBeanDefinitions(beanFactory); Synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory; } / /... Omit try/catch block}Copy the code

Here we focus on the implementation classes that correspond to XML configuration files, also in the form of annotations, which interested readers can delve into as a branch.

We entered the AbstractXmlApplicationContext# loadBeanDefinitions

Here we look at the interface isolation design principle and the single responsibility principle, and get a taste of the benefits of defining so many interfaces. Let’s see the BeanFactory inheritance system, DefaultListableBeanFactory is realized BeanDefinitionRegistry interface, has the ability to register BeanDefinition, But what you pass to the XmlBeanDefinitionReader BeanDefinition reader is simply passing in the BeanDefinitionRegistry, which has the BeanDefinition function registered (let’s look at XmlBeanDefinition) Reader knew that in the constructor and public XmlBeanDefinitionReader (BeanDefinitionRegistry registry)), the ability of the other is still in DefaultListableBeanFactory, This is to protect the DefaultListableBeanFactory, reflected the interface segregation effect.

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for// Create a BeanDefinition reader by reading the XML file, XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); // Delegate BeanDefinitions loadBeanDefinitions(beanDefinitionReader); }Copy the code

We then go to the loadBeanDefinitions method,

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {// getConfigResources is an empty implementation, the real implementation is to call the subclass's method to get the resource location // for example: Was realized in the ClassPathXmlApplicationContext / / and FileSystemXmlApplicationContext not using this method the Resource configResources = [] getConfigResources();if(configResources ! = null) {/ / XML Bean reader calls its parent class AbstractBeanDefinitionReader read reader positioning of the resources. The loadBeanDefinitions (configResources); } / / if a subclass of resource location is empty, obtain FileSystemXmlApplicationContext construction methodsetString[] ConfigLocations = getConfigLocations();if(configLocations ! = null) {/ / XML Bean reader calls its parent class AbstractBeanDefinitionReader read reader positioning of the resources. The loadBeanDefinitions (configLocations); }}Copy the code

Here we’re going to focus on

Reader. LoadBeanDefinitions (configLocations), and enter into

public int loadBeanDefinitions(String location, @ Nullable Set the < Resource > actualResources) throws BeanDefinitionStoreException {/ / in the process of the IOC container initialization Settings for Resource loader ResourceLoader resourceLoader = getResourceLoader();if (resourceLoader == null) {
			throw new BeanDefinitionStoreException(
					"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
		}

		if(resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); // Delegate calls methods XmlBeanDefinitionReader, int count = loadBeanDefinitions(resources);if(actualResources ! = null) { Collections.addAll(actualResources, resources); }if (logger.isTraceEnabled()) {
					logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
				}
				returncount; } / /... Omit try/catch block}Copy the code

We go to the subclass XmlBeanDefinitionReader#loadBeanDefinitions

Take an InputStream of an XML file and encapsulate it into an InputSource. See doLoadBeanDefinitions for a specific parsing process.

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { //... / / will omit some code resource files into an InputStream IO stream InputStream InputStream = encodedResource. GetResource () getInputStream (); InputSource InputSource = new InputSource(InputStream);if(encodedResource.getEncoding() ! = null) { inputSource.setEncoding(encodedResource.getEncoding()); } // Specify the parsing processreturn doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } / /... Omit try/catch block}Copy the code

XmlBeanDefinitionReader#doLoadBeanDefinitions:

This is mainly to encapsulate XML into a Document object, and then parse the Document object to complete the loading and registration of BeanDefinition. After many hardships, we finally came to this step, not easy ah!

protected int doLoadBeanDefinitions(InputSource inputSource, The Resource the Resource) throws BeanDefinitionStoreException {/ / by DOM4 load to parse the XML file, eventually form a Document object Document doc =doLoadDocument(inputSource, resource); Int count = registerBeanDefinitions(doc, resource);if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			returncount; / /... / omits the try/catch blockCopy the code

Let’s see how BeanDefinition is registered, right

Enter the XmlBeanDefinitionReader# registerBeanDefinitions

Here is very good use of the single responsibility principle of the object-oriented logic of handling the entrusted to a single class for processing, such as: BeanDefinitionDocumentReader

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // Using DefaultBeanDefinitionDocumentReader instantiation BeanDefinitionDocumentReader BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); Int countBefore = getRegistry().getBeandefinitionCount (); / / load and registered bean documentReader. RegisterBeanDefinitions (doc, createReaderContext (resource)); // Record the number of BeanDefinitions loaded this timereturn getRegistry().getBeanDefinitionCount() - countBefore;
	}
Copy the code

We entered the BeanDefinitionDocumentReader# registerBeanDefinitions

And into its default implementation class DefaultBeanDefinitionDocumentReader# doRegisterBeanDefinitions

protected void doRegisterBeanDefinitions(Element root) { Will be specific to BeanDefinitionParserDelegate BeanDefinition analytical work to complete BeanDefinitionParserDelegate parent = this. Delegate; this.delegate = createDelegate(getReaderContext(), root, parent); / /... PreProcessXml (root); preProcessXml(root); preProcessXml(root); / / / / entrusted to BeanDefinitionParserDelegate hook method, starting from the root element of the Document to BeanDefinition analytical parseBeanDefinitions (root, enclosing the delegate);  PostProcessXml (root); postProcessXml(root); // Hook method this.delegate = parent; }Copy the code

Here we are concerned with parseBeanDefinitions

Enter the DefaultBeanDefinitionDocumentReader# parseBeanDefinitions

This is where it is important to iterate through all the children of the Document object. Here we only care about parseDefaultElement (bean tag, import tag, alias tag) and use the default resolution rules

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {/ / loaded Document object whether or not to use the Spring to the default XML namespace (beans namespaces)if(delegate. IsDefaultNamespace (root)) {/ / get all the child nodes of the Document root element object (bean label and import label,aliasTags and other custom tags context, aop, etc.) NodeList nl = root.getChildNodes();for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				if(node instanceof Element) { Element ele = (Element) node; // Bean tags, import tags,aliasTag, the default parsing rules are usedif (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					}
					else{/ / as the context tag, aop, tx labels, use the parsing rules of user custom analytic element node delegate. ParseCustomElement (ele); }}}}else{ delegate.parseCustomElement(root); }}Copy the code

We entered the DefaultBeanDefinitionDocumentReader# parseDefaultElement

Private void parseDefaultElement (Element ele, BeanDefinitionParserDelegate delegate) {/ / parsing < import > tagif(delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } // parse <alias> tagelse if(delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } // Parse the bean labelelse if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		else if(delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {// recurse // recurse calldoRegisterBeanDefinitions(ele); }}Copy the code

Here we mainly look at the tag analysis, other readers interested in the words can go to see.

We entered the DefaultBeanDefinitionDocumentReader# processBeanDefinition

BeanDefinitionParserDelegate# parseBeanDefinitionElement parses BeanDefinition and packaging to BeanDefinitionHolder,

BeanDefinitionReaderUtils# registerBeanDefinition will eventually BeanDefinition registered to BeanDefinitionRegistry (DefaultListableBeanFactory) Private final map <String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

For those of you who are interested, follow along, and here we’re finally done parsing the BeanDefinition. Completed AbstractApplicationContext# refresh () step 2: XML document parsing and BeanDefinition loading and registration work

Protected void processBeanDefinition (Element ele, BeanDefinitionParserDelegate delegate) {/ / parsing < bean > tag, Access to BeanDefinition BeanDefinitionHolder bdHolder = delegate. ParseBeanDefinitionElement (ele);if(bdHolder ! = null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); Try {/ / registered ultimate BeanDefinition to BeanDefinitionRegistry (DefaultListableBeanFactory) / / Register the final decorated instance. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); }}Copy the code

Instantiate the Bean

Let’s take a look at AbstractApplicationContext# refresh () step 11, this step is very important, very important, very important…

This completes the instantiation of the singleton Bean, where the IOC, ID, and AOP of the Bean occur

AbstractApplicationContext#finishBeanFactoryInitialization

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { //... Omit some code / / Instantiate all remaining (non - lazy - init) singletons. / / Instantiate the singleton bean the beanFactory. PreInstantiateSingletons (); }Copy the code

We entered the DefaultListableBeanFactory# preInstantiateSingletons

Let’s take a look at the difference between BeanFactory and FactoryBean.

  • The BeanFactory is the Spring top-level interface, the spring base container, which is responsible for managing bean instances.

  • A FactoryBean is simply a bean object that is managed in the Spring container, except that this bean has the ability to generate other objects.

  • BeanFactory is a big factory that contains everything

  • A FactoryBean is a small factory that produces only specified objects and is managed by a large factory.

  • Factorybeans are treated differently from regular Bean instances when they are managed by Spring. The & prefix distinguishes factoryBeans from ordinary Bean instances

public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		// Iterate over a copy to allow for init methods which inturn register new bean definitions. // While this may not be part of the regular factory bootstrap, it does otherwise work fine. List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans... // Triggers the creation of all non-lazy-loaded singleton beansfor (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if(! bd.isAbstract() && bd.isSingleton() && ! Bd.islazyinit ()) {// If the bean is a FactoryBean, go to the following methodif (isFactoryBean(beanName)) {
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if(bean instanceof FactoryBean) { final FactoryBean<? > factory = (FactoryBean<? >) bean; boolean isEagerInit;if(System.getSecurityManager() ! = null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)  ((SmartFactoryBean<? >) factory)::isEagerInit, getAccessControlContext()); }else{ isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<? >) factory).isEagerInit()); }if(isEagerInit) { getBean(beanName); }}}else{// Ordinary beans go to the following method getBean(beanName); }}} / /... Omit some code}Copy the code

Here we are going to go with the normal Bean

Enter the AbstractBeanFactory# getBean,

Enter AbstractBeanFactor #doGetBean

This method is mainly divided into two steps:

  1. Get the singleton Bean from the cache, detect it if you get it, and generate an object from the FactoryBean instance if the Bean you get is a FactoryBean
  2. If you don’t get a Bean, you need to instantiate a Bean return through BeanDefinition
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {// Obtain bean name final String beanName = transformedBeanName(name); Object bean; // Eagerly check singleton cacheforManually registered singletons. // Obtain singleton Object sharedInstance = getSingleton(beanName) from the cache; // If you get a singleton bean, go to the following codeif(sharedInstance ! = null && args == null) {if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); }} // If the Bean instance is a Bean instance of a FactoryBean, Generate an object instance bean from the FactoryBean instance bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); }else{// If you do not get a singleton bean, go to // Failif we're already creating this bean instance: // We'Re assumably within a circular referenceif(isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } / /... Omitted the code that checks whether BeanDefinition is in Factory try {// Gets the BeanDefinition object of the instantiated bean final RootBeanDefinition MBD = getMergedLocalBeanDefinition(beanName); / / check the BeanDefinition object corresponding to the Bean is abstract checkMergedBeanDefinition (MBD, beanName, args); / /... // Create bean instance. // If it is a singleton bean, see the following codeif(mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {// The main method to create a singleton Beanreturn createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow forcircular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; }}); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }else if(mbd.isprototype ()) {// prototype //... Omitted the branch that handles the prototypical pattern Bean}else{/ /... Omitted branches that handle request, session-level beans for example}return (T) bean;
	}
Copy the code

Let’s focus on this code (important) :

Lambda expressions for Java8 are used here

// Create bean instance. // If it is a singleton bean, see the following codeif(mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {// The main method to create a singleton Beanreturn createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow forcircular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; }}); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }Copy the code

Enter the DefaultSingletonBeanRegistry# getSingleton

I’ve dealt with the issue of circular dependencies, what they are, and how Spring solves them. Look forward to my next article.

public Object getSingleton(String beanName, ObjectFactory<? > singletonFactory) { synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName);if(singletonObject == null) { //... // Before creation, set a beforeSingletonCreation(beanName); boolean newSingleton =false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if(recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } the try {/ / invoke an anonymous inner class for singleton singletonObject = singletonFactory. GetObject (); newSingleton =true; } / /... Omit catch block finally {if(recordSuppressedExceptions) { this.suppressedExceptions = null; } // Eliminate afterSingletonCreation(beanName); } // Put the generated singleton Bean into the cache (total level 3 caching)if(newSingleton) { addSingleton(beanName, singletonObject); }}returnsingletonObject; }}Copy the code

The above singletonObject = singletonFactory. GetObject (); The createBean(beanName, MBD, args) method in the lambda expression is called.

We enter its implementation class

AbstractAutowireCapableBeanFactory#createBean

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { //... // Create Bean instance (instantiate, populate properties, initialize) Object beanInstance =doCreateBean(beanName, mbdToUse, args);
}
Copy the code

Into what we care about

AbstractAutowireCapableBeanFactory#doCreateBean

This completes the creation of the completion Bean instance in three steps:

  1. instantiation

    The default call to construct the instantiated Bean without arguments is where the construct parameter dependency injection occurs

  2. Property population (DI dependency injection occurs in this step)

    Properties are set using reflection and introspection techniques

  3. Initialization (AOP occurs in this step)

    It also uses reflection to call the initialization method for example

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if(mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } // Bean initialization step 1: the default call to instantiate the bean with no arguments constructor // Construct parameter dependency injection, which occurs in this stepif(instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } / / instantiate the Bean Object after the final Object Bean. = instanceWrapper getWrappedInstance (); Class<? > beanType = instanceWrapper.getWrappedClass();if(beanType ! = NullBean.class) { mbd.resolvedTargetType = beanType; } / /... // Sometimes it is sometimes triggered by lifecycle. // Sometimes it is sometimes triggered by lifecycle Boolean earlySingletonExposure = (mbd.issingleton () && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); // If the singleton Bean needs to be exposed ahead of time, the Bean is placed in the level 3 cacheif (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references"); } // Place the bean in the singleFactories(key is beanName, Value is FactoryBean) addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, MBD, bean)); } // Initialize the bean instance. Object exposedObject = bean; Try {// bean initialization step 2: populate properties (DI dependency injection occurs in this step) // There are two main cases: // 1. For non-collection attributes, use reflection and introspection directly to set the attributes // 2. For a property of a collection type, parse its property value into a collection of the target type and assign it directly to the property populateBean(beanName, MBD, instanceWrapper); ExposedObject = initializeBean(beanName, exposedObject, MBD); // Call the initialization method to complete the bean initialization (AOP occurs in this step). } / /... //... Omit some codereturn exposedObject;
	}
Copy the code

At this point, the SpringIOC container has resolved the loading, parsing, and dependency injection of the resource files defined by the Bean. The SpringIOC container now manages a set of beans that are linked by dependencies, without the application having to manually create the required objects. The SpringIOC container automatically creates and injects dependencies for us as we use them. This is the inversion of control of Spring’s core functionality and dependency injection, which gives Spring the ability to manage Bean creation.