Detailed explanation of Spring IoC createBean method

preface

This article mainly analyzes the flow of the createBean() method of Spring IoC and the bean life cycle.

Here is a general flow chart:

text

AbstractAutowireCapableBeanFactory#createBean

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

    if (logger.isTraceEnabled()) {
        logger.trace("Creating instance of bean '" + beanName + "'");
    }
    RootBeanDefinition mbdToUse = mbd;

    // Make sure bean class is actually resolved at this point, and
    // clone the bean definition in case of a dynamically resolved Class
    // which cannot be stored in the shared merged bean definition.
    // Convert a class String of String type to a class object, such as the class attribute configured in XML
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    // Prepare method overrides.
    try {
        // Method override defined
        mbdToUse.prepareMethodOverrides();
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                                               beanName, "Validation of method overrides failed", ex);
    }

    try {
        // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
        // If the callback method returns non null before instantiation of the bean, return to the instance directly, and skip the following steps
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                                        "BeanPostProcessor before instantiation of bean failed", ex);
    }

    try {
        // The real way to create bean s
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isTraceEnabled()) {
            logger.trace("Finished creating instance of bean '" + beanName + "'");
        }
        // Returns an instance of the bean
        return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
        // A previously detected exception with proper bean creation context already,
        // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
        throw ex;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
            mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
    }
}

If resolveBeforeInstantiation() returns non null, the above method will skip the following steps and return the instance directly. This is also an extension point, giving BeanPostProcessor a chance to return a proxy to replace the real instance.

AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    // Determine whether the bean has been parsed before instantiation
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // Make sure bean class is actually resolved at this point.
        // If the bean is a composite & & there is an interface to implement the instantiaionawarebeanpostprocessor
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            // Resolving bean types
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                // Execute the pre instantiation callback of the bean
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                // If the life cycle callback method does not return null before instantiation
                if (bean != null) {
                    // Execute the callback after instantiation of the bean, because it can only be called here
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        // If the bean is not empty, value beforeInstantiationResolved to true, which means it has been resolved before instantiation
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}

The above method is mainly to judge that the bean has not been resolved before and has registered the instantiaawarebeanpostprocessor interface, and then the callback method before the bean instantiation will be called here. If the return is not empty, the callback method after the bean instantiation will be called; because the return is not empty, the subsequent normal process will not go, so it can only be called here.

The following is the interface of instantialoawarebanpostprocessor, as follows:

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

  /**
  * Bean Before instantiation, the non {@code null} IoC container is instantiated and the subsequent lifecycle callback method does not instantiate the Bean.
  * Call, return {@ code null} to instantiate the Bean by the IoC container
  */
  @Nullable
  default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    return null;
  }

  /**
  * Bean After instantiation, the {@code true} is returned before the attribute is filled, then the default attribute fill step is returned, and the {@code false} is returned.
  * The property fill phase is skipped, as is the callback of the lifecycle method in the initialization phase
  */
  default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    return true;
  }

  /**
  * Bean After instantiation, it is called before attribute assignment. PropertyValues is an attribute value that has been encapsulated and returned to {@code null} to continue.
  * Use existing properties, otherwise PropertyValues will be replaced
  */
  @Nullable
  default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
    return null;
  }

  /**
  * It's the same as the above method, but it's used by the previous version
  */
  @Deprecated
  @Nullable
  default PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
    return pvs;
  }

}

The above interface provides three extension points, as follows:

  • Before bean instantiation
  • After bean instantiation
  • Before bean property assignment

This is also the life cycle callback method for bean instantiation.

AbstractAutowireCapableBeanFactory#doCreateBean

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

    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        // If the scope of the bean is singleton, you need to remove the cache of the unfinished FactoryBean instance
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        // Create an instance of the bean through constructor reflection, but the property is not assigned
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    // Get an instance of the bean
    final Object bean = instanceWrapper.getWrappedInstance(); 
    // Get the type of bean
    Class<?> beanType = instanceWrapper.getWrappedClass(); 
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }

    // Allow post-processors to modify the merged bean definition.
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                // The callback after BeanDefinition merging is explained in detail below
                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 to be able to resolve circular references
    // even when triggered by lifecycle interfaces like BeanFactoryAware.
    // The scope of the bean is singleton & & allow circular reference & & currently the bean is being created
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
    // If the bean is allowed to be exposed in advance
    if (earlySingletonExposure) {
        if (logger.isTraceEnabled()) {
            logger.trace("Eagerly caching bean '" + beanName +
                         "' to allow for resolving potential circular references");
        }
        // Put the key value pair formed by beanName and ObjectFactory into the singleton factories cache
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
        // Assign values to bean properties
        populateBean(beanName, mbd, instanceWrapper);
        // Initialize bean
        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 the singleton bean is allowed to be exposed in advance
    if (earlySingletonExposure) {
        Object earlySingletonReference = getSingleton(beanName, false);
        // Not null only if circular dependency is detected
        if (earlySingletonReference != null) {
            // If the exposedObject is not changed in the initialization method, it is not enhanced
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
            } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                String[] dependentBeans = getDependentBeans(beanName);
                Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                // Detect dependency
                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 " +
										"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                }
            }
        }
    }

    // Register bean as disposable.
    try {
        // For registering destroy bean s
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    } catch (BeanDefinitionValidationException ex) {
        throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }
    // Return bean instance
    return exposedObject;
}

AbstractAutowireCapableBeanFactory#createBeanInstance

/**
* @param args	  getBean() args parameter in
* @return 		  bean BeanWrapper after instance wrapping
*/
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // Make sure bean class is actually resolved at this point.
    // Resolving bean types
    Class<?> beanClass = resolveBeanClass(mbd, beanName);
    // Judge whether the beanClass is a public decorated class and whether access to non-public constructors and methods is allowed, instead of throwing an exception
    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());
    }
    // New to Spring 5, if there is a Supplier callback, the given callback method is used to initialize the policy. You can set rootbeandefinition ා setinstancesupplier()
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }
    // If the factory method is set, the bean instance is created with the given method, which is divided into static factory and instance factory
    if (mbd.getFactoryMethodName() != null) {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    // Shortcut when re-creating the same bean...
    // Resolved: whether the constructor or factory method has been resolved
    boolean resolved = false;
    // autowireNecessary: whether auto injection is required (i.e. whether a parse constructor is required)
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (mbd.constructorArgumentLock) {
            // If resolvedConstructorOrFactoryMethod is not empty, it means that the constructor or factory method has been resolved
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                // Judge whether automatic injection is needed according to constructor arguments resolved
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }
    if (resolved) {
        if (autowireNecessary) {
            // If the constructor or factory method has been parsed and auto injection is required, perform auto injection of the constructor, as explained below
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            // Otherwise, use the default constructor to instantiate the bean, as detailed below
            return instantiateBean(beanName, mbd);
        }
    }

    // Candidate constructors for autowiring?
    // After applying the postprocessor, smartinstantiaionawarebeanpostprocessor gets the candidate constructor of the bean
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    // Candidate constructor is not empty | | constructor dependency injection | | parameter value of defined constructor | | args is not empty, execute constructor auto injection
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
        mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // Preferred constructors for default construction?
    // If there is a preferred constructor, use it to create a bean instance
    ctors = mbd.getPreferredConstructors();
    if (ctors != null) {
        return autowireConstructor(beanName, mbd, ctors, null);
    }

    // No special handling: simply use no-arg constructor.
    // No special handling, instantiate the bean with the default parameterless constructor
    return instantiateBean(beanName, mbd);
}

