Spring source code analysis - instantiation of simple benefit Bean

Posted by fourthe on Thu, 03 Feb 2022 05:40:51 +0100

preface

In the previous series of chapters, we analyzed the startup process of Spring IOC, including container creation, configuration loading, configuration parsing, Bean registration and other stages. Therefore, Bean registration is actually to encapsulate the relevant attributes and dependencies of a Bean into a beandefinition object, and then register it in a ConcurrentHashMap. It should be noted that this BeanDeafinition is only a definition encapsulation of a Bean, not a real Bean instance. When was the Bean instance created? There are three situations

  • If it is a simple Bean and lazy init = false (instant, immediate, urgent and hungry are the same meaning), the Bean will be instantiated according to BeanDeafinition after the IOC container is started.
  • If a Bean has not yet been instantiated, use beanfactory When getBean obtains a Bean, it will trigger the instantiation of the Bean.
  • When automatic injection is adopted, the instantiation of Bean will be triggered

Although there are many situations that will trigger the instantiation of beans, the instantiation process is the same. This article will talk about the instantiation process of simple benefit beans after the IOC is started.

refresh() simple Bean instantiation

The code also needs to go back to the AbstractApplicationContext#refresh method, where< IOC startup process >In this article, we have studied the container refresh method

@Override
   public void refresh() throws BeansException, IllegalStateException {
   	synchronized (this.startupShutdownMonitor) {
   		// Prepare this context for refreshing.
   		//Prepare the refresh work, record the start time, initialize the properties, verify the configuration file, and prepare the storage Set of events
   		prepareRefresh();

   		// Tell the subclass to refresh the internal bean factory.
   		//Tell the subclass to refresh the Bean factory, destroy the old beanFactory, and create a new beanFactory. The default is DefaultListableBeanFactory
   		//Load the Bean's asset file from the child container's refreshBeanFactory method
   		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
		
        ...ellipsis...
            
        // Instantiate all remaining (non-lazy-init) singletons.
        //Instantiate all remaining (non deferred initialization) singleton beans
        finishBeanFactoryInitialization(beanFactory);

   		...ellipsis...
   }

In the obtainFreshBeanFactory method, some processes such as Bean resource file loading, Bean parsing and BeanDefinition registration are completed. Finally, the BeanDefinition is saved in a concurrent HashMap managed by DefaultListableBeanFactory.

The next thing we want to discuss is finishBeanFactoryInitialization; Method, which implements the creation process of a singleton Bean urgently initialized.

/**
	 * Finish the initialization of this context's bean factory,
	 * initializing all remaining singleton beans.
	 * Complete the initialization of the bean factory in this context and initialize all the remaining singleton beans.
	 */
	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// Initialize conversion service for this context.
		//Service interface for type conversion
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

		// Register a default embedded value resolver if no bean post-processor
		// (such as a PropertyPlaceholderConfigurer bean) registered any before:
		// at this point, primarily for resolution in annotation attribute values.
		if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		}

		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

		// Stop using the temporary ClassLoader for type matching.
		//Stop using temporary class loader for type matching
		beanFactory.setTempClassLoader(null);

		// Allow for caching all bean definition metadata, not expecting further changes.
		//Allows caching of all beandefinition metadata to prevent changes
		beanFactory.freezeConfiguration();

		// Instantiate all remaining (non-lazy-init) singletons.
		//[important] the entry is here. Instantiate the simple Bean with lazy init = false
		beanFactory.preInstantiateSingletons();
	}

After initializing Bean Factory here, call beanFactory.. The preinstantiatesingletons method instantiates a simple bean with lazy init = false. The defaultlistablebeanfactory#preinstantiatesingletons source code is as follows:

