There are a lot of analyses on the Internet about the life cycle of Spring beans, but most of them introduce the interface implementation of BeanPostProcessor and integrate the implementation of this interface. The complete life cycle of Spring beans starts with the creation of the Spring container. Until finally the Spring container destroys the Bean, which includes a number of key points. Today we’ll explore its implementation in the source code with respect to the instantiation aspect of the bean lifecycle.

preface

After looking at the refresh logic of the Spring container in the last few articles, let’s follow up with the analysis.

Spring does a lot of fine-grained control over the creation of bean instantiations, and today we’ll just look at the bean instantiation process and the implementation of dependency injection in it.

So let’s take a look at the key messages. Here’s what they say:

The profile

An analysis of the bean instantiation process and its implementation of dependency injection

  • AbstractBeanFactory
    • DoGetBean Gets the bean instance
  • DefaultSingletonRegistry
    • GetSingleton Gets the singleton instance
    • Level 3 caching resolves circular dependencies
  • AbstractAutowireCapableBeanFactory
    • CreateBean Preparation for creating a bean instance
    • DoCreateBean Creates a bean instance
    • ApplyMergedBeanDefinitionPostProcessors @ Autowriet and @ the Value
    • PopulateBean injects property values into the bean instance (dependency injection)
  • AutowiredAnnotationBeanPostProcessor
    • PostProcessProperties Autowriet dependency injection logic
  • DefaultListableBeanFactory
    • DoResolveDependency Dependency resolution
  • DependencyDescriptor
    • Extends InjectionPoint Extends InjectionPoint dependency injection instance

Analysis of the

Gets the source of the bean instance

In the Spring container refresh logic in the end we see DefaultListableBeanFactory# preInstantiateSingletons methods to instantiate all the rest of the (non – lazy – init not delay loading) singleton.

public void preInstantiateSingletons(a) throws BeansException {
    if (logger.isTraceEnabled()) {
		logger.trace("Pre-instantiating singletons in " + this);
	}
    Definitionnames; // Obtain all beanName names from the beanDefinitionNames container
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // Loop through all registered beanName
    for (String beanName : beanNames) {
        BeanDefinition = beanDefinition = beanDefinition = beanDefinition = beanDefinition = beanDefinition
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        // Non-abstract (whether the XML configuration has the abstract property configured, not that the class is not an abstract class), singleton, and non-lazily loaded classes require instantiation
        if(! bd.isAbstract() && bd.isSingleton() && ! bd.isLazyInit()) {if (isFactoryBean(beanName)) {
                // Handle factoryBean (&)
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof FactoryBean) {
                    finalFactoryBean<? > factory = (FactoryBean<? >) bean;boolean isEagerInit;
                    if(System.getSecurityManager() ! =null && factory instanceofSmartFactoryBean) { isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<? >) factory)::isEagerInit, getAccessControlContext()); }else {
                        isEagerInit = (factory instanceofSmartFactoryBean && ((SmartFactoryBean<? >) factory).isEagerInit()); }if(isEagerInit) { getBean(beanName); }}}else {
                // This is where the bean is instantiated and managed
                // Get a bean; if you can't get one, create onegetBean(beanName); }}}// After the bean is instantiated, there will be some processing
	/ / @ EventListener labeling method was DefaultEventListenerFactory packaged into ApplicationListenerMethodAdapter
	// Classes in @eventListener are event objects
	/ / ApplicationListenerMethodApdapter registered to the ApplicationContext.
	// Wait for the event source to publish the notification, and the logic that is executed after the notification is the logic that annotates the @eventListener method
    for (String beanName : beanNames) {
		Object singletonInstance = getSingleton(beanName);
		if (singletonInstance instanceof SmartInitializingSingleton) {
			SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
			if(System.getSecurityManager() ! =null) {
				AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
					smartSingleton.afterSingletonsInstantiated();
					return null;
				}, getAccessControlContext());
			} else{ smartSingleton.afterSingletonsInstantiated(); }}}}Copy the code

That brings us to the AbstractBeanFactory#getBean method

public Object getBean(String name) throws BeansException {
	return doGetBean(name, null.null.false);
}
Copy the code

Getting the Bean instance

You can see that the getBean method calls doGetBean, and you’ll find many similar methods in the Spring source code where the internal processing is handed over to the do* method. Let’s move on to the doGetBean method:

