Spring getBean and createBean process and three-level cache

DefaultSingletonBeanRegistry

L3 cache

In this class, there are the following three properties, which are the three-level cache of bean s

/** The first level cache stores the mapping of singletonBean instances: bean name -- > bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
/** The L2 cache stores the mapping of Singleton instances that were not completely created earlier: bean name -- > bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap(16);
/** The third level cache stores the singletonBean production factory: bean name -- > objectfactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);

Two questions to consider:

  • Why use L3 cache? Under normal circumstances, L2 cache can also solve circular dependency
  • Why does the third level cache store ObjectFactory instead of Object?

If objects are also stored in the third level cache, it is the same as the second level cache, which is meaningless. The necessity of the third level must be related to the ObjectFactory stored in the cache. The focus is on the Get Object () method of ObjectFactory

getSingleton(String beanName)

    //Get the bean corresponding to beanName and allow early reference
    public Object getSingleton(String beanName) {
        return this.getSingleton(beanName, true);
    }

getSingleton(String beanName, boolean allowEarlyReference)

  • If alloweerlyreference is true, the singleton bean can be obtained from the third level cache
  • If allowrearlyreference is false, the object cannot be obtained from the third level cache, that is, the singleton bean cannot be referenced in advance
    //Obtain the singleton bean, and obtain the singleton bean from the L1 cache, L2 cache and L3 cache respectively
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        //First, get the singleton bean object from the first level cache singletonObjects
        Object singletonObject = this.singletonObjects.get(beanName);
        //If the object cannot be obtained from singletonObjects & & the object is being created
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
            synchronized(this.singletonObjects) {
                //Get the object from the L2 cache earlysingletonobjects (a collection of singleton bean s referenced in advance)
                singletonObject = this.earlySingletonObjects.get(beanName);
                //If the object is not obtained from the L2 cache earlySingletonObjects & & early reference is allowed
                if (singletonObject == null && allowEarlyReference) {
                    //Get the object from the bean collection singletonFactories being created
                    ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        //If the object obtained from singletonFactories is not empty, it is placed in the singleton collection referenced in advance and deleted from the collection singletonFactories being created
                        singletonObject = singletonFactory.getObject();
                        //Put it into the singleton collection referenced in advance
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        //Remove from the collection singletonFactories being created
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return singletonObject;
    }

getSingleton(String beanName, ObjectFactory<?> singletonFactory)

    //getSingleton method with ObjectFactory parameter
    //The logic injected into the ObjectFactory.getObject() method is to call the createBean() method. See the call to this method in AbstractBeanFactory.doGetBean()
    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "Bean name must not be null");
        synchronized(this.singletonObjects) {
            //Get the modified bean from the L1 cache
            Object singletonObject = this.singletonObjects.get(beanName);
            //If not, create a new bean
            if (singletonObject == null) {
                if (this.singletonsCurrentlyInDestruction) {
                    throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)");
                }
    
                this.beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = this.suppressedExceptions == null;
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet();
                }
                try {
                    //ObjectFactory is a functional interface
                    //The logic in getObejct() is to call createBean() and return the created bean
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                } catch (IllegalStateException var16) {
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        throw var16;
                    }
                } catch (BeanCreationException var17) {
                    BeanCreationException ex = var17;
                    if (recordSuppressedExceptions) {
                        Iterator var8 = this.suppressedExceptions.iterator();
                        while(var8.hasNext()) {
                            Exception suppressedException = (Exception)var8.next();
                            ex.addRelatedCause(suppressedException);
                        }
                    }
                    throw ex;
                } finally {
                    if (recordSuppressedExceptions) {
                        this.suppressedExceptions = null;
                    }
    
                    this.afterSingletonCreation(beanName);
                }
                //If it is a new singleton, it will be added to the singleton L1 cache
                if (newSingleton) {
                    this.addSingleton(beanName, singletonObject);
                }
            }
            return singletonObject;
        }
    }

addSingleton(String beanName, Object singletonObject)

After bean initialization, put it into singletonobjects (first level cache) and clear the corresponding earlysingletonobjects (second level cache) or singletonfactories (third level cache) of the bean

    //Put the bean corresponding to beanName into the singletonObjects L1 cache
    protected void addSingleton(String beanName, Object singletonObject) {
        synchronized(this.singletonObjects) {
            //Put into L1 cache
            this.singletonObjects.put(beanName, singletonObject);
            //Remove from L3 cache
            this.singletonFactories.remove(beanName);
            //Remove from pre reference cache
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }

addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)

    //Putting the bean factory corresponding to beanName into the singletonFactories three-level cache is the key to solve the circular dependency
    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(singletonFactory, "Singleton factory must not be null");
        synchronized(this.singletonObjects) {
            //If it does not exist in the L3 cache, it is placed in the L3 cache
            if (!this.singletonObjects.containsKey(beanName)) {
                this.singletonFactories.put(beanName, singletonFactory);
                //Remove from pre reference cache
                this.earlySingletonObjects.remove(beanName);
                this.registeredSingletons.add(beanName);
            }
        }
    }

AbstractBeanFactory

getBean

    public Object getBean(String name) throws BeansException {
        return this.doGetBean(name, (Class)null, (Object[])null, false);
    }
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return this.doGetBean(name, requiredType, (Object[])null, false);
    }
    public Object getBean(String name, Object... args) throws BeansException {
        return this.doGetBean(name, (Class)null, args, false);
    }
    public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args) throws BeansException {
        return this.doGetBean(name, requiredType, args, false);
    } 

doGetBean

    protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
        String beanName = this.transformedBeanName(name);
        //Call the getSingleton method in the parent DefaultSingletonBeanRegistry
        Object sharedInstance = this.getSingleton(beanName);
        Object bean;
        //If sharedInstance is not null, it means that the bean 1. Has been created and initialized successfully, or 2. Is being created
        if (sharedInstance != null && args == null) {
            bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
        } else {
            //If sharedInstance is null
            if (this.isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            BeanFactory parentBeanFactory = this.getParentBeanFactory();
            if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
                String nameToLookup = this.originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory) {
                    return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
                }

                if (args != null) {
                    return parentBeanFactory.getBean(nameToLookup, args);
                }

                if (requiredType != null) {
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }

                return parentBeanFactory.getBean(nameToLookup);
            }

            if (!typeCheckOnly) {
                this.markBeanAsCreated(beanName);
            }

            try {
                //Get the definition of the merged bean
                RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
                //check merged bean definitions
                this.checkMergedBeanDefinition(mbd, beanName, args);
                //Gets the dependency set through @ dependsOn, which is different from the dependency referenced through the property
                String[] dependsOn = mbd.getDependsOn();
                String[] var11;
                //Check the dependency relationship. If there is a circular dependency, throw an exception directly
                if (dependsOn != null) {
                    var11 = dependsOn;
                    int var12 = dependsOn.length;
                    for(int var13 = 0; var13 < var12; ++var13) {
                        //Dependent bean name dep
                        String dep = var11[var13];
                        //Check whether the bean has circular dependency. If there is circular dependency, throw an exception directly
                        if (this.isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        //Register bean dependencies
                        this.registerDependentBean(dep, beanName);
                        //Get dependent bean s 
                        try {
                            this.getBean(dep);
                        } catch (NoSuchBeanDefinitionException var24) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", var24);
                        }
                    }
                }
                //Judge whether the scope of the bean is singleton or native
                if (mbd.isSingleton()) {
                    //If the bean is a singleton, call the getSingleton method to get the singleton bean
                    sharedInstance = this.getSingleton(beanName, () -> {
                        //The ObjectFactory here uses functional programming, and getObject() calls the createBean method below
                        try {
                            return this.createBean(beanName, mbd, args);
                        } catch (BeansException var5) {
                            this.destroySingleton(beanName);
                            throw var5;
                        }
                    });
                    bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                } else if (mbd.isPrototype()) {
                    //If the bean is native
                    var11 = null;
                    Object prototypeInstance;
                    try {
                        this.beforePrototypeCreation(beanName);
                        prototypeInstance = this.createBean(beanName, mbd, args);
                    } finally {
                        this.afterPrototypeCreation(beanName);
                    }

                    bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                } else {
                    //
                    String scopeName = mbd.getScope();
                    if (!StringUtils.hasLength(scopeName)) {
                        throw new IllegalStateException("No scope name defined for bean ยด" + beanName + "'");
                    }
                    Scope 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, () -> {
                            this.beforePrototypeCreation(beanName);
                            Object var4;
                            try {
                                var4 = this.createBean(beanName, mbd, args);
                            } finally {
                                this.afterPrototypeCreation(beanName);
                            }
                            return var4;
                        });
                        bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    } catch (IllegalStateException var23) {
                        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", var23);
                    }
                }
            } catch (BeansException var26) {
                this.cleanupAfterBeanCreationFailure(beanName);
                throw var26;
            }
        }
        //
        if (requiredType != null && !requiredType.isInstance(bean)) {
            try {
                T convertedBean = this.getTypeConverter().convertIfNecessary(bean, requiredType);
                if (convertedBean == null) {
                    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                } else {
                    return convertedBean;
                }
            } catch (TypeMismatchException var25) {
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
        } else {
            return bean;
        }
    }

DefaultSingletonBeanRegistry#getSingleton(beanName)

DefaultSingletonBeanRegistry#getSingleton(beanName,ObjectFactory)

ObjectFactory is a function interface. When calling this method, the logic injected into ObjectFactory.getObject() is to call AbstractAutowireCapableBeanFactory#createBean

AbstractAutowireCapableBeanFactory

createBean

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

        RootBeanDefinition mbdToUse = mbd;
        //1. Resolve the Bean type corresponding to beanName,
        Class<?> resolvedClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }
        // 2. Methods for verifying and preparing overrides (marking and verifying the override attribute)
        try {
            mbdToUse.prepareMethodOverrides();
        } catch (BeanDefinitionValidationException var9) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", var9);
        }

        Object beanInstance;
        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
             // 3. The processing before instantiation gives the instantiaawarebeanpostprocessor an opportunity to return the proxy object to replace the real bean instance to achieve the "short circuit" effect
            beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);
            // 3.1. If the bean is not empty, the default instantiation process of Spring will be skipped and the returned bean will be used directly
            if (beanInstance != null) {
                return beanInstance;
            }
        } catch (Throwable var10) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", var10);
        }
        // 4. Create a Bean instance (the method to actually create a Bean)
        try {
            beanInstance = this.doCreateBean(beanName, mbdToUse, args);
            //Returns the created bean
            return beanInstance;
        } catch (ImplicitlyAppearedSingletonException | BeanCreationException var7) {
            throw var7;
        } catch (Throwable var8) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", var8);
        }
    }

resolveBeforeInstantiation

    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
        Object bean = null;
        if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
            // mbd is not a composite & & there is an instantiaawarebeanpostprocessor implementation class in beanfactory
            if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
                // Resolve the type of Bean instance corresponding to beanName
                Class<?> targetType = this.determineTargetType(beanName, mbd);
                if (targetType != null) {
                    // The post processor application before instantiation calls back the postProcessBeforeInstantiation method of the instantiaawarebeanpostprocessor interface
                    bean = this.applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                    if (bean != null) {
                       // Callback the postProcessAfterInitialization method of the BeanPostProcessor implementation class
                        bean = this.applyBeanPostProcessorsAfterInitialization(bean, beanName);
                    }
                }
            }
            //If the bean is not empty, assign beforeInstantiationResolved to true, which means it has been resolved before instantiation
            mbd.beforeInstantiationResolved = bean != null;
        }
        return bean;
    }

applyBeanPostProcessorsBeforeInstantiation

	protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
            //AbstractAutoProxyCreator implements this interface
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
				if (result != null) {
					return result;
				}
			}
		}
		return null;
	}

doCreateBean

    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        //Instantiate bean
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }
        //
        if (instanceWrapper == null) {
            // Create Bean instances with corresponding policies according to beanName, mbd and args, and return the wrapper class BeanWrapper
            //There are three ways to create Bean instances
            //(1).instanceSupplier: if the instanceSupplier property in the BeanDefinition is not empty, the bean is created in this way
            //(2).beanFactory: if the BeanFactory property in the BeanDefinition is not empty, the bean is created in this way
            //(3) Through the bean constructor, use reflection technology to customize the bean construction
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }

        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }
        // Allow post-processors to modify the merged bean definition
        // Allow post processors to modify the merged bean definition
        // These POS processors are the implementation classes of MergedBeanDefinitionPostProcessor
        // The MergedBeanDefinitionPostProcessor interface inherits the BeanPostProcessor interface
        synchronized(mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                } catch (Throwable var17) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
                }
                //Setting postProcessed to true indicates that the bean definition has been executed by post processors
                mbd.postProcessed = true;
            }
        }
        // Judge whether the instance needs to be referenced in advance: Singleton & & allow circular dependency & & the current bean is being created
        boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
        if (earlySingletonExposure) {
            // Reference the ObjectFactory of beanName in advance and put it into the third level cache singletonFactories
            // When ObjectFactory is a function interface, the method name is getObject()
            // Please note: 1. Objectfactory is stored in this level of cache
            //2. Getting beans through getEarlyBeanReference is a complex process, so the L2 cache earlySingletonObjects appears
            this.addSingletonFactory(beanName, () -> {
                //This method body is executed when ObjectFactory.getObject() is called
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }
        //Initialize bean instance
        Object exposedObject = bean;
        try {
            //Fill in the attributes of the bean; If there may be properties that depend on other beans, the dependent bean instance will be recursively initialized
            this.populateBean(beanName, mbd, instanceWrapper);
            //Initialize the bean
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);
        } catch (Throwable var18) {
            if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
                throw (BeanCreationException)var18;
            }
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
        }

        //If it is a bean referenced in advance, relevant validation is performed
        if (earlySingletonExposure) {
            //Perform a circular dependency check
            Object earlySingletonReference = this.getSingleton(beanName, false);
            //earlySingletonReference is not null only if the currently resolved bean has a circular dependency
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    //If the exposedObject is not enhanced in the initializeBean method, the previous circular reference is not affected
                    exposedObject = earlySingletonReference;
                } else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
                    //If exposedObject is enhanced in initializeBean method & & it is not allowed to inject the original bean instance in the case of circular reference
                // &&The current bean is dependent on other beans
                    
                    //Get the beanName array of all beans that depend on the current bean
                    String[] dependentBeans = this.getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
                    String[] var12 = dependentBeans;
                    int var13 = dependentBeans.length;

                    for(int var14 = 0; var14 < var13; ++var14) {
                        String dependentBean = var12[var14];
                        //Try to remove instances of these beans, because the beans they depend on have been enhanced, and the beans they depend on are equivalent to dirty data
                        if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            //Remove failed add to actualDependentBeans
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    //If the removal fails, an exception is thrown because the existing bean depends on "dirty data"
                    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 beans for destruction. There are three types of beans for destruction: Custom destroy method, DisposableBean interface, and DestructionAwareBeanPostProcessor
        try {
            this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
            return exposedObject;
        } catch (BeanDefinitionValidationException var16) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
        }
    }

createBeanInstance instantiation

    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
        Class<?> beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
        } else {
            Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
            if (instanceSupplier != null) {
                return this.obtainFromSupplier(instanceSupplier, beanName);
            } else if (mbd.getFactoryMethodName() != null) {
                return this.instantiateUsingFactoryMethod(beanName, mbd, args);
            } else {
                boolean resolved = false;
                boolean autowireNecessary = false;
                if (args == null) {
                    synchronized(mbd.constructorArgumentLock) {
                        if (mbd.resolvedConstructorOrFactoryMethod != null) {
                            resolved = true;
                            autowireNecessary = mbd.constructorArgumentsResolved;
                        }
                    }
                }

                if (resolved) {
                    return autowireNecessary ? this.autowireConstructor(beanName, mbd, (Constructor[])null, (Object[])null) : this.instantiateBean(beanName, mbd);
                } else {
                    Constructor<?>[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName);
                    if (ctors == null && mbd.getResolvedAutowireMode() != 3 && !mbd.hasConstructorArgumentValues() && ObjectUtils.isEmpty(args)) {
                        ctors = mbd.getPreferredConstructors();
                        return ctors != null ? this.autowireConstructor(beanName, mbd, ctors, (Object[])null) : this.instantiateBean(beanName, mbd);
                    } else {
                        return this.autowireConstructor(beanName, mbd, ctors, args);
                    }
                }
            }
        }
    }

applyMergedBeanDefinitionPostProcessors

    protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
        Iterator var4 = this.getBeanPostProcessors().iterator();
        while(var4.hasNext()) {
            BeanPostProcessor bp = (BeanPostProcessor)var4.next();
            if (bp instanceof MergedBeanDefinitionPostProcessor) {
                MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor)bp;
                bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
            }
        }
    }

DefaultSingletonBeanRegistry#addSingletonFactory

populateBean fill attribute

   protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		if (bw == null) {
			if (mbd.hasPropertyValues()) {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
			}
			else {
				// Skip property population phase for null instance.
				return;
			}
		}

        //If the mbd is not a composite && and there is an InstantiationAwareBeanPostProcessor, the instantiawarebeanpostprocessor #postprocessafterinstance method is traversed and executed
        //Here is an opportunity for any instantiaawarebeanpostprocessor implementation class to modify the state of the bean before setting the properties of the bean
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
						return;
					}
				}
			}
		}
        //Returns the property value of this bean
		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

        //Assemble according to the set automatic assembly mode
		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// Add property values based on autowire by name if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}

		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
            //If the instantiaawarebeanpostprocessor interface is implemented, the postProcessProperties and postProcessPropertyValues methods are executed
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						if (filteredPds == null) {
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvsToUse == null) {
							return;
						}
					}
					pvs = pvsToUse;
				}
			}
		}
        //Dependency check, corresponding to the dependencies on attribute
		if (needsDepCheck) {
			if (filteredPds == null) {
				filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			}
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}

		if (pvs != null) {
            // Populate the bean with properties from all PropertyValues
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

AbstractAutoProxyCreator#postProcessAfterInstantiation

autowireByName

If autowire is set to "byName", this method is used to populate the property values of references to other bean s

protected void autowireByName(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
		for (String propertyName : propertyNames) {
			if (containsBean(propertyName)) {
				Object bean = getBean(propertyName);
				pvs.add(propertyName, bean);
				registerDependentBean(propertyName, beanName);
			}
		}
	}

autowireByType

	protected void autowireByType(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

		TypeConverter converter = getCustomTypeConverter();
		if (converter == null) {
			converter = bw;
		}

		Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
		for (String propertyName : propertyNames) {
			try {
				PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
				// Don't try autowiring by type for type Object: never makes sense,
				// even if it technically is a unsatisfied, non-simple property.
				if (Object.class != pd.getPropertyType()) {
					MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
					// Do not allow eager init for type matching in case of a prioritized post-processor.
					boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
					DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
					Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
					if (autowiredArgument != null) {
						pvs.add(propertyName, autowiredArgument);
					}
					for (String autowiredBeanName : autowiredBeanNames) {
						registerDependentBean(autowiredBeanName, beanName);
					}
					autowiredBeanNames.clear();
				}
			}
			catch (BeansException ex) {
				throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
			}
		}
	}

CommonAnnotationBeanPostProcessor/AutowiredAnnotationBeanPostProcessor#postProcessProperties

CommonAnnotationBeanPostProcessor/AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues

initializeBean initialization

Initialize the given bean instance, and apply the factory callback method, initMethod and post processor after bean initialization.

    protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(() -> {
                this.invokeAwareMethods(beanName, bean);
                return null;
            }, this.getAccessControlContext());
        } else {
            this.invokeAwareMethods(beanName, bean);
        }
        Object wrappedBean = bean;
        //Call post processor before initialization
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
        }
        //Call initialization method init method
        try {
            this.invokeInitMethods(beanName, wrappedBean, mbd);
        } catch (Throwable var6) {
            throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
        }
        //Post processor after initialization is called
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
        return wrappedBean;
    }

invokeAwareMethods

Call relevant methods according to the Aware interface implemented by bean

	private void invokeAwareMethods(String beanName, Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof BeanNameAware) {
				((BeanNameAware) bean).setBeanName(beanName);
			}
			if (bean instanceof BeanClassLoaderAware) {
				ClassLoader bcl = getBeanClassLoader();
				if (bcl != null) {
					((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
				}
			}
            //If the bean implements the BeanFactory aware interface, set BeanFactory to the bean
			if (bean instanceof BeanFactoryAware) {
				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
			}
		}
	}

applyBeanPostProcessorsBeforeInitialization

	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {
		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessBeforeInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

applyBeanPostProcessorsAfterInitialization

	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {
		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

getEarlyBeanReference

    //Gets the reference of the bean exposed in advance
    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
            Iterator var5 = this.getBeanPostProcessors().iterator();
            while(var5.hasNext()) {
                BeanPostProcessor bp = (BeanPostProcessor)var5.next();
                //AbstractAutoProxyCreator implements this interface
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor)bp;
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                }
            }
        }
        return exposedObject;
    }

BeanFactoryAware

Let the Bean implementing this interface get the reference of BeanFactory

public interface BeanFactoryAware extends Aware {
	 /**
	  *Provide the BeanFactory to the callback of the bean instance.
	  *After populating the ordinary bean properties (that is, after the populateBean() method)
	  *However, it is called before initializing callbacks, such as {@link InitializingBean#afterPropertiesSet (}} or custom initialization).
	  *
	  */
	void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}