@Override
	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 in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		//Get the names of all beans
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		for (String beanName : beanNames) {
			//Gets the BeanDefinition definition object of the Bean
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			//If it is not an abstract class, if it is simple interest, and if lazyInit is false, the instantiation logic is triggered
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				//Determine whether it is a FactoryBean
				if (isFactoryBean(beanName)) {
					//Call the getBean method to get the FactoryBean factory class instance.
					//[important] get Bean method is the core of instantiating beans. We will focus on this method later
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					//If FactoryBean
					if (bean instanceof FactoryBean) {
						FactoryBean<?> factory = (FactoryBean<?>) bean;
						//Do you want to initialize now
						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) {
							//[important] if you need to instantiate immediately, call the getBean method to instantiate the Bean
							getBean(beanName);
						}
					}
				}
				else {
					//[important] if it is an ordinary simple Bean, call the getBean method to instantiate the Bean
					getBean(beanName);
				}
			}
		}

		// Trigger post-initialization callback for all applicable beans...
		// init initialization method that triggers all Bean lifecycle methods
		for (String beanName : beanNames) {
			//Get the instance of simple interest Bean
			Object singletonInstance = getSingleton(beanName);
			//Judge whether the Bean implements the SmartInitializingSingleton interface. SmartInitializingSingleton is the initialization interface for simple benefit beans
			if (singletonInstance instanceof SmartInitializingSingleton) {
				SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					//Trigger the call of the afterSingletonsInstantiated method
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}

In this method, first get the names of all beans registered in the IOC container, then cycle to get the BeanDefinition definition object of each Bean, and then make three judgments: it can't be abstract, it must be simple interest, it must be urgent initialization, if it meets the conditions, then look at whether it is an ordinary Bean or a FactoryBean, and finally call getBean(beanName); Method, which calls AbstractBeanFactory#doGetBean. This method creates a Bean.

After creating the Bean, it will determine whether Bean implements the SmartInitializingSingleton initialization interface, which is the initialization interface for single interest Bean, and then calls afterSingletonsInstantiated to initialize Bean.

Bean instantiation flow chart

Let's start with a flow chart. You can look at the code according to this chart later.

AbstractBeanFactory#doGetBean

protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {
		//Get the name of the Bean. If the alias is specified, convert the alias to the standard Bean name
		String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		//Bean s that get simple interest from the cache will only be created once for simple interest, and then they will be cached in the map
		//By default, beans are urgently loaded. They are instantiated and cached in the Map during the process of container startup
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				//Judge whether the bean is in the singletonsCurrentlyInCreation set, which stores the simple bean being created
				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 + "'");
				}
			}
			//Obtaining the object of the Bean instance is mainly to complete the relevant processing of FactoryBean
			//That is, if naem starts with $, it will return to the FactoryBean factory
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			//The code goes here to show that there is no bean being created in the map of simple profit cache.

			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
			//If there is no simple benefit Bean in the cache, but there is a multi benefit Bean in the cache, which is currently being created. An exception is thrown due to circular dependency
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// Check if bean definition exists in this factory.
			//Get container IOC factory
			BeanFactory parentBeanFactory = getParentBeanFactory();
			//Check by beanName if the Bean is not included in the container
			//If there is no Bean in the container, it is handed over to the parent along the inheritance system
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				//Get the original name of the Bean and resolve the alias to the canonical name
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					//Find Bean according to name, type and parameter
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
					//Delegate the parent factory to find the Bean according to the name and parameters
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
					// No parameter - > delegate to standard getBean method according to name and type
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					//Find Bean by name
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}
			//Do you want to type check when creating a Bean
			if (!typeCheckOnly) {
				//The tag Bean is created
				markBeanAsCreated(beanName);
			}

			try {
				//Merging beans mainly solves the public properties of subclasses and parent classes during Bean inheritance
				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				// Guarantee initialization of beans that the current bean depends on.
				//Ensure the initialization of the bean on which the current bean depends.
				String[] dependsOn = mbd.getDependsOn();
				//If the current Bean depends on other beans
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						//
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						//Register a dependent bean for a given bean
						registerDependentBean(dep, beanName);
						try {
							//Recursion to obtain the dependent Bean from the container
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// Create bean instance.
				//Create simple interest Bean
				if (mbd.isSingleton()) {
					//Obtain the simple interest Bean according to the Bean name. This is the place where the Bean is really created. It is created through ObjectFactory
                      //This is an anonymous inner class
					sharedInstance = getSingleton(beanName, () -> {
						try {
							//Create Bean
							return 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 for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							//Destroy the instance and clear the simple Bean from the cached map
							destroySingleton(beanName);
							throw ex;
						}
					});
					//Returns the bean instance, which mainly deals with FactoryBean
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
				//If it's dolly
				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					//In the prototype mode, a new instance will be created each time
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						//Create an instance of the specified Bean object. If it is in prototype mode, a new instance will be created every time
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						//The default implementation marks the prototype as no longer created
						afterPrototypeCreation(beanName);
					}
					//Returns the bean instance, which mainly deals with FactoryBean
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				else {
					String scopeName = mbd.getScope();
					//If it is not simple interest or multi interest, and the Bean has no scope attribute, it is illegal
					if (!StringUtils.hasLength(scopeName)) {
						throw new IllegalStateException("No scope name defined for bean ยด" + beanName + "'");
					}
					Scope scope = this.scopes.get(scopeName);
					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);
				throw ex;
			}
		}
		//Check whether the required type matches the type of the actual bean instance.
		// Check if required type matches the type of the actual bean instance.
		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 new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
		}
		return (T) bean;
	}

There is a lot of code in the above method. Here is a summary

  • If it is a simple Bean, look it up from the map cached by the simple Bean (in ConcurrentHashMap), find it and return it directly. Every time you get the simple Bean, it will return from the map. If there is no in the cache, it will be created. By default, beans are created urgently, that is, in the process of container startup, Bean instances will be created according to the BeaDefinition and stored in the cache.
  • If it is a dolly Bean, a new Bean will be created every time