@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
		@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
	// Obtain beanName in three forms
	// One is the original beanName, one is the &, and one is the alias
	final String beanName = transformedBeanName(name);
	Object bean;

	// Try to get the bean instance from the singleton cache collection
	Object sharedInstance = getSingleton(beanName);
	// If an instance of the singleton Bean has been created previously and the getBean method is called with null arguments
	// Execute the logic in if
	if(sharedInstance ! =null && args == null) {
		if (logger.isTraceEnabled()) {
			// If the Bean is still being created, it is a circular reference
			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 it is a FactoryBean, return its getObject
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
	// If scope is prototype or singleton but no beans exist in the cache
	else {

		// If scope is prototype and the display is still being created, then this is basically a circular dependency
		// Throw an exception for Prototype's loop dependency
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}

		BeanFactory parentBeanFactory = getParentBeanFactory();
		// We can't find the bean with the specified name in the current container, so we recurse to parentFactory
		if(parentBeanFactory ! =null && !containsBeanDefinition(beanName)) {
			// Add the & to the Bean, mainly for FactoryBean
			String nameToLookup = originalBeanName(name);
			// If the parent container is still an instance of AbstractBeanFactory
			// instanceof returns a Boolean value to indicate whether the object is an instanceof this particular class or its subclasses
			if (parentBeanFactory instanceof AbstractBeanFactory) {
				// Call the method recursively to find it
				return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
						nameToLookup, requiredType, args, typeCheckOnly);
			}
			else if(args ! =null) {
				// If there are arguments, delegate the parent container to look up by the specified name and the explicit arguments
				return (T) parentBeanFactory.getBean(nameToLookup, args);
			}
			else if(requiredType ! =null) {
				// Delegate to the parent container by the specified name and type
				return parentBeanFactory.getBean(nameToLookup, requiredType);
			}
			else {
				// Delegate to the parent container by name
				return(T) parentBeanFactory.getBean(nameToLookup); }}// typeCheckOnly is used to determine whether getBean() is called only for type checking to get the bean, not to create the bean
		if(! typeCheckOnly) {// Create a bean if you don't just do type checking
			markBeanAsCreated(beanName);
		}

		try {
			// Overwrite the superclass BeanDefinition with the subclass BeanDefinition
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			BeanDefinition = BeanDefinition = BeanDefinition
			checkMergedBeanDefinition(mbd, beanName, args);

			// Get the names of all dependent beans for the current Bean
			String[] dependsOn = mbd.getDependsOn();
			// If the current Bean has a dependsOn attribute set
			// depends-on specifies the order in which beans are initialized and destroyed
			if(dependsOn ! =null) {
				for (String dep : dependsOn) {
					// Verify that the dependency is registered with the current bean, noting that the key passed in is the name of the current bean
					// If there is a dependency of the following type:
					// If so, throw an exception
					if (isDependent(beanName, dep)) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
					}
					// Cache the dependency call. Note that the key passed in is the name of the dependent bean
					registerDependentBean(dep, beanName);
					try {
						// Call the getBean method recursively to register dependencies between beans (e.g. C needs to be initialized later than B, and B needs to be initialized later than A)
						// Initialize the dependent bean
						getBean(dep);
					}
					catch (NoSuchBeanDefinitionException ex) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"'" + beanName + "' depends on missing bean '" + dep + "'", ex); }}}// If BeanDefinition is singleton
			if (mbd.isSingleton()) {
				// An anonymous inner class is used to create Bean instance objects and register them with dependent objects
				sharedInstance = getSingleton(beanName, () -> {
					try {
						return createBean(beanName, mbd, args);
					}
					catch (BeansException ex) {
						// Remove the bean instance explicitly from the singleton cache
						// It may already exist in singleton mode to resolve circular dependencies, so destroy it
						destroySingleton(beanName);
						throwex; }});FactoryBean returns its getObject if it is a FactoryBean
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}

			else if (mbd.isPrototype()) {
				// Prototype creates a new object every time
				Object prototypeInstance = null;
				try {
					// The default function is to register the currently created Prototype object as being created
					beforePrototypeCreation(beanName);
					// Create a prototype object instance
					prototypeInstance = createBean(beanName, mbd, args);
				}
				finally {
					// The default function is to erase the previously registered Bean information that is being created
					afterPrototypeCreation(beanName);
				}
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			}

			// The Bean to be created is neither singleton nor archetypal, so the resource is defined according to the Bean
			// Configure the lifecycle scope to select the appropriate method to instantiate the Bean, as in a Web application
			// Common usage, such as request, session, and Application lifecycle
			else {
				String scopeName = mbd.getScope();
				final Scope scope = this.scopes.get(scopeName);
				// If the lifecycle scope is not configured in the Bean definition resource, the Bean definition is invalid
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
				}
				try {
					Object scopedInstance = scope.get(beanName, () -> {
						beforePrototypeCreation(beanName);
						try {
							return createBean(beanName, mbd, args);
						}
						finally{ afterPrototypeCreation(beanName); }}); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); }catch (IllegalStateException ex) {
					throw new BeanCreationException(beanName,
							"Scope '" + scopeName + "' is not active for the current thread; consider " +
							"defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); }}}catch (BeansException ex) {
			cleanupAfterBeanCreationFailure(beanName);
			throwex; }}// Type check the created Bean instance object
	if(requiredType ! =null && !requiredType.isInstance(bean)) {
		try {
			T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
			if (convertedBean == null) {
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
			return convertedBean;
		}
		catch (TypeMismatchException ex) {
			if (logger.isTraceEnabled()) {
				logger.trace("Failed to convert bean '" + name + "' to required type '" +
						ClassUtils.getQualifiedName(requiredType) + "'", ex);
			}
			throw newBeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); }}return (T) bean;
}
Copy the code

