Starting with this article, I’ll have two articles on how Spring addresses loop dependencies.

How to solve the bean cycle dependency (2)

About AbstractApplicationContext# refresh method

The refresh method is a very important method in Spring. It can be said that the whole essence of IOC is in this method. I will not introduce the call link of this method today. Because Spring’s solution to bean cyclic dependencies starts with the bean creation process, it’s important to know where the bean creation portal is in Spring. I’ll find time to cover each method in detail later (ps: Each method is actually important).

@Override
public void refresh(a) throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
            StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory
            // Register some beans for internal use
            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                    // Subclasses can modify bean factory initialization
                    // Allows post-processing of the bean factory in context subclasses.
                    postProcessBeanFactory(beanFactory);

                    StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");

                    // Invoke factory processors registered as beans in the context.
                    /** * is important, Call all the spring BeanFactoryPostProcessor in bean plant and its subclasses (BeanDefinitionRegistryPostProcessor) the implementation of the * * -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Direct implementation BeanDefinitionRegistryPostProcessor: * * ConfigurationClassPostProcessor scan configuration class, Based on ConfigurationClassBeanDefinitionReader * * -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- to realize spring BeanFactoryPostProcessor directly: * * EventListenerMethodProcessor processing@EventListener, registered into ApplicationListener * DefaultEventListenerFactory EventListenerFactory default implementation, for handling@EventListenerAnd registered into ApplicationListener PropertyResourceConfigurer attribute configuration base class * * * PropertyOverrideConfigurer set attribute value, Such as beanName. Property = value * PlaceholderConfigurerSupport treatment placeholder * PropertySourcesPlaceholderConfigurer placeholder * Accomplished the original processing placeholder method, outdated * placeholder PreferencesPlaceholderConfigurer original processing method, Outdated * * CustomAutowireConfigurer custom Qualifier annotations * DeprecatedBeanWarner used for@DeprecatedLog print for the annotation class * CustomEditorConfigurer custom bean property editor, which can customize the value of the property * AspectJWeavingEnabler * CustomScopeConfigurer */
                    invokeBeanFactoryPostProcessors(beanFactory);

                    // Register bean processors that intercept bean creation.
                    // Register the BeanPostProcessor in the bean factory
                    /** * BeanPostProcessor  * ServletContextAwareProcessor * AdvisorAdapterRegistrationManager * AbstractAdvisingBeanPostProcessor * AbstractBeanFactoryAwareAdvisingPostProcessor * MethodValidationPostProcessor * AsyncAnnotationBeanPostProcessor * PersistenceExceptionTranslationPostProcessor * BootstrapContextAwareProcessor * BeanValidationPostProcessor * Son ApplicationContextAwareProcessor LoadTimeWeaverAwareProcessor BeanPostProcessorChecker * * * * BeanPostProcessor interface: * -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- MergedBeanDefinitionPostProcessor -- -- -- -- -- -- -- -- -- -- -- -- processing combined JmsListenerAnnotationBeanPostProcessor bd * * ScheduledAnnotationBeanPostProcessor * RequiredAnnotationBeanPostProcessor * InitDestroyAnnotationBeanPostProcessor * CommonAnnotationBeanPostProcessor * AutowiredAnnotationBeanPostProcessor * ApplicationListenerDetector * PersistenceAnnotationBeanPostProcessor * * ------------------- InstantiationAwareBeanPostProcessor ------------ Instantiation of before and after treatment, treatment properties * ImportAwareBeanPostProcessor ImportRegistry * AutowiredAnnotationBeanPostProcessor processing@Autowired,@Valueand@Inject* CommonAnnotationBeanPostProcessor processing@PreDestroy,@PostConstruct,@Resource,@WebServiceRefSuch as annotation * RequiredAnnotationBeanPostProcessor PersistenceAnnotationBeanPostProcessor * * * -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- SmartInstantiationAwareBeanPostProcessor -- -- -- -- -- -- -- -- -- -- -- -- inherit InstantiationAwareBeanPostProcessor, predict the type of bean, Infer that the constructor * * RequiredAnnotationBeanPostProcessor ScriptFactoryPostProcessor processing, etc@Required* AutowiredAnnotationBeanPostProcessor infer that constructor * AbstractAutoProxyCreator InstantiationAwareBeanPostProcessorAdapter * * BeanNameAutoProxyCreator * AbstractAdvisorAutoProxyCreator * DefaultAdvisorAutoProxyCreator * AspectJAwareAdvisorAutoProxyCreator * AnnotationAwareAspectJAutoProxyCreator * InfrastructureAdvisorAutoProxyCreator * * -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- DestructionAwareBeanPostProcessor -- -- -- -- -- -- -- -- -- -- -- -- bean destroyed before processing * ScheduledAnnotationBeanPostProcessor * SimpleServletPostProcessor * InitDestroyAnnotationBeanPostProcessor * CommonAnnotationBeanPostProcessor * ApplicationListenerDetector listener to detect * PersistenceAnnotationBeanPostProcessor * /
                    registerBeanPostProcessors(beanFactory);
                    beanPostProcess.end();

                    // Initialize message source for this context.
                    initMessageSource();

                    // Initialize event multicaster for this context.
                    initApplicationEventMulticaster();

                    // Initialize other special beans in specific context subclasses.
                    onRefresh();

                    // Check for listener beans and register them.
                    registerListeners();

                    // Instantiate all remaining (non-lazy-init) singletons.
                    //todo important, instantiate all non-lazy-loaded beans
                    finishBeanFactoryInitialization(beanFactory);

                    // Last step: publish corresponding event.
                    finishRefresh();
            } catch (BeansException ex) {
                    if (logger.isWarnEnabled()) {
                            logger.warn("Exception encountered during context initialization - " +
                                            "cancelling refresh attempt: " + ex);
                    }

                    // Destroy already created singletons to avoid dangling resources.
                    destroyBeans();

                    // Reset 'active' flag.
                    cancelRefresh(ex);

                    // Propagate exception to caller.
                    throw ex;
            } finally {
                    // Reset common introspection caches in Spring's core, since we
                    // might not ever need metadata for singleton beans anymore...resetCommonCaches(); contextRefresh.end(); }}}Copy the code

prepareRefresh()

This method initializes components that spring uses internally, including:

  • 1. Set some flag variables, such as closed or active
  • 2. InitPropertySources () initializes the environment properties
  • 3, get environment, if empty, create (StandardEnvironment)
  • 4. Verify the necessary environment properties
  • 5. Initialize the listener

obtainFreshBeanFactory()

Call refreshBeanFactory() and getBeanFactory(). RefreshBeanFactory () is a subclass implementation of the refreshBeanFactory. One of the implementation of a subclass is GenericApplicationContext, the subclass serialization flag bits in implementation; GetBeanFactory () is to obtain the bean factory object, subclass implementation, is obtained in GenericApplicationContext DefaultListableBeanFactory type of bean plant.

prepareBeanFactory(beanFactory)

This method is to prepare the bean factory, mainly for use within the registered some spring beans, including ApplicationContextAwareProcessor, Environment related beans, set to ignore dependent interface, etc.

postProcessBeanFactory(beanFactory)

This approach allows subclasses to modify the bean factory, preserving the ability of bean factory subclasses to extend the bean factory.

invokeBeanFactoryPostProcessors(beanFactory)

This method is very important, spring will call all the spring BeanFactoryPostProcessor in bean plant and its subclasses (BeanDefinitionRegistryPostProcessor) implementation. As for spring BeanFactoryPostProcessor and BeanDefinitionRegistryPostProcessor is what, what is the role, the reader can go to understand, here I make a brief introduction of the spring using the two interfaces are done, Such as scan configuration class is implemented using ConfigurationClassPostProcessor @ EventListener annotations parsing, use EventListenerMethodProcessor, These two classes are the implementation classes of BeanFactoryPostProcessor and its subclasses, and there are many more that I won’t cover, but there will be an article that will explain in more detail what this method and these interfaces do.

registerBeanPostProcessors(beanFactory)

As you can see from the name of the method, this method primarily registers the BeanPostProcessor in the bean factory. BeanPostProcessor is a key hook interface in Spring, which many translate as bean post-processor. Inside Spring, it implements bean type speculation, inferences bean constructors, handles @autowired, @Value, and @Inject annotations, and one heavyweight feature, Spring AOP, All are implemented based on the capabilities provided by BeanPostProcessor and its subclasses. At the same time, as a developer, you can also use the capabilities provided by BeanPostProcessor and its subclasses to extend beans in Spring. In the above code, I have also made a tidy up of the implementation classes of Spring’s internal BeanPostProcessor, and also marked some of the main functions of the class. Readers can find the parts of interest for a deeper understanding.

With initApplicationEventMulticaster initMessageSource () ()

InitMessageSource () method is used to initialize the MessageSource, initApplicationEventMulticaster is initialized ApplicationEventMulticaster () method.

With registerListeners onRefresh () ()

The onRefresh() method, which is implemented by subclasses that do some extra work before the bean is initialized, is an embodiment of the Spring template method design pattern, and of course there are many other places in Spring that use this pattern. RegisterListeners are registered to the container.

finishBeanFactoryInitialization(beanFactory)

This method completes the creation of all non-lazy-loaded beans in the Spring container. This method is important because it involves bean instantiation, AOP proxies, and callbacks to various hook functions (such as BeanPostProcessor and its subclasses). Spring’s solution to the circular dependency of beans is also included.

finishRefresh()

This method completes the refresh of the container, including callbacks to the LifecycleProcessor interface, publishing ContextRefreshedEvent events, and so on.

Get an entry to the bean -AbstractBeanFactory#getBean

Have talked about just now, in the spring to create the entry of the bean is finishBeanFactoryInitialization (the beanFactory) method, . This approach is the internal calls the beanFactory preInstantiateSingletons () method, this method is the entrance to the spring to create a lazy loaded bean, will eventually call AbstractBeanFactory# getBean method, Let’s look at the code for AbstractBeanFactor #getBean:

@Override
public void preInstantiateSingletons(a) throws BeansException {
    if (logger.isTraceEnabled()) {
            logger.trace("Pre-instantiating singletons in " + this);
    }

    // Iterate over a copy to allow for init methods which in turn register new bean definitions.
    // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
    // All bd names
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // Trigger initialization of all non-lazy singleton beans...
    for (String beanName : beanNames) {
            Bd / / merger
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            // Non-abstract, singleton, non-lazy loading
            if(! bd.isAbstract() && bd.isSingleton() && ! bd.isLazyInit()) {if (isFactoryBean(beanName)) {
                            Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                            if (bean instanceofFactoryBean) { FactoryBean<? > factory = (FactoryBean<? >) bean;boolean isEagerInit;
                                    if(System.getSecurityManager() ! =null && factory instanceofSmartFactoryBean) { isEagerInit = AccessController.doPrivileged( (PrivilegedAction<Boolean>) ((SmartFactoryBean<? >) factory)::isEagerInit, getAccessControlContext()); }else {
                                            isEagerInit = (factory instanceofSmartFactoryBean && ((SmartFactoryBean<? >) factory).isEagerInit()); }if(isEagerInit) { getBean(beanName); }}}else{ getBean(beanName); }}}}Copy the code

BeanDefinitionNames = beanDefinitionNames = beanDefinitionNames = beanDefinitionNames = beanDefinitionNames = beanDefinitionNames = beanDefinitionNames = beanDefinitionNames = beanDefinitionNames = beanDefinitionNames = beanDefinitionNames = beanDefinitionNames So what happens inside Spring when it comes to getting beans? Let’s move on.

@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null.null.false);
}
Copy the code
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
                throws BeansException {
    / / convert the name
    String beanName = transformedBeanName(name);
    Object beanInstance;

    // Eagerly check singleton cache for manually registered singletons.
    // Key point 1
    // Get it from the cache
    Object sharedInstance = getSingleton(beanName);
    if(sharedInstance ! =null && args == null) {
            if (logger.isTraceEnabled()) {
                    if (isSingletonCurrentlyInCreation(beanName)) {
                            logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                                            "' that is not fully initialized yet - a consequence of a circular reference");
                    }
                    else {
                            logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
                    }
            }
            beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    else{...try {
                    if(requiredType ! =null) {
                            beanCreation.tag("beanType", requiredType::toString);
                    }

                    // If markBeanAsCreated is executed, the bean is remerged
                    RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                    // Merge bd cannot be abstract
                    checkMergedBeanDefinition(mbd, beanName, args);

                    // Guarantee initialization of beans that the current bean depends on.
                    String[] dependsOn = mbd.getDependsOn();
                    if(dependsOn ! =null) {
                            for (String dep : dependsOn) {
                                    // Loop dependency
                                    if (isDependent(beanName, dep)) {
                                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                                            "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                                    }
                                    registerDependentBean(dep, beanName);
                                    try {
                                            // Create the dependent bean
                                            getBean(dep);
                                    }
                                    catch (NoSuchBeanDefinitionException ex) {
                                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                                            "'" + beanName + "' depends on missing bean '" + dep + "'", ex); }}}// Todo important: singleton bean creation
                    //Create bean instance.
                    if (mbd.isSingleton()) {
                             // Key point 2
                            sharedInstance = getSingleton(beanName, () -> {
                                    try {
                                             // Key point 3
                                            return createBean(beanName, mbd, args);
                                    }
                                    catch (BeansException ex) {
                                            // Explicitly remove instance from singleton cache: It might have been put there
                                            // eagerly by the creation process, to allow for circular reference resolution.
                                            // Also remove any beans that received a temporary reference to the bean.
                                            destroySingleton(beanName);
                                            throwex; }}); beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }... }catch (BeansException ex) {
                    beanCreation.tag("exception", ex.getClass().toString());
                    beanCreation.tag("message", String.valueOf(ex.getMessage()));
                    cleanupAfterBeanCreationFailure(beanName);
                    throw ex;
            }
            finally{ beanCreation.end(); }}return adaptBeanInstance(name, beanInstance, requiredType);
}
Copy the code

The above two pieces of code are the concrete implementation of getBean calling the doGetBean method. As you can see, the implementation is quite complex, but I have marked three key points in the code. These three places are the key nodes for obtaining and creating the bean.

A key – get bean, DefaultSingletonBeanRegistry# getSingleton (beanName)

Key one is to fetch the bean from the container’s cache, and if so, return it directly. Let’s see what this method of retrieving beans from the cache looks like:

@Override
@Nullable
public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}
Copy the code
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // Quick check for existing instance without full singleton lock
    // The first step
    // Get it from singletonObjects first
    Object singletonObject = this.singletonObjects.get(beanName);
    // If there is no todo in singletonObject and the current bean is being created
    // When first entered, it will not be in the set being created
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            // From earlySingletonObjects
            // The second step
            singletonObject = this.earlySingletonObjects.get(beanName);
            // If the earlySingletonObjects fetch is empty and allows the creation of early beans
            if (singletonObject == null && allowEarlyReference) {
                    synchronized (this.singletonObjects) {
                            // Consistent creation of early reference within full singleton lock
                            singletonObject = this.singletonObjects.get(beanName);
                            if (singletonObject == null) {
                                    singletonObject = this.earlySingletonObjects.get(beanName);
                                    if (singletonObject == null) {
                                            // Get from singletonFactoriesObjectFactory<? > singletonFactory =this.singletonFactories.get(beanName);
                                            if(singletonFactory ! =null) {
                                                    // The third step
                                                    // Create an object
                                                    singletonObject = singletonFactory.getObject();
                                                    // Create an early bean
                                                    this.earlySingletonObjects.put(beanName, singletonObject);
                                                    this.singletonFactories.remove(beanName);
                                            }
                                    }
                            }
                    }
            }
    }
    return singletonObject;
}
Copy the code

Spring uses three maps to store beans. The first is singletonObjects, the second is earlySingletonObjects and the third is singletonFactories. Why use three maps? Is it ok to use one? Is it ok to use two? With that in mind, we read on.

I’ve labeled the steps at the key points in the code, so let’s take a closer look

The first step is to obtain the singletonObjects. If the singletonObjects obtained are not null, If (singletonObject = = null && isSingletonCurrentlyInCreation (beanName)) the judge will not into, if singletonObject equal to null, Requires the judge isSingletonCurrentlyInCreation (beanName) value, so this method is stem what of, let’s take a look at:

public boolean isSingletonCurrentlyInCreation(String beanName) {
    return this.singletonsCurrentlyInCreation.contains(beanName);
}
Copy the code

This method is to determine whether the bean in singletonsCurrentlyInCreation collection, so singletonsCurrentlyInCreation is stem what of? This collection stores a collection of beans currently being created in Spring. That is, if a bean is being created, it will be added to the collection. When will the bean be added to the collection? I’ll explain what happens next. Actually read this already very clear, entering for the first time, the bean does not exist in singletonsCurrentlyInCreation collection, namely this condition will not enter, finally singletonObject returns null. That if the bean is singletonsCurrentlyInCreation collection, here we might as well imagine, can appear what circumstance the bean in the collection, actually is a kind of situation, is in the back of the code in the process, Spring will add the bean into singletonsCurrentlyInCreation collection, and then walk a getBean process of this bean, This time the if (singletonObject = = null && isSingletonCurrentlyInCreation (beanName)) the judge will enter, then here we assume that this condition was established, and then analysis the second step down.

The second step is to get the earlySingletonObjects from the map. According to the singletonObjects, If (singletonObject == null && allowEarlyReference), allowEarlyReference is passed in from getSingleton. It means whether or not it is allowed to get an earlier reference, so this condition is passed in as true. The code before marking the third line is spring’s optimization of the double Check lock for retrieving beans, which can be ignored for now. So let’s see what step three does.

The third step gets an ObjectFactory object from singletonFactories, and then calls getObject to get the singletonObject, which will be put into earlySingletonObjects. ObjectFactory is a factory method schema interface that produces an object. When is the ObjectFactory object put into singletonFactories? Read on.

Key 2 – get bean, DefaultSingletonBeanRegistry# getSingleton (beanName objectFactory)

Key point 2, this method is used to get the singleton bean. Let’s look at the implementation code:

public Object getSingleton(String beanName, ObjectFactory
        singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    synchronized (this.singletonObjects) {
            // Get it from singletonObjects first
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                    if (this.singletonsCurrentlyInDestruction) {
                            throw new BeanCreationNotAllowedException(beanName,
                                            "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                                            "(Do not request a bean from a BeanFactory in a destroy method implementation!) ");
                    }
                    if (logger.isDebugEnabled()) {
                            logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
                    }

                    // Add the current bean to the set collection being created
                    beforeSingletonCreation(beanName);

                    boolean newSingleton = false;
                    boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
                    if (recordSuppressedExceptions) {
                            this.suppressedExceptions = new LinkedHashSet<>();
                    }
                    try {
                            // Create the bean, call createBean
                            singletonObject = singletonFactory.getObject();
                            newSingleton = true;
                    }
                    catch (IllegalStateException ex) {
                            // Has the singleton object implicitly appeared in the meantime ->
                            // if yes, proceed with it since the exception indicates that state.
                            singletonObject = this.singletonObjects.get(beanName);
                            if (singletonObject == null) {
                                    throwex; }}catch (BeanCreationException ex) {
                            if (recordSuppressedExceptions) {
                                    for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); }}throw ex;
                    }
                    finally {
                            if (recordSuppressedExceptions) {
                                    this.suppressedExceptions = null;
                            }

                            // The current bean is removed from the set being created
                            afterSingletonCreation(beanName);
                    }
                    if (newSingleton) {
                            // Add the bean to singletonObjects and remove it from singletonFactories and earlySingletonObjectsaddSingleton(beanName, singletonObject); }}returnsingletonObject; }}Copy the code

There are several key codes in this, I will analyze them in detail.

BeforeSingletonCreation method

Let’s first look at the internal implementation of the BeforesletonCreation method:

protected void beforeSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
            throw newBeanCurrentlyInCreationException(beanName); }}Copy the code

It can be seen that this method is to add bean into singletonsCurrentlyInCreation in the collection, also is the answer when the bean is added into the above singletonsCurrentlyInCreation in the collection. InCreationCheckExclusions need to explain, refer to rule out bean is created, that is if a bean in this collection, explain the bean cannot be added to the singletonsCurrentlyInCreation collection, A bean is generally not in the inCreationCheckExclusions, so can be added to the singletonsCurrentlyInCreation.

singletonObject = singletonFactory.getObject()

What singletonFactory. GetObject (), enforce a AbstractAutowireCapableBeanFactory# createBean method, behind this is to say, also is the process of creating bean. SingletonFactory. GetObject () returns a value, also is to create bean, assigned to singletonObject.

AfterSingletonCreation (beanName) method

protected void afterSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
            throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); }}Copy the code

AfterSingletonCreation method is actually the beans from is creating a collection of singletonsCurrentlyInCreation removed, said the bean has been created.

AddSingleton (beanName, singletonObject) method

protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
            this.singletonObjects.put(beanName, singletonObject);
            this.singletonFactories.remove(beanName);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName); }}Copy the code

This method adds a bean to singletonObjects and removes the associated bean from singletonFactories and earlySingletonObjects, at which point the bean is already a complete bean, It is stored in singletonObjects and can be retrieved directly from singletonObjects if obtained via getBean without creation.

summary

Through the above analysis, I make a simple summary here to consolidate the previous analysis. Here I will introduce it step by step:

  • 1. Spring obtains the bean through getBean method, which actually calls doGetBean method inside;
  • 2. Inside the doGetBean method I have listed three key areas, as follows:
// Key point 1
// Get it from the cacheObject sharedInstance = getSingleton(beanName); .// Singleton bean creation
//Create bean instance.
if (mbd.isSingleton()) {
    // Key point 2
    sharedInstance = getSingleton(beanName, () -> {
            try {
                // Key point 3
                return createBean(beanName, mbd, args);
            }
            catch (BeansException ex) {
                    // Explicitly remove instance from singleton cache: It might have been put there
                    // eagerly by the creation process, to allow for circular reference resolution.
                    // Also remove any beans that received a temporary reference to the bean.
                    destroySingleton(beanName);
                    throwex; }}); beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }...Copy the code

Let’s briefly review these key points:

Key 1: Get the bean from the Spring container using the getSingleton(beanName) method, and return the bean if the sharedInstance obtained is not NULL. The getSingleton(beanName) method internally uses three maps to handle the bean fetching. Get it from singletonObjects first. If you can get it, you don’t need to go through the following process; If not get from singletonObjects, then the bean exists in singletonsCurrentlyInCreation set again, and get out of the earlySingletonObjects; If not, and allowEarlyReference=true, then fetch a singletonFactory associated with the bean from singletonFactories. By calling the singletonFactory. GetObject () method for an object, and then back out. Pay attention to the places where there are two important, singletonsCurrentlyInCreation and allowEarlyReference singletonsCurrentlyInCreation said in the spring container is to create a bean, AllowEarlyReference said whether get early object reference, if it is true, will from singletonFactory. GetObject () to get early object reference, and then put into the earlySingletonObjects.

Key 2, DefaultSingletonBeanRegistry# getSingleton (beanName objectFactory) method, method of internal has several key areas:

  • BeforeSingletonCreation method, add the bean into singletonsCurrentlyInCreation collection, namely is creating a collection of beans
  • SingletonObject = singletonFactory. GetObject (), create a bean, through actual lamada expression calls the AbstractAutowireCapableBeanFactory# createBean method
  • AfterSingletonCreation (beanName) method, is actually the beans from is creating a collection of singletonsCurrentlyInCreation removed
  • The addSingleton(beanName, singletonObject) method adds beans to singletonObjects and removes them from singletonFactories and earlySingletonObjects

Through the analysis of a key and key 2, our the whole logic process of getBean have a more clear understanding, then, let’s take a look at three key AbstractAutowireCapableBeanFactory# createBean method of internal logic, Understand the bean creation process.

Key 3 – create a bean, AbstractAutowireCapableBeanFactory# createBean

The createBean method is used to create the bean. Here is the main code:

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
                throws BeanCreationException {...try {
                // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
                // Focus 1
                // Proxy objects can be returned
                Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
                if(bean ! =null) {
                        returnbean; }}catch (Throwable ex) {
                throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                                "BeanPostProcessor before instantiation of bean failed", ex);
        }

        try {
                // Focus 2
                / / create a bean
                Object beanInstance = doCreateBean(beanName, mbdToUse, args);
                if (logger.isTraceEnabled()) {
                        logger.trace("Finished creating instance of bean '" + beanName + "'");
                }
                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); }}Copy the code

I’ve labeled two concerns in the code above, and we’ll focus on concern two later. The code of concern is the one that gets the object of the bean when instantiating the previous bean and then returns it. Let’s look at the code here:

@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    / / beforeInstantiationResolved could enter branch is true, the default is null
    // The first time I will enter this judgment branch, because it is null
    if(! Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {// Make sure bean class is actually resolved at this point.
            / / implements postProcessBeforeInstantiation method only:
            / / 1, AbstractAutoProxyCreator
            / / 2, CommonAnnotationBeanPostProcessor (empty)
            / / 3, ScriptFactoryPostProcessor
            if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { Class<? > targetType = determineTargetType(beanName, mbd);if(targetType ! =null) {
                            / / callback InstantiationAwareBeanPostProcessor. PostProcessBeforeInstantiation () method
                            bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                            if(bean ! =null) {
                                    / / callback BeanPostProcessor. PostProcessAfterInitialization () methodbean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } mbd.beforeInstantiationResolved = (bean ! =null);
    }
    return bean;
}
Copy the code

I put some comments in the code, Can see inside actually callback callbacks respectively InstantiationAwareBeanPostProcessor. PostProcessBeforeInstantiation () method and callback BeanPostProcessor postProcessAft ErInitialization () method. Inside Spring, InstantiationAwareBeanPostProcessor. PostProcessBeforeInstantiation AbstractAutoProxyCreator, CommonAnnotationBeanPost () implementation Processor and ScriptFactoryPostProcessor, CommonAnnotationBeanPostProcessor internal implementation is empty, we focus on AbstractAutoProxyCreator. AbstractAutoProxyCreator is a key base class in the spring aop framework. Its subclass implements processing bena and proxy object generation.

DoCreateBean method

Now let’s look at the code in concern 2, where we are actually creating the bean, and let’s look at the specific implementation of the doCreateBean method:

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

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
                // Get the bean from the unfinished factoryBean cache
                // Todo is for factoryBeans
                instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
                // Create the bean instance. The important thing here is to infer the constructor
                instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        // Here is the bean inferred from the constructor, not yet matureObject bean = instanceWrapper.getWrappedInstance(); 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 {
                                . / / here call MergedBeanDefinitionPostProcessor postProcessMergedBeanDefinition () method, with combine the bd
                                // You can also do something with merging bd information
                                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.
        // Expose an object factory and add it to the singletonFactories Map
        // For example, A, which is singleton, also allows circular dependencies, and has been added to the list of beans being created in the beforeSingletonCreation method
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                        isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
                if (logger.isTraceEnabled()) {
                        logger.trace("Eagerly caching bean '" + beanName +
                                        "' to allow for resolving potential circular references");
                }
                / / add object factory here will call SmartInstantiationAwareBeanPostProcessor getEarlyBeanReference () method
                // Only AbstractautoXyCreator is available
                // Here we can process the initialized bean
                addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
                // Populate the properties
                populateBean(beanName, mbd, instanceWrapper);
                // Initialize the 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 (earlySingletonExposure) {
                // The earlySingletonReference is null when there is no loop dependency
                Object earlySingletonReference = getSingleton(beanName, false);
                if(earlySingletonReference ! =null) {
                        // If exposedObject and bean are equal, there are only two cases:
                        // earlySingletonReference is a proxy object
                        // earlySingletonReference is a proxy object
                        // To make things uniform,
                        if (exposedObject == bean) {
                                exposedObject = earlySingletonReference;
                        }
                        else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                                String[] dependentBeans = getDependentBeans(beanName);
                                Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                                for (String dependentBean : dependentBeans) {
                                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                                                actualDependentBeans.add(dependentBean);
                                        }
                                }
                                if(! actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,
                                                        "Bean with name '" + beanName + "' has been injected into other beans [" +
                                                        StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                                        "] in its raw version as part of a circular reference, but has eventually been " +
                                                        "wrapped. This means that said other beans do not use the final version of the " +
                                                        "bean. This is often the result of over-eager type matching - consider using " +
                                                        "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example."); }}}}// Register bean as disposable.
        try {
                registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
                throw new BeanCreationException(
                                mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
}
Copy the code

As you can see from the code above, the doCreateBean method is quite complex inside, and I’ll break down its implementation mechanism step by step.

CreateBeanInstance method

// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
        // Get the bean from the unfinished factoryBean cache
        // Todo is for factoryBeans
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
        // Create the bean instance. The important thing here is to infer the constructor
        instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// Here is the bean inferred from the constructor, not yet matureObject bean = instanceWrapper.getWrappedInstance(); Class<? > beanType = instanceWrapper.getWrappedClass();if(beanType ! = NullBean.class) { mbd.resolvedTargetType = beanType; }Copy the code

The above code mainly creates an instance of the bean through the createBeanInstance method. The bean is still immature and needs to go through the subsequent initialization process to become a bean that is actually usable. The createBeanInstance method is important, as is the process of inferring the bean’s constructor.

EarlySingletonExposure and DefaultSingletonBeanRegistry# addSingletonFactory

// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// Expose an object factory and add it to the singletonFactories Map
// For example, A, which is singleton, also allows circular dependencies, and has been added to the list of beans being created in the beforeSingletonCreation method
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
        if (logger.isTraceEnabled()) {
                logger.trace("Eagerly caching bean '" + beanName +
                                "' to allow for resolving potential circular references");
        }
        / / add object factory here will call SmartInstantiationAwareBeanPostProcessor getEarlyBeanReference () method
        // Only AbstractautoXyCreator is available
        // Here we can process the initialized bean
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Copy the code

In this example, you just add an ObjectFactory object to the singletonFactories Map. Inside the ObjectFactory object, the getEarlyBeanReference method is called.

I’m going to get a bool earlySingletonExposure, If the bean is a singleton, allowCircularReferences = true, and the current bean is creating a collection of bean singletonsCurrentlyInCreation, this value is true. Beans are singletons, which limit the scope of beans. That is, beans of other scopes, such as prototypes, do not have an associated ObjectFactory object. AllowCircularReferences parameter is a member of the fields, the default is true, according to whether to allow circular dependencies, this value can be set by setAllowCircularReferences method set, that is to say, developers can manually close the value, This turns off loop dependency; SingletonsCurrentlyInCreation collection in front has been introduced in detail, here is not to do too much explanation.

EarlySingletonExposure is usually true, so we’ll get into the logic. Let’s see what the addSingletonFactory method does:

protected void addSingletonFactory(String beanName, ObjectFactory
        singletonFactory) {
        Assert.notNull(singletonFactory, "Singleton factory must not be null");
        synchronized (this.singletonObjects) {
                if (!this.singletonObjects.containsKey(beanName)) {
                        this.singletonFactories.put(beanName, singletonFactory);
                        this.earlySingletonObjects.remove(beanName);
                        this.registeredSingletons.add(beanName); }}}Copy the code

As you can see, you are adding an ObjectFactory object to the singletonFactories map. This answers the question of when the ObjectFactory object is put into the singletonFactories map.

PopulateBean method

The next step is to populate the bean’s properties:

// Populate the properties
populateBean(beanName, mbd, instanceWrapper);
Copy the code

Cyclic dependencies may occur in the above code, for example, A depends on B, and B depends on A. When the property of A is filled, the creation process of B will be followed when B is found, and then the populateBean method of B will be followed, and then A will be found, and the cyclic dependency will appear. So how does Spring handle this, I will explain in detail in the second article.

InitializeBean method

// Initialize the bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
Copy the code
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
        if(System.getSecurityManager() ! =null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                        invokeAwareMethods(beanName, bean);
                        return null;
                }, getAccessControlContext());
        }
        else {
                invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null| |! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); }try {
                invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
                throw newBeanCreationException( (mbd ! =null ? mbd.getResourceDescription() : null),
                                beanName, "Invocation of init method failed", ex);
        }
        if (mbd == null| |! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }return wrappedBean;
}
Copy the code

As you can see, the initializeBean is actually a callback to some hook functions. InvokeAwareMethods is a callback to the Aware interface. To BeanPostProcessor# applyBeanPostProcessorsBeforeInitialization postProcessBeforeInitialization callback methods, The invokeInitMethods method is a callback to InitializingBean#afterPropertiesSet, To BeanPostProcessor# applyBeanPostProcessorsAfterInitialization postProcessAfterInitialization callback, So we can develop our own InitializingBean, Aware interface, implement certain functions, and then submit to spring callback, these interfaces are the core interface of Spring extension; Such as powerful in the spring aop framework, based on BeanPostProcessor# postProcessAfterInitialization for implementation.