The above code mainly determines whether to use constructor auto injection or default constructor construction. To sum up, the following situations are automatically injected using the constructor:

  • The constructor has been cached and its parameters resolved.
  • The candidate constructor is not empty. Here, the candidate constructor implements the determineCandidateConstructors() in the smartinstantiaawarebeanpostprocessor interface
  • Auto injection mode auto injection for constructors
  • BeanDefinition defines constructor parameters, such as < constructor Arg index = "0" value = "1" / > in XML
  • The args parameter is specified when getBean() is called

AbstractAutowireCapableBeanFactory#instantiateBean

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
    try {
        Object beanInstance;
        final BeanFactory parent = this;
        if (System.getSecurityManager() != null) {
            beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                                                         getInstantiationStrategy().instantiate(mbd, beanName, parent),
                                                         getAccessControlContext());
        }
        else {
            // Use the specified policy to de strength the bean
            beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
        }
        // Encapsulate the instantiated bean as a BeanWrapper and return
        BeanWrapper bw = new BeanWrapperImpl(beanInstance);
        initBeanWrapper(bw);
        return bw;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
    }
}

// SimpleInstantiationStrategy.java
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    // Don't override the class with CGLIB if no overrides.
    // If there are methods that need to be overridden or replaced dynamically, CGLIB is of course needed for dynamic proxy, because methods can be woven into classes at the same time of proxy creation
    // But if there's no way to change dynamically, you can use reflection directly for convenience
    if (!bd.hasMethodOverrides()) {
        Constructor<?> constructorToUse;
        synchronized (bd.constructorArgumentLock) {
            // Get the constructor or factory method of the cache
            constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
            // Cache is empty
            if (constructorToUse == null) {
                final Class<?> clazz = bd.getBeanClass();
                // Throw an exception if clazz is an interface
                if (clazz.isInterface()) {
                    throw new BeanInstantiationException(clazz, "Specified class is an interface");
                }
                try {
                    if (System.getSecurityManager() != null) {
                        constructorToUse = AccessController.doPrivileged(
                            (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
                    }
                    else {
                        // Get the default parameterless constructor
                        constructorToUse = clazz.getDeclaredConstructor();
                    }
                    // Set cache
                    bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                }
                catch (Throwable ex) {
                    throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                }
            }
        }
        // This is to instantiate the bean with the specified parameterless constructor, without any specific analysis
        return BeanUtils.instantiateClass(constructorToUse);
    }
    else {
        // Must generate CGLIB subclass.
        // A method of generating subclass dynamic weaving rewriting with CGLIB
        return instantiateWithMethodInjection(bd, beanName, owner);
    }
}

The above code is relatively simple. It just uses the default parameterless constructor to instantiate the bean and encapsulate it as a BeanWrapper return.

ConstructorResolver#autowireConstructor

protected BeanWrapper autowireConstructor(
			String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
	// Find a suitable constructor and instantiate it
    return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}

public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
			@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {

    BeanWrapperImpl bw = new BeanWrapperImpl();
    this.beanFactory.initBeanWrapper(bw);
    // Final instantiated constructor
    Constructor<?> constructorToUse = null;
    // The final parameter Holder for instantiation
    ArgumentsHolder argsHolderToUse = null;
    // Constructor parameters that are ultimately used for instantiation
    Object[] argsToUse = null;
    // If explicitArgs is not empty, use explicitArgs as the constructor function parameter
    if (explicitArgs != null) {
        argsToUse = explicitArgs;
    }
    else {
        Object[] argsToResolve = null;
        synchronized (mbd.constructorArgumentLock) {
            // Get cached constructor or factory method
            constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
            if (constructorToUse != null && mbd.constructorArgumentsResolved) {
                // Found a cached constructor...
                // Get cached constructor parameters
                argsToUse = mbd.resolvedConstructorArguments;
                if (argsToUse == null) {
                    // If the constructor or factory method is already cached, resolvedConstructorArguments and preparedConstructorArguments must have one cached constructor parameter
                    argsToResolve = mbd.preparedConstructorArguments;
                }
            }
        }
        if (argsToResolve != null) {
            // If argsToResolve is not empty, the constructor parameter will be parsed, that is, operation such as type conversion will be performed
            // For example, A(int,int) converts ("1", "1") in the configuration to (1,1)
            argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
        }
    }
    // If there is no cache constructor or its parameters
    if (constructorToUse == null || argsToUse == null) {
        // Take specified constructors, if any.
        Constructor<?>[] candidates = chosenCtors;
        if (candidates == null) {
            Class<?> beanClass = mbd.getBeanClass();
            try {
                // If access to non public constructors and methods is allowed (the default value is true), all constructors will be obtained, otherwise only public decorated constructors will be obtained
                candidates = (mbd.isNonPublicAccessAllowed() ?
                              beanClass.getDeclaredConstructors() : beanClass.getConstructors());
            }
            catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                                "Resolution of declared constructors on bean Class [" + beanClass.getName() +
                                                "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
            }
        }
        // If there is only one constructor & & getbean() does not display the parameter value of the specified args & & no constructor defined
        if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
            // Get constructor
            Constructor<?> uniqueCandidate = candidates[0];
            if (uniqueCandidate.getParameterCount() == 0) {
                synchronized (mbd.constructorArgumentLock) {
                    // Set cache for constructors and parameters
                    mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
                    mbd.constructorArgumentsResolved = true;
                    mbd.resolvedConstructorArguments = EMPTY_ARGS;
                }
                // Create an instance of the bean through the parameterless constructor and return directly
                bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
                return bw;
            }
        }

        // Need to resolve the constructor.
        // If the candidate constructor is not empty, the constructor will inject the mode automatically
        boolean autowiring = (chosenCtors != null || mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
        ConstructorArgumentValues resolvedValues = null;

        int minNrOfArgs;
        // getBean() shows that the parameter is specified and gets the parameter length
        if (explicitArgs != null) {
            minNrOfArgs = explicitArgs.length;
        }
        else {
            // Get defined constructor parameters
            ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
            resolvedValues = new ConstructorArgumentValues();
            // Resolves the constructor parameter and assigns it to resolvedValues to return the number of parameters. See details below
            minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
        }
        // Here we sort the constructors according to the following rules: first, public constructors and the number of parameters are from more to less, then non public constructors and the number of parameters is from more to less
        AutowireUtils.sortConstructors(candidates);
        // Minimum matching weight, the smaller the weight, the closer to the target constructor we are looking for
        int minTypeDiffWeight = Integer.MAX_VALUE;
        Set<Constructor<?>> ambiguousConstructors = null;
        LinkedList<UnsatisfiedDependencyException> causes = null;
        // Traverse the constructor to find the matching one
        for (Constructor<?> candidate : candidates) {
            // Get the number of parameters
            int parameterCount = candidate.getParameterCount();
            // If a satisfied constructor has been found & & the number of target constructor parameters is greater than the number of currently traversed constructor parameters, terminate
            // Because constructors are already ordered, there won't be any more suitable ones
            if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) {
                // Already found greedy constructor that can be satisfied ->
                // do not look any further, there are only less greedy constructors left.
                break;
            }
            // If the number of constructor parameters of the target is less than what we need, skip directly
            if (parameterCount < minNrOfArgs) {
                continue;
            }

            ArgumentsHolder argsHolder;
            // Get parameter type to constructor
            Class<?>[] paramTypes = candidate.getParameterTypes();
            if (resolvedValues != null) {
                try {
                    // To evaluate the parameter name is to determine whether the @ ConstructorProperties annotation is marked on the constructor. If it is marked, take the parameter name defined in it directly
                    String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
                    // The @ ConstructorProperties annotation is not marked. Use the parameter name parser to get the parameter name
                    if (paramNames == null) {
                        ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                        if (pnd != null) {
                            paramNames = pnd.getParameterNames(candidate);
                        }
                    }
                    // Create an array of parameters to call a constructor or factory method, as explained below
                    // It mainly resolves the parameters required by the constructor or factory method through the parameter type and parameter name (if the parameter is another bean, it will resolve the dependent bean)
                    argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
                }
                catch (UnsatisfiedDependencyException ex) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
                    }
                    // Swallow and try next constructor.
                    if (causes == null) {
                        causes = new LinkedList<>();
                    }
                    causes.add(ex);
                    continue;
                }
            }
            // resolvedValues is empty, explicitArgs is not empty, that is, the args parameter of getBean() is specified
            else {
                // Explicit arguments given -> arguments length must match exactly.
                // If the length of explicitArgs is not equal to the number of parameters of the current constructor, skip the constructor directly
                if (parameterCount != explicitArgs.length) {
                    continue;
                }
                // Encapsulate explicit args into argumentholder
                argsHolder = new ArgumentsHolder(explicitArgs);
            }
            // According to mbd's parsing constructor mode (true: loose mode, false: strict mode)
            // Compare argsHolder's parameters with paramTypes, and calculate the type difference weight value of paramTypes
            int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                                  argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
            // Choose this constructor if it represents the closest match.
            // The smaller the difference value is, the more matching the constructor is, then select this constructor
            if (typeDiffWeight < minTypeDiffWeight) {
                constructorToUse = candidate;
                argsHolderToUse = argsHolder;
                argsToUse = argsHolder.arguments;
                minTypeDiffWeight = typeDiffWeight;
                // If there is a candidate with a lower weight value, clear the ambiguousConstructors, and allow the previous candidates with the same weight value to exist
                ambiguousConstructors = null;
            }
            // The weight values of the two candidates are the same, and the weight values of the current traversal are the lowest
            else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
                // Add two candidates to the ambient constructors
                if (ambiguousConstructors == null) {
                    ambiguousConstructors = new LinkedHashSet<>();
                    ambiguousConstructors.add(constructorToUse);
                }
                ambiguousConstructors.add(candidate);
            }
        }
        // No matching constructor found, exception thrown
        if (constructorToUse == null) {
            if (causes != null) {
                UnsatisfiedDependencyException ex = causes.removeLast();
                for (Exception cause : causes) {
                    this.beanFactory.onSuppressedException(cause);
                }
                throw ex;
            }
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                            "Could not resolve matching constructor " +
                                            "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
        }
        // Throw an exception if there are multiple matching candidates and they are not loose patterns
        else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                            "Ambiguous constructor matches found in bean '" + beanName + "' " +
                                            "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " + ambiguousConstructors);
        }
        // getBean() method does not specify args Parameter & & constructor parameter is not empty
        if (explicitArgs == null && argsHolderToUse != null) {
            // Cache parsed constructors and parameters
            argsHolderToUse.storeCache(mbd, constructorToUse);
        }
    }

    Assert.state(argsToUse != null, "Unresolved constructor arguments");
    // Using reflection to create bean instance
    bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
    return bw;
}