BeanPostProcessor

postProcessBeforeInitialization

    /**
     * This method is executed before any bean initialization callback method call (such as {@ code afterpropertieset} of InitializingBean or custom initialization method). 
     * At this point, the bean has been filled with attribute values, that is, the populateBean method has been executed.
     * The returned bean instance may be the wrapped bean of the original instance.
     * The default implementation returns the given {@ code bean} as is
     *
     */
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

postProcessAfterInitialization

    /**
     * After any bean initialization callback method call (such as {@ code afterpropertieset} of InitializingBean or custom initialization method), the method will be executed. 
     * At this point, the bean has been filled with attribute values, that is, the populateBean method has been executed.
     * The returned bean instance may be the wrapped bean of the original instance.
     * The default implementation returns the given {@ code bean} as is
     *
     */
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

InstantiationAwareBeanPostProcessor

The sub interface of BeanPostProcessor, which adds callbacks before instantiation and callbacks after instantiation but before setting explicit properties or automatic assembly.

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
}

postProcessBeforeInstantiation

    //The method is called back before the target bean is instantiated
    //The returned bean object may be a proxy to replace the target bean, which effectively suppresses the default instantiation of the target bean.
	@Nullable
	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

postProcessAfterInstantiation

    //The method is called back after the bean is instantiated (through a constructor or factory method), but before Spring property filling (from explicit properties or auto assembly) occurs
    //This is an ideal callback to perform custom field injection on a given bean instance before Spring's automatic assembly begins.
    //Return true, indicating that the property should be set on the bean, and the normal implementation class of the interface should return true
    //Returns false, indicating that property filling should be skipped.
    //Returning false will also prevent any subsequent instantiaawarebeanpostprocessor instances from being called on this bean instance.
	default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		return true;
	}