As you can see, the doGetBean method has a lot of logic inside it, mainly getting or creating a bean instance and then type checking the bean instance. There are roughly seven steps:

  1. Try to get the bean instance from the cache
    1. Implementation of level 3 cache
  2. Circular dependency judgment
    1. Examples of cyclic dependencies: B with @autowired A, A with @autowired B, A B with cyclic dependencies
  3. Retrieve the bean instance recursively from the parent container
  4. Gets BeanDefinition instance from the current container
  5. Recursively instantiate the explicitly dependent bean
  6. Bean instances are created using different policies for different scopes
  7. Type check the bean instance

Let’s follow the steps in the doGetBean method

Gets the level 3 cache of the bean instance

From doGetBean method we follow up to obtain a bean instance from the singleton cache collection, namely DefaultSingletonBeanRegistry# getSingleton method, the source code is as follows:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	// Try to get a full Bean from the level 1 cache
	Object singletonObject = this.singletonObjects.get(beanName);
	/ / if complete singleton has not yet been created, create the Bean's name will be saved in the singletonsCurrentlyInCreation
	// So see if it's being created
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		// Try to lock the level 1 cache object, because the cache object will be operated on next
		synchronized (this.singletonObjects) {
			EarlySingletonObjects is an instance of a Bean that has not yet been added to its properties
			singletonObject = this.earlySingletonObjects.get(beanName);
			// If not already and the second argument is true, true indicates that the bean is allowed to be referenced circularly
			if (singletonObject == null && allowEarlyReference) {
				// Try to get the singletonFactories that create the Bean from the cache of the ObjectFactory instance with the third-level cache singletonFactoriesObjectFactory<? > singletonFactory =this.singletonFactories.get(beanName);
				// If the factory instance is obtained
				if(singletonFactory ! =null) {
					// Call the singleton factory's getObject method to return the object instance
					singletonObject = singletonFactory.getObject();
					// Put the instance in the level 2 cache
					this.earlySingletonObjects.put(beanName, singletonObject);
					// Remove from level 3 cache
					this.singletonFactories.remove(beanName); }}}}return singletonObject;
}
Copy the code

In DefaultSingletonBeanRegistry in this class, we can see the three cache map

/ / level cache: singleton buffer pool, beanName - > beans, including storage is instantiated attribute assignment after successful singleton
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

BeanName ->ObjectFactory, which is added when the instance does not have attributes
// Use this to map the relationship between beanName and the Factory where the bean was created.
// Why use the factory approach? Some beans need to be proxied. There is no point in exposing the proxied beans
private finalMap<String, ObjectFactory<? >> singletonFactories =new HashMap<>(16);

// Secondary cache: early singleton, beanName->Bean, which stores the singleton whose properties are not assigned after instantiation. // Secondary cache: early singleton, beanName->Bean, which stores the singleton whose properties are not assigned after instantiation
// Execute the Bean produced by the factory method. After the Bean is put in,
// When the bean is created, it can be obtained by the getBean method
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
Copy the code

Getting the bean instance from the cache is basically dealing with the three Map caches

Retrieve the bean instance recursively from the parent container

If the bean with the specified name cannot be found in the current container, we recursively go to parentFactory to look for it