The functions of the above codes are as follows:

  1. Determination of constructor parameters
    • If the explicitArgs parameter is not empty, the parameter can be determined directly. Because the explicitArgs parameter is specified manually when getBean() is called, this parameter is mainly used for static factory method calls.
    • If the cache is not empty, it can be used directly.
    • Read from BeanDefinition, all the beans we defined will generate a BeanDefinition, in which the constructor parameters defined are recorded and obtained through getConstructorArgumentValues().
  2. Determination of the constructor. After the first step, the parameters of the constructor have been determined, and then the number of parameters is used to lock the corresponding constructor in all constructors. Before matching, the constructors will be sorted. First, the public constructors are used and the number of parameters is from many to few. Then, the non public constructors are used and the number of parameters is from many to few. In this way, you can quickly determine whether the number of constructor parameters in the next row meets the conditions.
  3. Convert the corresponding parameter type according to the corresponding constructor.
  4. Instantiate the bean according to the instantiation policy and the resulting constructor and constructor parameters.

ConstructorResolver#resolveConstructorArguments

private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
			ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) {
    // Get custom type converter
    TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
    TypeConverter converter = (customConverter != null ? customConverter : bw); 
    // Use bw if there is no custom converter
    BeanDefinitionValueResolver valueResolver =
        new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
    // minNrOfArgs initialized to indexedArgumentValues+genericArgumentValues
    int minNrOfArgs = cargs.getArgumentCount();
    // Traverse IndexArgumentValues, where IndexArgumentValues have subscripts, such as < constructor Arg index = "0" value = "1" / >
    for (Map.Entry<Integer, ConstructorArgumentValues.ValueHolder> entry : cargs.getIndexedArgumentValues().entrySet()) {
        int index = entry.getKey();
        if (index < 0) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                            "Invalid constructor argument index: " + index);
        } 
        // If the index is greater than minNrOfArgs, modify the minNrOfArgs value
        if (index > minNrOfArgs) {
            // Because index is the subscript value of the constructor, add 1 to the total
            minNrOfArgs = index + 1; 
        }
        ConstructorArgumentValues.ValueHolder valueHolder = entry.getValue();
        // If the parameter type has been converted, add it directly to resolvedValues
        if (valueHolder.isConverted()) { 
            resolvedValues.addIndexedArgumentValue(index, valueHolder);
        }
        // Parameter type has not been converted, convert
        else { 
            Object resolvedValue =
                valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
            // Building ValueHolder with converted parameter values
            ConstructorArgumentValues.ValueHolder resolvedValueHolder = 
						new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName());
            resolvedValueHolder.setSource(valueHolder); 
            // Add to resolvedValues
            resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder);
        }
    }
    // Traverse GenericArgumentValues and perform type conversion as above. GenericArgumentValues here have no subscript specified, for example: < constructor Arg value = "1" / >
    for (ConstructorArgumentValues.ValueHolder valueHolder : cargs.getGenericArgumentValues()) {
        if (valueHolder.isConverted()) {
            resolvedValues.addGenericArgumentValue(valueHolder);
        }
        else {
            Object resolvedValue =
                valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
            ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder(
                resolvedValue, valueHolder.getType(), valueHolder.getName());
            resolvedValueHolder.setSource(valueHolder);
            resolvedValues.addGenericArgumentValue(resolvedValueHolder);
        }
    }
    // Number of return parameters
    return minNrOfArgs;
}

The above code mainly calls resolveValueIfNecessary() to resolve the values of indexedArgumentValues and genericArgumentValues; resolveValueIfNecessary() mainly resolves the types of parameters, such as beanName referenced by ref property will return an instance through getBean().

ConstructorResolver#createArgumentArray

