Springboot source code – bean loading (in)

Time:2022-5-9

Here comes the wonderful content, ladies and gentlemen, continue~

Following the previous section, the refresh () method in the abstractapplicationcontext class has a line of insignificant Code:

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

It is the place where beans are created most intensively and instantiates all non lazy loaded singletons.

Click this method to enter, and you can see another line of code in the method body:

// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();

It’s the man who really works. Click in again to see the method implementation:

  1. getMergedLocalBeanDefinition(beanName), merge the definitions of beandefinition
  2. if (isFactoryBean(beanName)) {……}, judge whether it is a factorybean, get the instance of factorybean, judge whether it needs to be instantiated in advance, and instantiate it through getBean if necessary
  3. getBean(beanName)For the instantiation of an ordinary bean, click in and go to dogetbean(), with the code:

    protected <T> T doGetBean(
        String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)throws BeansException {
        //Get the real beanname, because some beans have aliases. When factorybean itself is created, it passes & beanname
        String beanName = transformedBeanName(name);
        Object beanInstance;
    
        //Obtain a single instance from the cache to solve circular dependency and duplicate creation
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            if (logger.isTraceEnabled()) {
                if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.trace("……");
                }
                else {
                    logger.trace("……");
                }
            }
            //Solve special bean processing like factorybean
            beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }
    
        else {
            //The prototype pattern does not need to solve the circular dependency, because the prototype bean does not put the cache and does not expose the reference in advance
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }
    
            //If the bean is not loaded in beandefinitionmap, look it up from parentbeanfactory
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                String nameToLookup = originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory) {
                    return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                            nameToLookup, requiredType, args, typeCheckOnly);
                }
                else if (args != null) {
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else if (requiredType != null) {
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
                else {
                    return (T) parentBeanFactory.getBean(nameToLookup);
                }
            }
            //The bean is marked as created only when it is not type checked
            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }
    
            StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")                .tag("beanName", name);
            try {
                if (requiredType != null) {
                    beanCreation.tag("beanType", requiredType::toString);
                }
                RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);
    
                //The creation of the bean on which the current bean depends.
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        //Non explicit dependency (@ dependon)
                        if (isDependent(beanName, dep)) {
                            throw new BeanCreationException("……");
                        }
                        //Create the dependent bean first, and then create itself
                        registerDependentBean(dep, beanName);
                        try {
                            getBean(dep);
                        }
                        catch (NoSuchBeanDefinitionException ex) {
                            throw new BeanCreationException("……");
                        }
                    }
                }
    
                //Singleton bean creation
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
                //Prototype bean creation
                else if (mbd.isPrototype()) {
                    Object prototypeInstance = null;
                    try {
                        beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        afterPrototypeCreation(beanName);
                    }
                    beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }
                //Instantiate beans on specified scope
                else {
                    String scopeName = mbd.getScope();
                    if (!StringUtils.hasLength(scopeName)) {
                        throw new IllegalStateException("……");
                    }
                    Scope scope = this.scopes.get(scopeName);
                    if (scope == null) {
                        throw new IllegalStateException("……");
                    }
                    try {
                        Object scopedInstance = scope.get(beanName, () -> {
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            finally {
                                afterPrototypeCreation(beanName);
                            }
                        });
                        beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    }
                    catch (IllegalStateException ex) {
                        throw new ScopeNotActiveException(beanName, scopeName, ex);
                    }
                }
            }
            catch (BeansException ex) {
                beanCreation.tag("exception", ex.getClass().toString());
                beanCreation.tag("message", String.valueOf(ex.getMessage()));
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
            finally {
                beanCreation.end();
            }
        }
        //Check whether the actual type is consistent with the required type. If not, replace it
        return adaptBeanInstance(name, beanInstance, requiredType);
    }

    In the above code, the place to create the bean is:

    createBean(beanName, mbd, args);

    Click this method to go in, and there is another layer:

    doCreateBean(beanName, mbdToUse, args);

    Click this method to go in, which is where the bean is really created. I’ll talk about it in the next section. Take a sip of wine first~~