if(parentBeanFactory ! =null && !containsBeanDefinition(beanName)) {
	// Add the & to the Bean, mainly for FactoryBean
	String nameToLookup = originalBeanName(name);
	// If the parent container is still an instance of AbstractBeanFactory
	// instanceof returns a Boolean value to indicate whether the object is an instanceof this particular class or its subclasses
	if (parentBeanFactory instanceof AbstractBeanFactory) {
		// Call the method recursively to find it
		return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
				nameToLookup, requiredType, args, typeCheckOnly);
	}
	else if(args ! =null) {
		// If there are arguments, delegate the parent container to look up by the specified name and the explicit arguments
		return (T) parentBeanFactory.getBean(nameToLookup, args);
	}
	else if(requiredType ! =null) {
		// Delegate to the parent container by the specified name and type
		return parentBeanFactory.getBean(nameToLookup, requiredType);
	}
	else {
		// Delegate to the parent container by name
		return(T) parentBeanFactory.getBean(nameToLookup); }}Copy the code

Gets BeanDefinition instance from the current container

In getMergedLocalBeanDefinition method mainly BeanDefinition and children of the parent class of BeanDefinition merge coverage, In checkMergedBeanDefinition approach is mainly to merge BeanDefinition do validation, basically see whether attributes for the abstract

// Return the merged BeanDefinition, traversing the parent BeanDefinition if the specified bean corresponds to a child BeanDefinition
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
	RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
	if(mbd ! =null && !mbd.stale) {
		return mbd;
	}
        // Iterate over the parent BeanDefinition
	return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}

// Check the given merge bean definition, which may throw validation exceptions.
protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, @Nullable Object[] args)
		throws BeanDefinitionStoreException {
	if (mbd.isAbstract()) {
		throw newBeanIsAbstractException(beanName); }}Copy the code

Recursively instantiate the explicitly dependent bean

Note that Spring does not support explicitly defining dependencies, for example: if there is a direct exception thrown

<bean id="beanA" class="BeanA" depends-on="beanB">
<bean id="beanB" class="BeanB" depends-on="beanA">
Copy the code

Visible in the code: the getBean method is recursively called to register the dependencies between beans.

// Cache the dependency call. Note that the key passed in is the name of the dependent bean
registerDependentBean(dep, beanName);
try {
	// Call the getBean method recursively to register dependencies between beans (e.g. C needs to be initialized later than B, and B needs to be initialized later than A)
	// Initialize the dependent bean
	getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
	throw new BeanCreationException(mbd.getResourceDescription(), beanName,
			"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
Copy the code

Bean instances are created using different policies for different scopes

Different createBean methods are used for different scopes

When scope is instance, an anonymous inner class is used to create the Bean instance object and register it with the dependent object

sharedInstance = getSingleton(beanName, () -> {
	try {
		return createBean(beanName, mbd, args);
	}
	catch (BeansException ex) {
		// Remove the bean instance explicitly from the singleton cache
		// It may already exist in singleton mode to resolve circular dependencies, so destroy it
		destroySingleton(beanName);
		throwex; }});Copy the code

Let’s look at the getSingleton method

public Object getSingleton(String beanName, ObjectFactory
        singletonFactory) {
    synchronized (this.singletonObjects) {
        // Get the bean instance from singletonObjects via beanName
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            // If the Spring singleton bean container is being destroyed, do not allow the creation of a singleton bean to continue
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            try {
                // The lamdba method is called and the createBean method is called to create the bean instance
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            // ··· catch
            finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }
                // Remove beanNameSet from being created
                afterSingletonCreation(beanName);
            }
            // If the bean instance is successfully created, you need to add it to the singletonObjects container
            // So that the next retrieval can be directly from the container
            if(newSingleton) { addSingleton(beanName, singletonObject); }}returnsingletonObject; }}// After the Bean instance is created, only the level 1 cache and the order in which the beanName is registered are retained, and the rest is cleared
protected void addSingleton(String beanName, Object singletonObject) {
	synchronized (this.singletonObjects) {
		this.singletonObjects.put(beanName, singletonObject);
		this.singletonFactories.remove(beanName);
		this.earlySingletonObjects.remove(beanName);
		this.registeredSingletons.add(beanName); }}protected void addSingletonFactory(String beanName, ObjectFactory
        singletonFactory) {
	Assert.notNull(singletonFactory, "Singleton factory must not be null");
	synchronized (this.singletonObjects) {
		if (!this.singletonObjects.containsKey(beanName)) {
			// Add to the level 3 cache
			this.singletonFactories.put(beanName, singletonFactory);
			// Clear the cache information of this Bean in the secondary cache
			this.earlySingletonObjects.remove(beanName);
			// This is to record the order in which singletons are registered
			this.registeredSingletons.add(beanName); }}}Copy the code

Type check the bean instance

See if type checking is necessary for the created Bean instance object. If not, return the Bean instance directly.

DoGetBean method before we can see the real bean initialization logic methods: AbstractAutowireCapableBeanFactory# createBean