private ArgumentsHolder createArgumentArray(
    String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable,boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {
    // Get type converter
    TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
    TypeConverter converter = (customConverter != null ? customConverter : bw);
    // Building argumentholder
    ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
    Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);
    Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
    // Traversal parameter type array
    for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
        // Get parameter type and name
        Class<?> paramType = paramTypes[paramIndex]; 
        String paramName = (paramNames != null ? paramNames[paramIndex] : "");
        // Try to find matching constructor argument value, either indexed or generic.
        ConstructorArgumentValues.ValueHolder valueHolder = null;
        if (resolvedValues != null) {
            // Query whether there is a match based on the subscript, type and name of the parameter
            valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders);
            // If we couldn't find a direct match and are not supposed to autowire,
            // let's try the next generic, untyped argument value as fallback:
            // it could match after type conversion (for example, String -> int).
            // There is no matching & & not auto assemble. Try the next generic type free parameter value as a demotion method that matches after a type conversion (for example, string - > int)
            if (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) {
                valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);
            }
        }
        // Matching valueHolder found
        if (valueHolder != null) {
            // We found a potential match - let's give it a try.
            // Do not consider the same value definition multiple times!
            // Add to usedValueHolders
            usedValueHolders.add(valueHolder);
            Object originalValue = valueHolder.getValue();
            Object convertedValue;
            // Type has been converted
            if (valueHolder.isConverted()) {
                // Get the converted value as the preparatory parameter of args in paramIndex
                convertedValue = valueHolder.getConvertedValue();
                args.preparedArguments[paramIndex] = convertedValue;
            }
            // Type has not been converted
            else {
                // Encapsulate construction methods and parameter subscripts into MethodParameter(MethodParameter is a tool class encapsulating methods and parameter indexes)
                MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
                try {
                    // Convert the original value to a value of type paramType, throw an exception if it cannot be converted
                    convertedValue = converter.convertIfNecessary(originalValue, paramType, methodParam);
                }
                catch (TypeMismatchException ex) {
                    throw new UnsatisfiedDependencyException(
                        mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
                        "Could not convert argument value of type [" +
										ObjectUtils.nullSafeClassName(valueHolder.getValue()) +
										"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
                }
                Object sourceHolder = valueHolder.getSource();
                if (sourceHolder instanceof ConstructorArgumentValues.ValueHolder) {
                    Object sourceValue = ((ConstructorArgumentValues.ValueHolder) sourceHolder).getValue();
                    // Tag args needs to be resolved
                    args.resolveNecessary = true;
                    // Use sourceValue as a preliminary parameter for args at paramIndex
                    args.preparedArguments[paramIndex] = sourceValue;
                }
            }
            // Use convertedValue as args parameter at paramIndex
            args.arguments[paramIndex] = convertedValue;
            //  Use originalValue as the original parameter of args at paramIndex
            args.rawArguments[paramIndex] = originalValue;
        }
        // No matching valueHolder found
        else {
            // Encapsulate constructor and parameter subscript as MethodParameter
            MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
            // No explicit match found: we're either supposed to autowire or
            // have to fail creating an argument array for the given constructor.
            // No explicit match found, not auto inject, exception thrown
            if (!autowiring) {
                throw new UnsatisfiedDependencyException(
							mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
                    "Ambiguous argument values for parameter of type [" + paramType.getName() +
                    "] - did you specify the correct bean references as arguments?");
            }
            try {
                // If it is auto injection, use resolveAutowiredArgument() to parse the parameters, as detailed below
                // Parameter bean s in constructor auto injection are processed here
                Object autowiredArgument = resolveAutowiredArgument(
                    methodParam, beanName, autowiredBeanNames, converter, fallback);
                // Assign the parameters resolved through automatic assembly to args
                args.rawArguments[paramIndex] = autowiredArgument;
                args.arguments[paramIndex] = autowiredArgument;
                args.preparedArguments[paramIndex] = autowiredArgumentMarker;
                args.resolveNecessary = true;
            }
            catch (BeansException ex) {
                throw new UnsatisfiedDependencyException(
                    mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);
            }
        }
    }
    // If you depend on other beans, register the dependencies (autowiredBeanNames here are all the dependent bean names)
    for (String autowiredBeanName : autowiredBeanNames) {
        this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
        if (logger.isDebugEnabled()) {
            logger.debug("Autowiring by type from bean name '" + beanName +
                         "' via " + (executable instanceof Constructor ? "constructor" : "factory method") +
                         " to bean named '" + autowiredBeanName + "'");
        }
    }
	// Return the parsed parameter value
    return args;
}

The above code determines that if there is a matching parameter in the constructor, it will be converted to the corresponding type. If there is no matching parameter, most of it is the constructor's automatic injection. Through resolveAutowiredArgument(), find the bean and return the instance.

ConstructorResolver#resolveAutowiredArgument

protected Object resolveAutowiredArgument(MethodParameter param, String beanName,
                                          @Nullable Set<String> autowiredBeanNames, TypeConverter typeConverter, boolean fallback) {
    // Get the type of parameter
    Class<?> paramType = param.getParameterType();
    // If the parameter type is InjectionPoint
    if (InjectionPoint.class.isAssignableFrom(paramType)) {
        // Get the current InjectionPoint (store the method parameter information that is currently resolving the dependency, DependencyDescriptor)
        InjectionPoint injectionPoint = currentInjectionPoint.get();
        if (injectionPoint == null) {
            // If the current injectionpoint is empty, an exception will be thrown: there is no currently available injectionpoint
            throw new IllegalStateException("No current InjectionPoint available for " + param);
        }
        // The current injectionPoint is not empty, directly return
        return injectionPoint;
    }
    try {
        // Resolve the specified dependency, DependencyDescriptor: encapsulate the method parameter index information of MethodParameter into DependencyDescriptor, as detailed below
        return this.beanFactory.resolveDependency(
					new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
    }
    catch (NoUniqueBeanDefinitionException ex) {
        throw ex;
    }
    catch (NoSuchBeanDefinitionException ex) {
        if (fallback) {
            // Single constructor or factory method -> let's return an empty array/collection
            // for e.g. a vararg or a non-null List/Set/Map parameter.
            if (paramType.isArray()) {
                return Array.newInstance(paramType.getComponentType(), 0);
            }
            else if (CollectionFactory.isApproximableCollectionType(paramType)) {
                return CollectionFactory.createCollection(paramType, 0);
            }
            else if (CollectionFactory.isApproximableMapType(paramType)) {
                return CollectionFactory.createMap(paramType, 0);
            }
        }
        throw ex;
    }
}

We usually only need to focus on the above code this.beanFactory.resolveDependency() this is the secret of solving dependency injection.

DefaultListableBeanFactory#resolveDependency

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
                                @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

    descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
    // Processing of Optional type indicates that Spring can also inject parameters of Optional type
    if (Optional.class == descriptor.getDependencyType()) {
        return createOptionalDependency(descriptor, requestingBeanName);
    }
    // Handling of ObjectFactory or ObjectProvider types
    else if (ObjectFactory.class == descriptor.getDependencyType() ||
             ObjectProvider.class == descriptor.getDependencyType()) {
        return new DependencyObjectProvider(descriptor, requestingBeanName);
    }
    // javax.inject.Provider Handling of type
    else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
        return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
    }
    else {
        // Get delay resolution agent
        Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
        if (result == null) {
            // Resolve the dependency. The returned result is the bean instance that needs to be injected. See details below
            result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
        }
        return result;
    }
}

The above code mainly judges that if the type of bean to be injected is Optional, ObjectFactory, ObjectProvider and Provider, special processing will be done. In general, the injected bean will go to the last donresolvedependency(). Another important parameter DependencyDescriptor is the dependency descriptor, which stores the type of bean to be injected, the subscript of the constructor parameter (constructor injection value is not empty), whether it is required, the field name (field injection value is not empty), the method name (setter method injection value is not empty), etc.