postProcessProperties

    /**
     * Post-process the given property values before the factory applies them to the given bean, without any need for property descriptors.
     * Before the factory applies the given property value to the given bean, the given property value is post processed without any property descriptor.
	 * 
	 * @param pvs the property values that the factory is about to apply (never {@code null})
	 * @param bean the bean instance created, but whose properties have not yet been set
	 * @param beanName the name of the bean
	 * @return the actual property values to apply to the given bean
	 */
	@Nullable
	default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
			throws BeansException {

		return null;
	}

postProcessPropertyValues

    /**
     *Post-process the given property values before the factory applies them to the given bean. 
     *Allows for checking whether all dependencies have been satisfied, for example based on a "Required" annotation on bean property setters.
     *Also allows for replacing the property values to apply, typically through creating a new MutablePropertyValues instance based on the original PropertyValues, adding or removing specific values.
     *Post process the given property value before the factory applies the given property value to the given bean
     *Allows you to check whether all dependencies have been met, such as based on the "required" comment on the bean property setter.
     *It also allows you to replace the property values to be applied, usually by adding or deleting specific values by creating a new MutablePropertyValues instance based on the original property values.
     *
     */
    @Deprecated
	@Nullable
	default PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
		return pvs;
	}

SmartInstantiationAwareBeanPostProcessor