The creation of beans is left to the ObjectFactory#createBean method, which is implemented in the way of anonymous inner classes in the code. The specific instantiation process is delegated to the AbstractAutowireCapableBeanFactory#createBean method

AbstractAutowireCapableBeanFactory#createBean

The following is the source code of AbstractAutowireCapableBeanFactory#createBean method

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

		...ellipsis...

		try {
			//Create Bean [important]
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		...ellipsis...
	}

The following is the source code of AbstractAutowireCapableBeanFactory#doCreateBean method

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

		// Instantiate the bean.
		//Decoration of Bean
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			//Create Bean method [important]
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}
		//Allows the post processor to modify the merged bean definition.
		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					//Call Post Processor
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}
		//Eagerly cache singletons so that circular references can be resolved
		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			//Anonymous inner classes prevent circular references and hold references to objects as early as possible
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		//Initialize Bean and handle dependency injection
		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			//Filling beans is mainly to assign attributes, and use the attribute values in the bean definition to fill the bean instances in a given BeanWrapper.
			populateBean(beanName, mbd, instanceWrapper);
			//Initialize the Bean. If the Bean implements the InitializingBean interface, the afterPropertiesSet method will be called here
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		if (earlySingletonExposure) {
			//Get the registered simple interest Bean
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			//Register a DisposableBean to implement the destruction callback
             //Registers its DisposableBean interface and / or the given destruction method called when the factory is closed
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}

The important code is to call the createBeanInstance method to create an instance, and then populate and initialize the Bean, mainly for the injection of attribute values, the initialization of the Bean, and the registration of DisposableBean.

Several important methods:

  • createBeanInstance: creates an instance of BeanDean
  • populateBean, dependency injection for Bean attributes
  • initializeBean initializes the Bean. If the Bean implements the InitializingBean interface, the afterPropertiesSet method will be called here
  • Registerdisposablebeaninifnecessary: destruction method support. If the Bean implements the DisposableBean interface, wrap the Bean into a DisposableBeanAdapter through DefaultSingletonBeanRegistry and register it in a disposableBeans = new LinkedHashMap. When the container is closed, such as applicaiton Close() will trigger the AbstractApplicationContext#destroyBeans method to traverse all beans in the collection and execute the destroy method of the Bean.

The following is the code for creating an instance of AbstractAutowireCapableBeanFactory#createBeanInstance. The policy mode is used in this method,

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
		//Get the class of Bean
		Class<?> beanClass = resolveBeanClass(mbd, beanName);

    	Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}

		if (mbd.getFactoryMethodName() != null)  {
             //Instantiate beans through factory methods
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}
    
    	//Instantiate beans using auto assemble
    	// Shortcut when re-creating the same bean...
		boolean resolved = false;
		boolean autowireNecessary = false;
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		if (resolved) {
			if (autowireNecessary) {
                	//If the auto assembly attribute is configured, it can be instantiated by auto assembly
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
                //Instantiate using the default parameterless construction method
				return instantiateBean(beanName, mbd);
			}
		}
    
		...ellipsis...
		//Determines the constructor used to create the instance
		// Candidate constructors for autowiring?
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		...ellipsis...
		//Instantiate Bean [important]
         //Instantiate using the default parameterless construction method
		// No special handling: simply use no-arg constructor.
		return instantiateBean(beanName, mbd);
	}

The above code reflects several instantiation methods. Instantiate beans through factory methods or through automatic assembly features, which needs to be completed by calling the corresponding constructor. However, we usually use the default parameterless construction, which requires the reflection mechanism to instantiate. See instantiateBean method. The following is the source code of AbstractAutowireCapableBeanFactory#instantiateBean method:

protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
		try {
			Object beanInstance;
			if (System.getSecurityManager() != null) {
				beanInstance = AccessController.doPrivileged(
						(PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this),
						getAccessControlContext());
			}
			else {
				//The important code here is to instantiate the Bean through the InstantiationStrategy
				beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
			}
			BeanWrapper bw = new BeanWrapperImpl(beanInstance);
			initBeanWrapper(bw);
			return bw;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
		}
	}

In the method, beans are instantiated through the InstantiationStrategy instantiation strategy. Simple interest beans are instantiated using the SimpleInstantiationStrategy strategy. Get the instance object and wrap it in the BeanWrapper object.

SimpleInstantiationStrategy#instantiate

The following is the source code of the simpleinstantiationstrategy#instance () method