DefaultListableBeanFactory#doResolveDependency

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

    InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
    try {
        // Get the shortcut to the bean to be injected, and return directly if it is not empty
        Object shortcut = descriptor.resolveShortcut(this);
        if (shortcut != null) {
            return shortcut;
        }
        // Get the type of bean to be injected
        Class<?> type = descriptor.getDependencyType();
        // Used to support the new annotation @ Value in Spring (determine whether the given dependency declares the @ Value annotation, and get the Value if any)
        Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
        if (value != null) {
            if (value instanceof String) {
                String strVal = resolveEmbeddedValue((String) value);
                BeanDefinition bd = (beanName != null && containsBean(beanName) ?
                                     getMergedBeanDefinition(beanName) : null);
                value = evaluateBeanDefinitionString(strVal, bd);
            }
            TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
            try {
                return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
            }
            catch (UnsupportedOperationException ex) {
                // A custom TypeConverter which does not support TypeDescriptor resolution...
                return (descriptor.getField() != null ?
                        converter.convertIfNecessary(value, type, descriptor.getField()) :converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
            }
        }
        // Analyze multiplebeans, such as Array, Collection, Map
        Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
        if (multipleBeans != null) {
            return multipleBeans;
        }
        // Matching beans (key: beanname value: if the bean already has an instance cached (for example, a single bean will cache its instance),
        // Is the bean instance, otherwise it is the corresponding class object)
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
        if (matchingBeans.isEmpty()) {
            // If no matching bean is found, judge whether it is necessary. If not, return null directly. Otherwise, throw an exception
            if (isRequired(descriptor)) {
                raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
            }
            return null;
        }

        String autowiredBeanName;
        Object instanceCandidate;
        // If there are multiple matching candidates
        if (matchingBeans.size() > 1) {
            // Judge the best candidate, that is, find the best matching bean name
            autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
            if (autowiredBeanName == null) {
                if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
                    return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
                }
                else {
                    // In case of an optional Collection/Map, silently ignore a non-unique case:
                    // possibly it was meant to be an empty collection of multiple regular beans
                    // (before 4.3 in particular when we didn't even look for collection beans).
                    return null;
                }
            }
            // Get the value corresponding to autowiredBeanName (bean instance or bean instance type)
            instanceCandidate = matchingBeans.get(autowiredBeanName);
        }
        else {
            // We have exactly one match.
            // Only one matching bean was found
            Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
            autowiredBeanName = entry.getKey();
            instanceCandidate = entry.getValue();
        }

        if (autowiredBeanNames != null) {
            // Add dependent beannames to autowiredBeanNames
            autowiredBeanNames.add(autowiredBeanName);
        }
        // If the bean to be injected does not have a cache instance, instanceCandidate is a Class object, and then get the corresponding instance according to getBean()
        if (instanceCandidate instanceof Class) {
            instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
        }
        Object result = instanceCandidate;
        if (result instanceof NullBean) {
            if (isRequired(descriptor)) {
                raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
            }
            result = null;
        }
        if (!ClassUtils.isAssignableValue(type, result)) {
            throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
        }
        // Return the bean instance that needs to be injected finally
        return result;
    }
    finally {
        ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
    }
}

The above code is really to get the bean to be injected, which is roughly divided into the following steps:

  1. Check whether there is a shortcut to get whether the injection bean is empty, and return directly if it is not empty. The shortcut here is by inheriting the DependencyDescriptor and overriding resolveShortcut().

  2. If the parameter is decorated with @ Value annotation, if the Value is obtained, it will be returned directly.

  3. Analyze the MultipleBean. The MultipleBean here is generally Array, Collection, Map, which is returned directly without being empty.

  4. Find all matching beans according to the type. There are two situations for the value of the key in matchingBeans: beanName and value. If the bean has cached the instance (for example, a single bean will cache its instance), it is the bean instance, otherwise it is the corresponding class object.

  5. Matchbeans is empty. Judge whether the bean to be injected is required. If an exception is thrown, null will be returned.

  6. matchingBeans is longer than 1, which means there are multiple candidates. The best candidate is selected according to the following rules:

    1. First, find the one whose primary attribute is true.
    2. Find the one with the highest Priority, implement the PriorityOrdered interface or annotate @ Priority annotation.
    3. Find that the name matches.
  7. Only one candidate, direct use.

  8. If the bean to be injected does not have a cache instance, instanceCandidate is a Class object, and then get the corresponding instance according to getBean().

  9. Finally, the bean instance to be injected is returned.

AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof MergedBeanDefinitionPostProcessor) {
            MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
            bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
        }
    }
}

The above code is very simple. All you need is to get all registered beanpostprocessors, and then traverse to determine whether they are of the type of mergedbeandefinitionpostprocessor. If yes, you can make a method callback after the BeanDefinition is merged. In this callback method, you can make some changes to the BeanDefinition of the specified bean.

Let's take a brief look at the methods in the MergedBeanDefinitionPostProcessor interface:

public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {

    /**
    * Processing method callback after merging BeanDefinition of the specified bean
    */
    void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);

    /**
    * Notifies that the BeanDefinition of the specified beanName has been reset, and that all metadata of the affected bean should be cleared if the method is implemented
    * @since 5.1
    */
    default void resetBeanDefinition(String beanName) {
        
    }

}

DefaultSingletonBeanRegistry#addSingletonFactory

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(singletonFactory, "Singleton factory must not be null");
    // Lock up
    synchronized (this.singletonObjects) {
        // If the single bean cache does not contain the current bean name
        if (!this.singletonObjects.containsKey(beanName)) {
            // Add the ObjectFactory that created the instance to the cache
            this.singletonFactories.put(beanName, singletonFactory);
            // Remove beans from the early singleton bean cache
            this.earlySingletonObjects.remove(beanName);
            // Add beanName to the registered singleton bean cache
            this.registeredSingletons.add(beanName); 
        }
    }
}

In the above code, ObjectFactory is added to the singletonFactories cache. The following is the declaration of singletonFactories:

/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

Take a simple AB circular dependency as an example. Class A contains attribute class B, and class B contains attribute class A. Then, the process of initializing beanA is as follows:

Spring's methods for solving circular dependency are in the addSingletonFactory() and getBean() methods. First, when creating beanA, encapsulate the instantiated beanA as ObjectFactory and put it into singletonFactories cache, and then fill in the attribute; because beanB is dependent, instantiate beanB first, then fill in the beanB attribute, and call getBean() to get the beanA instance if beanA is needed. As mentioned in the previous article, getBean() will first determine whether there is a created bean or beanFactory in the cache, as shown in the following code:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // Check whether the single instance transmission exists
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        // If it is empty and the current bean is being created, lock the global variable for processing
        synchronized (this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                // When some methods need to be initialized in advance, the addSingletonFactory method will be called
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    // Call the preset getObject(), and the bean a of the unfilled property will be returned
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

Because beanA and beanA in beanB represent the same attribute address, the created attribute filling in beanA can be obtained by beanA in beanB naturally, which solves the problem of circular dependency.

AbstractAutowireCapableBeanFactory#getEarlyBeanReference

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
            }
        }
    }
    return exposedObject;
}

The above code is very simple. It is used to determine whether there is an implementation of registering the instantialoawarebeanpostprocessor. If there is a traversal to find the type, smartinstantialoawarebeanpostprocessor calls getEarlyBeanReference() to return the bean instance.

Here is another extension point of Spring. AOP, as we know well, weaves advice into beans dynamically. If not, it will directly return the beans without any processing.