public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {}

predictBeanType

	//Predicts the type of bean that will eventually be returned from the {@ link #postprocessbeforeinstance} callback of the processor
    @Nullable
	default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

determineCandidateConstructors

	//Determines the candidate constructor for the given bean
	@Nullable
	default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
			throws BeansException {
		return null;
	}

getEarlyBeanReference

	//Gets a reference to an earlier access to a specified bean, usually used to resolve a circular reference.
    //The callback method gives post processors the opportunity to expose the wrapper as early as possible - that is, before the target bean instance is fully initialized.
    //Exposed objects should be equivalent to {@ link #postProcessBeforeInitialization} / {@link #postProcessAfterInitialization} objects that would otherwise be exposed.
    //Note that the object returned by this method will be used as a bean reference unless the post processor returns a different wrapper from the post-processing callback.
    default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		return bean;
	}

CommonAnnotationBeanPostProcessor

postProcessProperties

	@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
		try {
			metadata.inject(bean, beanName, pvs);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
		}
		return pvs;
	}

postProcessPropertyValues

    @Deprecated
	@Override
	public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
		return postProcessProperties(pvs, bean, beanName);
	}

AutowiredAnnotationBeanPostProcessor

postProcessProperties

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
   InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
   try {
      metadata.inject(bean, beanName, pvs);
   }
   catch (BeanCreationException ex) {
      throw ex;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
   }
   return pvs;
}