@Override
	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// Don't override the class with CGLIB if no overrides.
		//If the Bean definition does not have an override method, do not override the class with CGLIB.
		if (!bd.hasMethodOverrides()) {
			Constructor<?> constructorToUse;
			synchronized (bd.constructorArgumentLock) {
				constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
				if (constructorToUse == null) {
					//Reflection to get the type of Bean
					final Class<?> clazz = bd.getBeanClass();
					//Interface cannot be instantiated
					if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						if (System.getSecurityManager() != null) {
							//Anonymous inner class, get constructor
							constructorToUse = AccessController.doPrivileged(
									(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
						}
						else {
							//Reflection, get constructor
							constructorToUse = clazz.getDeclaredConstructor();
						}
						bd.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Throwable ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex);
					}
				}
			}
			//Use Bean tool to create Bean through reflection and construct method newInstance(arg) create Bean
			return BeanUtils.instantiateClass(constructorToUse);
		}
		else {
			// Must generate CGLIB subclass.
			//Instantiate beans using CGLIB
            //Call the subclass cglibsubclassing instantiationstrategy Instantiatewithmethodinjection

			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}


	public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
		Assert.notNull(ctor, "Constructor must not be null");
		try {
			ReflectionUtils.makeAccessible(ctor);
            //Through ctor The newinstance constructor instantiates the Bean
			return (KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
					KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
        }

A judgment is made in the method. If the Bean has a method to be overwritten, JDK reflection is used to create an instance of the Bean, otherwise CGLIB is used to instantiate. CGLIB calls the subclass cglibsubclassing instantiationstrategy. If a class has no interface, only CGLIB can be used

CglibSubclassingInstantiationStrategy#instantiateWithMethodInjection

The following is the code for cglibsubclassing instantiationstrategy#instantiatewithmethodinjection cglib to create objects

@Override
	protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
			@Nullable Constructor<?> ctor, Object... args) {

		// Must generate CGLIB subclass...
		return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
	}


public Object instantiate(@Nullable Constructor<?> ctor, Object... args) {
        //[important] create a proxy subclass and return class
        Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
        Object instance;
        if (ctor == null) {
            //Turn class into an object through reflection
            instance = BeanUtils.instantiateClass(subclass);
        }
        else {
            try {
                //Proxy subclass constructor
                Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
                //Create instance through constructor
                instance = enhancedSubclassConstructor.newInstance(args);
            }
            catch (Exception ex) {
                throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
                                                     "Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
            }
        }
        // SPR-10785: set callbacks directly on the instance instead of in the
        // enhanced class (via the Enhancer) in order to avoid memory leaks.
        Factory factory = (Factory) instance;
        factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
                                             //Find override method interceptor
                                             //CGLIB MethodInterceptor overrides the methods and replaces them with an implementation that returns the bean s found in the container.
                                             new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
                                             //CGLIB MethodInterceptor to override the methods and replace them with calls to the generic methodreplace
                                             new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
        return instance;
    }


	private Class<?> createEnhancedSubclass(RootBeanDefinition beanDefinition) {
			Enhancer enhancer = new Enhancer();
        	//The enhanced class (proxy class) will parent the current class
			enhancer.setSuperclass(beanDefinition.getBeanClass());
			enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
			if (this.owner instanceof ConfigurableBeanFactory) {
				ClassLoader cl = ((ConfigurableBeanFactory) this.owner).getBeanClassLoader();
				enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(cl));
			}
			enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition));
			enhancer.setCallbackTypes(CALLBACK_TYPES);
			return enhancer.createClass();
		}

	

The above is the code for CGLIB to create an agent. For JDK dynamic agent, the proxy class must have an interface. JDK dynamic agent will generate a proxy class for the proxy class and implement the same interface as the proxy class, so as to implement the same method, but the proxy class can be held and called in the method of the proxy class, Thus, the method of the proxy class is enhanced. However, if the proxy class does not have an interface, it must be switched to CGLIB proxy mode.

The proxy class generated in this way will take the proxy class as the parent class and copy and enhance the methods of the proxy class. If you haven't touched CGLIB dynamic agent, you may look dizzy.

summary

I have made a summary of the process of creating the Bean. I've analyzed the specific process of creating the Bean here

  1. We discussed the instantiation timing of beans. After IOC is started, we instantiate simple interest beans. Instantiation is triggered when we manually get beans, and instantiation is triggered when we automatically inject beans
  2. Bean instantiation is completed through AbstractBeanFactory#doGetBean method. If it is a simple interest bean, look it up from the map of the simple interest bean cache (in the ConcurrentHashMap), find it and return it directly to ensure the simple interest. If it is not in the cache, it will be created. If it is a dolly bean, a new bean will be created every time
  3. The process of creating a Bean is mainly to create a Bean through the BeanDeifnition object of the Bean, using JDK reflection or CGLIB.
  4. When the Bean is created successfully, the dependency injection of the Bean and the initialization method of the Bean will be triggered.
  5. Finally, the DisposableBean is registered to support the Bean's destruction method call

Well, that's all for this article. If you like it, give it a good comment. If it's 500, I'll lose my hair and write the next chapter!!!

Topics: Spring