AbstractAutowireCapableBeanFactory#populateBean

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;
        }
    }

    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
    // state of the bean before properties are set. This can be used, for example,
    // to support styles of field injection.
    // Give instantiaawarebeanpostprocessors the last chance to change beans before setting properties
    // For example: types that can be used to support property injection
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                // The life cycle callback after bean instantiation will be called here. If false is returned, the following property assignment phase will be skipped
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                    return;
                }
            }
        }
    }
    // Get PropertyValues
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

    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.
        // Automatic injection according to name, see details below
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
        // Add property values based on autowire by type if applicable.
        // Automatic injection according to type, see details below
        if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }

    // Is there an implementation class for registering instantiaawarebeanpostprocessors
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

    PropertyDescriptor[] filteredPds = null;
    if (hasInstAwareBpps) {
        if (pvs == null) {
            pvs = mbd.getPropertyValues();
        }
        // Traverse and find the implementation class of instantiaawarebeanpostprocessor, and call the postprocessor to process the property value
        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 the postprocessing method of property value returns null and returns directly, the following property value application phase will not be carried out
                    if (pvsToUse == null) {
                        return;
                    }
                }
                pvs = pvsToUse;
            }
        }
    }
    if (needsDepCheck) {
        if (filteredPds == null) {
            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        }
        checkDependencies(beanName, mbd, filteredPds, pvs);
    }

    if (pvs != null) {
        // For attribute filling, see details below
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

The above code will first call the life cycle callback method after bean instantiation. If false is returned, the following property assignment phase will be skipped. Let's take a brief look at the interface definition of instantiaionawarebanpostprocessors:

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

	/**
	 * Bean Before the instantiation is called, the non {@code null} IoC container is returned to instantiate the Bean, and the subsequent lifecycle callback square method does not invoke the {@code null}. The {@code container is used to instantiate Bean.
	 * This method was analyzed in the last article
	 */
	@Nullable
	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

	/**
	 * Bean After instantiation, the {@code true} is returned before the attribute is filled, and the default attribute fill step is returned. The return {@code * false} skips the attribute fill phase.
	 */
	default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		return true;
	}

	/**
	 * Bean After instantiation, it is called before attribute assignment. PropertyValues is an attribute value that has been encapsulated and returned to {@code null} to continue.
	 * Use existing properties, otherwise PropertyValues will be replaced.
	 * @since 5.1 The new version is the same as the following one
	 */
	@Nullable
	default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
			throws BeansException {
		return null;
	}

	/**
	 * The same function as the above method is only used before 5.1
	 * Returning {@ code null} skips the property filling phase
	 */
	@Deprecated
	@Nullable
	default PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {

		return pvs;
	}

}

Then determine whether to automatically inject properties by name or type and fill them in newPvs, and then call the life cycle callback before bean property filling. There are two life cycle callback methods before property filling: postProcessProperties() and postProcessPropertyValues(). The first one is a new one added by Spring 5.1, and the latter one is old, which has been marked as obsolete. First, call postProcessProperties() to return the postProcessPropertyValues() for air conditioner, otherwise directly use the returned one PropertyValues; postProcessPropertyValues() if it returns null, it will directly skip the property filling stage. If it is not null, it will directly use the returned PropertyValues.

AbstractAutowireCapableBeanFactory#autowireByName

protected void autowireByName(
    String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    // Find the attribute name in bw that needs dependency injection
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    // Traverse the bean to be injected
    for (String propertyName : propertyNames) {
        if (containsBean(propertyName)) {
            Object bean = getBean(propertyName);
            // Add the instance that needs to be injected into the bean to pvs
            pvs.add(propertyName, bean);
            // Registration dependency, which was analyzed in the previous article
            registerDependentBean(propertyName, beanName);
            if (logger.isTraceEnabled()) {
                logger.trace("Added autowiring by name from bean name '" + beanName +
                             "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
            }
        } else {
            // The bean that needs to be injected at present throws an exception
            if (logger.isTraceEnabled()) {
                logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName + "' by name: no matching bean found");
            }
        }
    }
}

AbstractAutowireCapableBeanFactory#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);
    // Find the attribute name in bw that needs dependency injection
    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.
            // Never inject Object type according to type injection. Please taste it carefully
            if (Object.class != pd.getPropertyType()) {
                // The writable method to get the property, generally the set method
                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);
                // This method has been analyzed above, and will not be described here. Finally, it returns the bean instance that meets the conditions and needs to be injected
                Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
                if (autowiredArgument != null) {
                    // The bean instance to be injected is not empty, which is added to pvc
                    pvs.add(propertyName, autowiredArgument);
                }
                for (String autowiredBeanName : autowiredBeanNames) {
                    // Registration dependency, methods analyzed in the previous article
                    registerDependentBean(autowiredBeanName, beanName);
                    if (logger.isTraceEnabled()) {
                        logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
                                     propertyName + "' to bean named '" + autowiredBeanName + "'");
                    }
                }
                autowiredBeanNames.clear();
            }
        } catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
        }
    }
}

AbstractAutowireCapableBeanFactory#applyPropertyValues

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
    // Property is empty, return directly
    if (pvs.isEmpty()) {
        return;
    }

    if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
        ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
    }

    MutablePropertyValues mpvs = null;
    List<PropertyValue> original;

    if (pvs instanceof MutablePropertyValues) {
        mpvs = (MutablePropertyValues) pvs;
        // Shortcut, if the attribute has been converted, directly fill in the BeanWrapper
        if (mpvs.isConverted()) {
            // Shortcut: use the pre-converted values as-is.
            try {
                bw.setPropertyValues(mpvs);
                return;
            } catch (BeansException ex) {
                throw new BeanCreationException(
							mbd.getResourceDescription(), beanName, "Error setting property values", ex);
            }
        }
        // Property has not been converted, get property list
        original = mpvs.getPropertyValueList();
    } else {
        // Get property list
        original = Arrays.asList(pvs.getPropertyValues());
    }

    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
        converter = bw;
    }
    // Get the corresponding parser
    BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

    // Create a deep copy, resolving any references for values.
    // Create deep copy to solve the problem of reference
    List<PropertyValue> deepCopy = new ArrayList<>(original.size());
    boolean resolveNecessary = false;
    // Traversal property, converting property to corresponding type
    for (PropertyValue pv : original) {
        // If the pv type has been converted, directly add it to deepCopy
        if (pv.isConverted()) {
            deepCopy.add(pv);
        } else {
            // Convert
            // Get pv original attribute name and attribute value
            String propertyName = pv.getName();
            Object originalValue = pv.getValue();
            if (originalValue == AutowiredPropertyMarker.INSTANCE) {
                Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
                if (writeMethod == null) {
                    throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
                }
                originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
            }
            // Type conversion
            Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
            Object convertedValue = resolvedValue;
            boolean convertible = bw.isWritableProperty(propertyName) &&
                !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
            if (convertible) {
                // If convertible, converts the given value of the specified target property
                convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
            }
            // Possibly store converted value in merged bean definition,
            // in order to avoid re-conversion for every created bean instance.
            // Store converted values in the merged BeanDefinition to avoid re conversion for each bean instance created
            if (resolvedValue == originalValue) {
                if (convertible) {
                    pv.setConvertedValue(convertedValue);
                }
                deepCopy.add(pv);
            } else if (convertible && originalValue instanceof TypedStringValue &&
                       !((TypedStringValue) originalValue).isDynamic() &&
                       !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                pv.setConvertedValue(convertedValue);
                deepCopy.add(pv);
            } else {
                resolveNecessary = true;
                deepCopy.add(new PropertyValue(pv, convertedValue));
            }
        }
    }
    if (mpvs != null && !resolveNecessary) {
        mpvs.setConverted();
    }

    // Set our (possibly massaged) deep copy.
    try {
        // Fill bean property value
        bw.setPropertyValues(new MutablePropertyValues(deepCopy));
    } catch (BeansException ex) {
        throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Error setting property values", ex);
    }
}

The above code is mainly used for property type conversion, and finally to fill in the property value of the bean. Here, the reflection is generally used to use set() to assign values to properties.