postProcessPropertyValues

	@Deprecated
	@Override
	public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {

		return postProcessProperties(pvs, bean, beanName);
	}

AbstractAutoProxyCreator

The SmartInstantiationAwareBeanPostProcessor interface inherits from the InstantiationAwareBeanPostProcessor interface.

Therefore, AbstractAutoProxyCreator generally returns proxy objects through the postprocessbeforeinstance method and postprocessbeforeinstance method of the instantiawarebeanpostprocessor interface;

  • Postprocessbeforeinstance stage: the preprocessor generally returns null. Unless there is a TargetSource, that is, the object has been created, it directly returns the modified bean
  • postProcessAfterInitialization stage: if null is returned in the postprocessbeforeinstance stage, after the object is created and initialized, use the dynamic agent through the postProcessAfterInitialization method to create an enhanced dynamic agent object according to the instance object.
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
}

postProcessBeforeInstantiation

	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
		Object cacheKey = getCacheKey(beanClass, beanName);

		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}

		// Create proxy here if we have a custom TargetSource.
		// Suppresses unnecessary default instantiation of the target bean:
		// The TargetSource will handle target instances in a custom fashion.
        // If we have a custom TargetSource, create the proxy here
		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
		if (targetSource != null) {
			if (StringUtils.hasLength(beanName)) {
				this.targetSourcedBeans.add(beanName);
			}
			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
            // Create a dynamic proxy object
			Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}
		return null;
	}