The bean initialization logic method createBean

The createBean method is the actual bean initialization logic, because it involves more than just creating an instance of the bean. It also involves validation methods, dependency injection, and initialization method calls in the class.

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {... logger// Determine whether the Bean to be created can be instantiated, that is, whether it can be loaded through the current class loaderClass<? > resolvedClass = resolveBeanClass(mbd, beanName);if(resolvedClass ! =null&&! mbd.hasBeanClass() && mbd.getBeanClassName() ! =null) {
		// Clone a BeanDefinition, which sets the class object loaded on it
		// We use this copy later because we don't want to bind the parsed class to a cached BeanDefinition
		// Because the class might need to be resolved dynamically every time
		mbdToUse = new RootBeanDefinition(mbd);
		mbdToUse.setBeanClass(resolvedClass);
	}
	// Prepare the checksum and override the methods in the Bean...try {
		// Create the Bean entry
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		if (logger.isTraceEnabled()) {
			logger.trace("Finished creating instance of bean '" + beanName + "'");
		}
		return beanInstance;
	}
    // Exception handling...}Copy the code

As you can see, createBean is primarily a checksum preparation environment. Instead of actually creating an instance of the bean, the doCreateBean method is given to the doGetBean method, which is similar to how the getBean method calls the doGetBean method.

Create bean instance doCreateBean

Now we know that doCreateBean is our actual method of instantiating a bean:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
		throws BeanCreationException {
	// Bean instances wrap classes
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
		// Clean up the uncreated wrapper Bean cache and retrieve the related wrapper Bean instances. After all, the wrapper Bean instances are singletons and can only be saved one copy
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
		// There are three ways to create an instance of a bean
		// 1. Create a factory method
		// 2. Construct method injection
		// 3. Constructor injection with no parameters
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	// Get the wrapped Bean. Subsequent changes to the Bean are equivalent to changes to the Wrapper, and vice versa
	final Object bean = instanceWrapper.getWrappedInstance();
	// Get the type of the instantiated objectClass<? > beanType = instanceWrapper.getWrappedClass();if(beanType ! = NullBean.class) { mbd.resolvedTargetType = beanType; }// Call the BeanPostProcessor after the BeanDefinition attribute is merged
	synchronized (mbd.postProcessingLock) {
		if(! mbd.postProcessed) {try {
				// Properties marked by @autowired and @value are fetched here
				applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
			}
			// Exception handling......
 			mbd.postProcessed = true; }}// Cache the singleton pattern Bean object into the container to prevent circular references
	// Determine if the bean is an early reference, and if it is, allow it to expose the reference earlier
	// There are three main logic in this judgment:
	// 1. Whether this is a singleton
	// 2. Whether to allow circular references
	// 3. Whether the bean is being created
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		// logger
		// This is an anonymous inner class that holds references to objects as early as possible to prevent circular references
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}
	// The initialization of the Bean object where dependency injection is triggered
	// This exposedObject returns the Bean as a dependency injection completed after initialization
	Object exposedObject = bean;
	try {
		// Fill the properties of the bean instance
		populateBean(beanName, mbd, instanceWrapper);
		// Initialize the bean as follows:
		// 1: determine whether BeanNameAware, BeanClassLoaderAware,
		// The BeanFactoryAware method, if any, sets the relevant properties
		// 2: calls the BeanPostProcessor operation initialized by the bean
		// 3: performs the initialization method.
		// Call afterPropertiesSet if there is an initializingBean
		// If there is an InitMethod, the initial method is called
		// 4: Calls the BeanPostProcessor operation initialized by the bean
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	// Exception handling......
    
	// If circular dependencies are allowed, resolve the related circular dependencies
	if (earlySingletonExposure) {
		// Get the registered singleton schema Bean object with the specified name
		Object earlySingletonReference = getSingleton(beanName, false);
		/ /...
	}
	try {
		// Register the destruction logic of the Bean
		registerDisposableBeanIfNecessary(beanName, bean, mbd);
	}
	// Exception handling......
	return exposedObject;
}
Copy the code

As you can see, doCreateBean does roughly five things:

  1. CreateBeanInstance: createBeanInstance
  2. Call the BeanDefinition attribute after the BeanPostProcessor has been merged
  3. Populate the bean instance property: populateBean
  4. Call the bean’s initialization method: initializeBean
  5. Registered bean is a logic: the destruction of registerDisposableBeanIfNecessary

I’ll cover the doCreateBean method in detail in a separate article.

This article is based on the spring framework 5.2.10.RELEASE version for analysis