AbstractAutoCapableBeanFactory#initializeBean

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
   if (System.getSecurityManager() != null) {
       AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
           invokeAwareMethods(beanName, bean);
           return null;
       }, getAccessControlContext());
   } else {
       // Beaware's interface callback is explained in detail below
       invokeAwareMethods(beanName, bean);
   }

   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
       // postProcessBeforeInitialization() callback of BeanPostProcessor, that is, the callback before bean initialization
       // In the postProcessBeforeInitialization method implemented by applicationcontextawarprocessor
       // Interface callback for ApplicationContext Aware.
       // The postProcessBeforeInitialization() of the InitDestoryAnnotationBeanPostProcessor will execute
       // Annotated @ PostConstruct annotation method.
       wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }

   try {
       // Call the bean's custom initialization methods, such as afterpropertieset, the method specified by init property in XML, etc
       invokeInitMethods(beanName, wrappedBean, mbd);
   } catch (Throwable ex) {
       throw new BeanCreationException(
           (mbd != null ? mbd.getResourceDescription() : null),
           beanName, "Invocation of init method failed", ex);
   }
   if (mbd == null || !mbd.isSynthetic()) {
       // postProcessAfterInitialization() callback of BeanPostProcessor, that is, the callback after bean initialization
       wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }

   return wrappedBean;
}

AbstractAutowireCapableBeanFactory#invokeAwareMethods

private void invokeAwareMethods(final String beanName, final Object bean) {
    if (bean instanceof Aware) {
        // BeanNameAware interface method callback
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) bean).setBeanName(beanName);
        }
        // BeanClassLoaderAware interface method callback
        if (bean instanceof BeanClassLoaderAware) {
            ClassLoader bcl = getBeanClassLoader();
            if (bcl != null) {
                ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
            }
        }
        // BeanFactoryAware interface method callback
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware)
             bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
    }
}

Before the beans implementing these Aware interfaces are initialized, some corresponding resources can be obtained, such as beanName, beanFactory, etc.

AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {

    Object result = existingBean;
    // Traverse all registered BeanPostProcessor implementation classes and call the postProcessBeforeInitialization method
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        // Call the postProcessBeforeInitialization method before the bean initialization method executes
        Object current = processor.postProcessBeforeInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

AbstractAutowireCapableBeanFactory#invokeInitMethods

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {

    // Does the bean implement the InitializingBean interface
    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isTraceEnabled()) {
            logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }
        if (System.getSecurityManager() != null) {
            try {
                AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                    ((InitializingBean) bean).afterPropertiesSet();
                    return null;
                }, getAccessControlContext());
            } catch (PrivilegedActionException pae) {
					throw pae.getException();
            }
        } else {
            // Call afterpropertieset method
            ((InitializingBean) bean).afterPropertiesSet();
        }
    }

    // Call the custom init method, such as the method for setting the init method attribute in XML
    if (mbd != null && bean.getClass() != NullBean.class) {
        String initMethodName = mbd.getInitMethodName();
        if (StringUtils.hasLength(initMethodName) &&
            !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
            !mbd.isExternallyManagedInitMethod(initMethodName)) {
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

According to the above code, the process of bean initialization is as follows:

  1. @PostConstruct annotation modification method, if annotation driven
  2. afterPropertySet() that implements the InitializingBean interface
  3. Custom initialization methods, such as init method property settings in XML

AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
    throws BeansException {

    Object result = existingBean;
    // Traverse all registered BeanPostProcessor implementation classes and call the postProcessAfterInitialization method
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        // After the bean initialization method is executed, the postProcessBeforeInitialization method is called
        Object current = processor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

Let's take a brief look at the BeanPostProcessor interface, as follows:

public interface BeanPostProcessor {

	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

The BeanPostProcessor interface is relatively simple, providing two interface callbacks, one before and one after initialization. However, most of the other postprocessors are based on this and inherit from BeanPostProcessor.

AbstractBeanFactory#registerDisposableBeanIfNecessary

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
    AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
    // The scope of bean is not prototype
    if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
        if (mbd.isSingleton()) {
            // Register a DisposableBean implementation that performs all destruction
            // work for the given bean: DestructionAwareBeanPostProcessors,
            // In the singleton mode, register the bean for destruction to the disposableBeans cache, and perform all the destruction work of the given bean:
            // DestructionAwareBeanPostProcessors, DisposableBean interface, custom destruction method
            // DisposableBeanAdapter: use DisposableBeanAdapter to encapsulate beans for destruction
            // See details below
            registerDisposableBean(beanName,
                                   new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
        }
        else {
            // A bean with a custom scope...
            // Beans are custom scopes
            Scope scope = this.scopes.get(mbd.getScope());
            if (scope == null) {
                throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
            }
            // Register a callback, execute it at the time of destruction, manage the execution time by yourself, Spring will not help to call
            scope.registerDestructionCallback(beanName,
                                              new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
        }
    }
}

DisposableBeanAdapter constructor

public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition, List<BeanPostProcessor> postProcessors, @Nullable AccessControlContext acc) {

    Assert.notNull(bean, "Disposable bean must not be null");
    this.bean = bean;
    this.beanName = beanName;
    // Determine whether the bean calls the destroy method of DisposableBean
    this.invokeDisposableBean =
        (this.bean instanceof DisposableBean &&
         !beanDefinition.isExternallyManagedDestroyMethod("destroy"));
    this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();
    this.acc = acc;
    // Get the custom destroy method name and assign it to destroyMethodName
    String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition);
    if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) &&
        !beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) {
        // Get the custom destroy method name and assign it to destroyMethodName
        this.destroyMethodName = destroyMethodName;
        Method destroyMethod = determineDestroyMethod(destroyMethodName);
        // If the determined destroyMethod is empty, an exception will be thrown
        if (destroyMethod == null) {
            if (beanDefinition.isEnforceDestroyMethod()) {
                throw new BeanDefinitionValidationException("Could not find a destroy method named '" +
                                                            destroyMethodName + "' on bean with name '" + beanName + "'");
            }
        }
        // If the determined destroyMethod is not empty
        else {
            // Get method parameters of destroyMethod
            Class<?>[] paramTypes = destroyMethod.getParameterTypes();
            // An exception is thrown when the parameter length is greater than 1. Only one boolean parameter is allowed for the custom destroy method
            if (paramTypes.length > 1) {
                throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
                                                            beanName + "' has more than one parameter - not supported as destroy method");
            }
            // Parameter length equal to 1 & & not boolean type, throw exception
            else if (paramTypes.length == 1 && boolean.class != paramTypes[0]) {
                throw new BeanDefinitionValidationException("Method '" + destroyMethodName + "' of bean '" +
                                                            beanName + "' has a non-boolean parameter - not supported as destroy method");
            }
            destroyMethod = ClassUtils.getInterfaceMethodIfPossible(destroyMethod);
        }
        this.destroyMethod = destroyMethod;
    }
    // Find DestructionAwareBeanPostProcessors and assign to this.beanPostProcessors See details below
    this.beanPostProcessors = filterPostProcessors(postProcessors, bean);
}

DisposableBeanAdapter#filterPostProcessors

private List<DestructionAwareBeanPostProcessor> filterPostProcessors(List<BeanPostProcessor> processors, Object bean) {
    List<DestructionAwareBeanPostProcessor> filteredPostProcessors = null;
    // processors length is not empty
    if (!CollectionUtils.isEmpty(processors)) {
        // Traverse processors
        for (BeanPostProcessor processor : processors) {
            // If the processor type is DestructionAwareBeanPostProcessor
            if (processor instanceof DestructionAwareBeanPostProcessor) {
                DestructionAwareBeanPostProcessor dabpp = (DestructionAwareBeanPostProcessor) processor;
                // If the bean actually needs to be destroyed through this postprocessor, it will be added to the filtered postprocessors
                if (dabpp.requiresDestruction(bean)) {
                    filteredPostProcessors.add(dabpp);
                }
            }
        }
    }
    return filteredPostProcessors;
}