postProcessAfterInstantiation

	public boolean postProcessAfterInstantiation(Object bean, String beanName) {
		return true;
	}

getEarlyBeanReference

   //Get the reference of the bean exposed in advance 
   public Object getEarlyBeanReference(Object bean, String beanName) {
        //Generate the cacheKey corresponding to the bean
        Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
        //Put the bean into earlyProxyReferences to indicate that the bean has executed AOP
        this.earlyProxyReferences.put(cacheKey, bean);
        //Encapsulate a given bean if necessary. For example, the bean needs to be proxied
        return this.wrapIfNecessary(bean, beanName, cacheKey);
    }

postProcessAfterInitialization

    //Create a proxy with the configured interceptors if the bean is identified as one to proxy by the subclass.
    //If the bean is identified as a proxy by the subclass, a proxy is created using the configured interceptor.
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
            //If the bean has not executed AOP, it will be encapsulated. If it has, it will not be encapsulated
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                return this.wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }

wrapIfNecessary

   /**
	 * Encapsulate a given bean if necessary. For example, the bean needs to be proxied
	 * @param bean The raw bean instance
	 * @param beanName the name of the bean
	 * @param cacheKey the cache key for metadata access
	 * @return a proxy wrapping the bean, or the raw bean instance as-is
	 */
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

reference resources

Why does Spring use L3 cache instead of L2 cache to solve circular dependency

Spring L3 cache solves bean circular dependency. Why use L3 cache instead of L2 cache

Understanding of other netizens

This is not to say that if there is aop in the L2 cache, the proxy object cannot be injected. In essence, it should be said that the initial spring does not solve the circular reference problem. The design principle is to generate aop objects after bean instantiation, property setting and initialization. However, in order to solve the circular dependency, but try not to break this design principle, The third level cache with functional interface is used;

If you use L2 cache, you can advance the proxy work of aop to the stage of exposing instances in advance; In other words, all beans become proxy objects during the creation process, and then initialize and other work; However, this is contrary to the design principle of spring's aop. The implementation of aop needs to be separated from the creation of the normal life cycle of beans;

In this way, only the third level cache is used to encapsulate a functional interface object into the cache. When circular dependency occurs, the generation of proxy class is triggered;

The life cycle of Bean in Spring

Tags: Java Spring Spring Boot Cache

Posted on Thu, 30 Sep 2021 01:01:05 -0400 by Scottmandoo