The above code is mainly used to determine if the BeanPostProcessor is DestructionAwareBeanPostProcessor and requiresDestruction() returns true, which means that the instance needs to be destroyed through the postprocessor. Add the BeanPostProcessor to the filteredPostProcessors.

Let's take a brief look at the definition of the DestructionAwareBeanPostProcessor interface:

public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {

	/**
	 * bean Pre destruction phase life cycle callback method
	 */
	void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;

	/**
	 * bean Whether the instance needs to be destroyed by this postprocessor
	 */
	default boolean requiresDestruction(Object bean) {
		return true;
	}

}

It can be seen that it also inherits from BeanPostProcessor. It mainly provides two methods: one is the life cycle method callback before bean destruction, the other is to determine whether the bean instance needs to be destroyed by this postprocessor.

DefaultListableBeanFactory#destroySingletons

Because BeanFactory basically only uses the final implementation of DefaultListableBeanFactory, let's analyze the method of destroying single bean here.

public void destroySingletons() {
    // Call the destroy all singleton bean methods of the parent class
    super.destroySingletons();
    updateManualSingletonNames(Set::clear, set -> !set.isEmpty());
    // Clear cache for all bean types
    clearByTypeCache();
}

// DefaultSingletonBeanRegistry.java
public void destroySingletons() {
    if (logger.isTraceEnabled()) {
        logger.trace("Destroying singletons in " + this);
    }
    synchronized (this.singletonObjects) {
        this.singletonsCurrentlyInDestruction = true;
    }

    String[] disposableBeanNames;
    // Get all bean s that need to be destroyed
    synchronized (this.disposableBeans) { 
        disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
    } 
    // According to the registration order, traverse backward and destroy the bean
    for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
        destroySingleton(disposableBeanNames[i]);
    }

    this.containedBeanMap.clear();
    this.dependentBeanMap.clear();
    this.dependenciesForBeanMap.clear();
    // Clear all singleton instances from the cache
    clearSingletonCache();
}

// DefaultSingletonBeanRegistry.java
public void destroySingleton(String beanName) {
    // Remove a registered singleton of the given name, if any.
    // Clear all current single instance of beanName from the cache
    removeSingleton(beanName);

    // Destroy the corresponding DisposableBean instance.
    DisposableBean disposableBean;
    // Lock, remove the current bean from the disposableBeans
    synchronized (this.disposableBeans) {
        disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
    }
    // Destroy bean
    destroyBean(beanName, disposableBean);
}

protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
    // Trigger destruction of dependent beans first...
    Set<String> dependencies;
    // Lock to remove the current bean from the dependentBeanMap
    synchronized (this.dependentBeanMap) {
        // Within full synchronization in order to guarantee a disconnected Set
        dependencies = this.dependentBeanMap.remove(beanName);
    }
    if (dependencies != null) {
        if (logger.isTraceEnabled()) {
            logger.trace("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);
        }
        // dependencies is not empty, indicating that there are other dependent beans in the current bean, traverse to destroy
        for (String dependentBeanName : dependencies) {
            destroySingleton(dependentBeanName);
        }
    }

    // Actually destroy the bean now...
    // bean is not empty, call destroy method to start destroying
    if (bean != null) {
        try {
            bean.destroy();
        }
        catch (Throwable ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Destruction of bean with name '" + beanName + "' threw an exception", ex);
            }
        }
    }

    // Trigger destruction of contained beans...
    Set<String> containedBeans;
    synchronized (this.containedBeanMap) {
        // Within full synchronization in order to guarantee a disconnected Set
        containedBeans = this.containedBeanMap.remove(beanName);
    }
    if (containedBeans != null) {
        for (String containedBeanName : containedBeans) {
            destroySingleton(containedBeanName);
        }
    }

    // Remove destroyed bean from other beans' dependencies.
    synchronized (this.dependentBeanMap) {
        for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {
            Map.Entry<String, Set<String>> entry = it.next();
            Set<String> dependenciesToClean = entry.getValue();
            dependenciesToClean.remove(beanName);
            if (dependenciesToClean.isEmpty()) {
                it.remove();
            }
        }
    }

    // Remove destroyed bean's prepared dependency information.
    this.dependenciesForBeanMap.remove(beanName);
}

DisposableBeanAdapter#destroy

public void destroy() {
    // If beanPostProcessors is not empty
    if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
        // Traverse beanPostProcessors and call postprocessbeforestructure()
        for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
            processor.postProcessBeforeDestruction(this.bean, this.beanName);
        }
    }

    if (this.invokeDisposableBean) {
        if (logger.isTraceEnabled()) {
            logger.trace("Invoking destroy() on bean with name '" + this.beanName + "'");
        }
        try {
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                    ((DisposableBean) this.bean).destroy();
                    return null;
                }, this.acc);
            }
            else {
                // Call destroy() that implements DisposableBean
                ((DisposableBean) this.bean).destroy();
            }
        }
        catch (Throwable ex) {
            String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
            if (logger.isDebugEnabled()) {
                logger.warn(msg, ex);
            }
            else {
                logger.warn(msg + ": " + ex);
            }
        }
    }
    // Call the custom destroy method
    if (this.destroyMethod != null) {
        invokeCustomDestroyMethod(this.destroyMethod);
    }
    else if (this.destroyMethodName != null) {
        Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
        if (methodToInvoke != null) {          invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
        }
    }
}

Generally speaking, the above method is divided into three steps:

  1. The callback implements the postprocessbeforestructure method of the destructionawarebaanpostprocessor interface, and the method marked with @ PreDestory annotation will be executed in the postprocessbeforestructure() of the InitDestoryAnnotationBeanPostProcessor.

  2. Call destroy() that implements the DisposableBean interface.

  3. Call the destroyMethod of the custom implementation, such as the method specified by the destroy attribute in XML

summary

This article mainly introduces the createBean() process, and we can reorganize the following ideas:

  1. Call back the method before instantiation of the bean. If the return is not empty, skip the next step
  2. Create an instance of the bean. If it is constructor injection, the most appropriate constructor will be selected for automatic parameter injection. Otherwise, call the default parameterless construction to instantiate the bean.
  3. If the bean allows early exposure, put the ObjectFactory corresponding to beanName into the singleton factories cache.
  4. In the property assignment phase of a bean, first call the method callback after the bean is instantiated, and return false to skip the subsequent assignment phase; determine whether to inject automatically by name or type, and if so, inject automatically by property. Then call the postprocessing method to process attribute values. First, call the newly added method of spring 5.1. If the returned attribute is empty, then call the method of the previous version. If it is empty, return directly. There is no need to go to the later actual assignment stage.
  5. The initialization phase of bean is first calling some Aware interfaces that can get the corresponding resources; then calling bean to initialize the callback method (postProcessBeforeInitialization() of InitDestroyAnnotationBeanPostProcessor will execute.
    Annotated with the @ PostConstruct annotation method), then call the overridden afterpropertieset() and the custom initialization method; finally, call back the method after the bean initialization.
  6. Register the method to destroy the bean.
  7. Finally, an instance of the bean is returned.

Finally, I wrote a simplified version of Spring, and the code will keep updating. Now it is version 0.0.3. Address: https://github.com/leisurexi/tiny-spring . Visit the new blog address for better viewing https://leisurexi.github.io/

reference resources

  • Deep analysis of Spring source code -- Hao Jia

Keywords: Attribute Spring xml less

Added by skippence on Fri, 22 May 2020 13:27:50 +0300