Spring source code analysis-IOC-enable bean loading

Overview

Previously we have analyzed spring's parsing of xml configuration files, assembled the analyzed information into BeanDefinition, and saved and registered it in the corresponding BeanDefinitionRegistry. At this point, the initialization of Spring IOC is completed. Next we will explore the loading of beans.

BeanFactory

When we call explicitly or implicitly getBean(), the loading bean phase will be triggered. as follows:

public class AppTest {
    
    
    @Test
    public void MyTestBeanTest() {
    
    
        BeanFactory bf = new XmlBeanFactory( new ClassPathResource("spring-config.xml"));
        MyTestBean myTestBean = (MyTestBean) bf.getBean("myTestBean");
    }
}

We see that this method is defined in the interface BeanFactory. Let's take a look at the BeanFactory architecture, as shown in the following figure:

From the picture above we see:

(1) As a main interface, BeanFactory does not inherit any interface and is temporarily called a first-level interface.

(2) Three sub-interfaces inherit it and enhance its functionality. These three sub-interfaces are called secondary interfaces.

(3) ConfigurableBeanFactory can be called the third-level interface. The second-level interface HierarchicalBeanFactory has been enhanced again. It also inherits another foreign interface SingletonBeanRegistry.

(4) ConfigurableListableBeanFactory is a more powerful interface that inherits all the above interfaces and is all-encompassing, called a fourth-level interface. (These 4-level interfaces are the basic interface system of BeanFactory.

(5) AbstractBeanFactory, as an abstract class, implements most of the functions of the three-level interface ConfigurableBeanFactory.

(6) AbstractAutowireCapableBeanFactory is also an abstract class, inherits from AbstractBeanFactory, and additionally implements the secondary interface AutowireCapableBeanFactory

(7) DefaultListableBeanFactory inherits from AbstractAutowireCapableBeanFactory, implements the most powerful four-level interface ConfigurableListableBeanFactory, and implements a foreign interface BeanDefinitionRegistry, which is not an abstract class.

(8) Finally, there is the most powerful XmlBeanFactory, which inherits from DefaultListableBeanFactory and rewrites some functions to make itself more powerful.

definition

BeanFactory, ending with Factory, indicates that it is a factory class (interface), which is responsible for producing and managing a factory of beans . In Spring, BeanFactory is the core interface of the IOC container. Its responsibilities include instantiating, locating, configuring objects in the application and establishing dependencies between these objects. BeanFactory is just an interface, not a specific implementation of the IOC container. However, the Spring container provides many implementations, such as DefaultListableBeanFactory , Dependencies between objects . The XmlBeanFactory class will hold this XML configuration metadata and use it to build a fully configurable system or application.

BeanFactory is the originator of Spring IOC container and the basic interface of IOC container. All containers inherit and implement it from it. This shows its status. BeanFactory provides the most basic IOC container functions, that is, the standards that all containers need to implement at least.

XmlBeanFactory only provides the most basic IOC container functions. And XMLBeanFactory, inherits from DefaultListableBeanFactory. DefaultListableBeanFactory actually contains all the important functions of the basic IOC container and is a complete IOC container.

ApplicationContext contains all the functionality of BeanFactory and is generally recommended to take precedence over BeanFactory.

The BeanFactory architecture is a typical factory method pattern, that is, what kind of factory produces what kind of products. BeanFactory is the most basic abstract factory, while other IOC containers are just specific factories, corresponding to their respective Bean definition methods. But at the same time, other containers have also been expanded to provide specific services for different specific scenarios. as follows:

Resource resource = new FileSystemResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
ClassPathResource resource = new ClassPathResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {
    
    "applicationContext.xml"});
BeanFactory factory = (BeanFactory) context;

That's basically it. Then use the getBean(String beanName) method to obtain the bean instance; the methods provided by BeanFactory are extremely simple, and only provide six methods for customers to call:

  • boolean containsBean(String beanName) determines whether the factory contains a bean definition with the given name, and returns true if so.
  • Object getBean(String) Returns the bean instance registered with the given name. According to the configuration of the bean, if it is singleton mode, a shared instance will be returned, otherwise a new instance will be returned. If the specified bean is not found, this method may throw an exception.
  • Object getBean(String, Class) Returns a bean instance registered with the given name and converted to the given class type
  • Class getType(String name) returns the Class of the bean with the given name. If the specified bean instance is not found, NoSuchBeanDefinitionException exception is eliminated.
  • boolean isSingleton(String) determines whether the bean definition with the given name is singleton mode
  • String[] getAliases(String name) returns all aliases for the given bean name
package org.springframework.beans.factory;  
import org.springframework.beans.BeansException;  
public interface BeanFactory {
    
      
    String FACTORY_BEAN_PREFIX = "&";  
    Object getBean(String name) throws BeansException;  
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;  
    <T> T getBean(Class<T> requiredType) throws BeansException;  
    Object getBean(String name, Object... args) throws BeansException;  
    boolean containsBean(String name);  
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;  
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;  
    boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;  
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;  
    String[] getAliases(String name);  
}

FactoryBean

Under normal circumstances, Spring uses 用<bean>the class attribute used by the reflection mechanism to specify the implementation class to instantiate the Bean. In some cases, the process of instantiating the Bean is more complicated. If you follow the traditional method, you need to provide a <bean>large amount of configuration information. The flexibility of the configuration method is limited. In this case, a simple solution may be obtained by coding. Spring provides a factory class interface of org.springframework.bean.factory.FactoryBean for this purpose. Users can customize the logic of instantiating Beans by implementing this interface. The FactoryBean interface occupies an important position in the Spring framework. Spring itself provides more than 70 FactoryBean implementations. They hide the details of instantiating some complex beans and bring convenience to upper-layer applications. Starting from Spring 3.0, FactoryBean begins to support generics, that is, the interface declaration is changed to FactoryBean<T>the form.

Ending with Bean, it means it is a Bean. The difference from ordinary beans is that it is a Bean that implements the FactoryBean interface. What is obtained from the BeanFactory according to the ID of the Bean is actually the object returned by FactoryBean's getObject(), not FactoryBean itself, if you want to get the FactoryBean object, please add an & symbol in front of the id to get it .

package org.springframework.beans.factory;  
public interface FactoryBean<T> {
    
      
    T getObject() throws Exception;  
    Class<?> getObjectType();  
    boolean isSingleton();  
}

The following three methods are also defined in this interface:

  • T getObject() : Returns the Bean instance created by FactoryBean. If isSingleton() returns true, the instance will be placed in the single instance cache pool in the Spring container;
  • boolean isSingleton() : Returns whether the scope of the Bean instance created by FactoryBean is singleton or prototype;
  • Class getObjectType() : Returns the bean type created by FactoryBean.

<bean>When the implementation class configured by the class attribute in the configuration file is FactoryBean, what is returned through the getBean() method is not the FactoryBean itself, but the object returned by the FactoryBean#getObject() method, which is equivalent to FactoryBean#getObject() proxying getBean ( )method.
Example: If you use the traditional method to configure the following Car <bean>, each attribute of the Car corresponds to an <property>element tag.

public class Car {
    
      
    private int maxSpeed ;  
    private String brand ;  
    private double price ;  
    //get//set 方法
}

If you use FactoryBean to implement it, it will be more flexible. The following example uses comma delimiters to specify configuration values ​​​​for all properties of Car at once:

import  org.springframework.beans.factory.FactoryBean;  
public  class CarFactoryBean implements  FactoryBean<Car> {
    
      
    private String carInfo ;  
    public  Car getObject()  throws  Exception  {
    
      
        Car car = new  Car();  
        String[] infos = carInfo.split(","); 
        car.setBrand(infos[0]);
        car.setMaxSpeed(Integer.valueOf(infos[1]));
        car.setPrice(Double.valueOf(infos[2]));
        return  car;  
    }  
    public  Class<Car> getObjectType(){
    
      
        return Car.class ;  
    }  
    public boolean isSingleton(){
    
      
        return false ;  
    }  
    public String getCarInfo(){
    
      
        return  this.carInfo;  
    }  
  
    //接受逗号分割符设置属性信息  
    public void setCarInfo (String carInfo){
    
      
        this.carInfo = carInfo;  
    }  
}

With this CarFactoryBean, you can use the following custom configuration method to configure CarBean in the configuration file:

<bean d="car"class="com.dabin.spring.CarFactoryBean" P:carInfo="大奔,600,1000000"/>

When calling getBean("car"), Spring discovers through the reflection mechanism that CarFactoryBean implements the FactoryBean interface. At this time, the Spring container calls the interface method CarFactoryBean#getObject() method to return. If you want to get an instance of CarFactoryBean, you need to add the "&" prefix before the beanName when using the getBean(beanName) method: such as getBean("&car");

Get beans

Next we return to the bean loading phase. When we call explicitly or implicitly getBean(), the bean loading phase will be triggered. as follows:

public Object getBean(String name) throws BeansException {
    
    
    return doGetBean(name, null, null, false);
}

Internal call doGetBean()method, the code of this method is relatively long, please read it patiently:

@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
        @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    
    
    //获取 beanName,这里是一个转换动作,将 name 转换为 beanName
    final String beanName = transformedBeanName(name);
    Object bean;
    /*
     *检查缓存中的实例工程是否存在对应的实例
     *为何要优先使用这段代码呢?
     *因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖
     *spring创建bean的原则是在不等bean创建完就会将创建bean的objectFactory提前曝光,即将其加入到缓存中,一旦下个bean创建时依赖上个bean则直接使用objectFactory          
     *直接从缓存中或singletonFactories中获取objectFactory
     *就算没有循环依赖,只是单纯的依赖注入,如B依赖A,如果A已经初始化完成,B进行初始化时,需要递归调用getBean获取A,这是A已经在缓存里了,直接可以从这里取到
     */
    // Eagerly check singleton cache for manually registered singletons.
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
    
    
        if (logger.isDebugEnabled()) {
    
    
            if (isSingletonCurrentlyInCreation(beanName)) {
    
    
                logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
    
    
                logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        //返回对应的实例,有些时候并不是直接返回实例,而是返回某些方法返回的实例
        //这里涉及到我们上面讲的FactoryBean,如果此Bean是FactoryBean的实现类,如果name前缀为"&",则直接返回此实现类的bean,如果没有前缀"&",则需要调用此实现类的getObject方法,返回getObject里面真是的返回对象
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    else {
    
    
        //只有在单例的情况下才会解决循环依赖
        if (isPrototypeCurrentlyInCreation(beanName)) {
    
    
            throw new BeanCurrentlyInCreationException(beanName);
        }
        //尝试从parentBeanFactory中查找bean
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
    
    
            // Not found -> check parent.
            String nameToLookup = originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
    
    
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                        nameToLookup, requiredType, args, typeCheckOnly);
            }
            else if (args != null) {
    
    
                // Delegation to parent with explicit args.
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else {
    
    
                // No args -> delegate to standard getBean method.
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
        }
        //如果不是仅仅做类型检查,则这里需要创建bean,并做记录
        if (!typeCheckOnly) {
    
    
            markBeanAsCreated(beanName);
        }
        try {
    
    
            //将存储XML配置文件的GenericBeanDefinition转换为RootBeanDefinition,同时如果存在父bean的话则合并父bean的相关属性
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            //如果存在依赖则需要递归实例化依赖的bean
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
    
    
                for (String dep : dependsOn) {
    
    
                    if (isDependent(beanName, dep)) {
    
    
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    registerDependentBean(dep, beanName);
                    try {
    
    
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
    
    
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }

            // 单例模式
            // 实例化依赖的bean后对bean本身进行实例化
            if (mbd.isSingleton()) {
    
    
                sharedInstance = getSingleton(beanName, () -> {
    
    
                    try {
    
    
                        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);
                        throw ex;
                    }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
            // 原型模式
            else if (mbd.isPrototype()) {
    
    
                // It's a prototype -> create a new instance.
                Object prototypeInstance = null;
                try {
    
    
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
    
    
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }
            // 从指定的 scope 下创建 bean
            else {
    
    
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
    
    
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
    
    
                    Object scopedInstance = scope.get(beanName, () -> {
    
    
                        beforePrototypeCreation(beanName);
                        try {
    
    
                            return createBean(beanName, mbd, args);
                        }
                        finally {
    
    
                            afterPrototypeCreation(beanName);
                        }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
    
    
                    throw new BeanCreationException(beanName,
                            "Scope '" + scopeName + "' is not active for the current thread; consider " +
                            "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                            ex);
                }
            }
        }
        catch (BeansException ex) {
    
    
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    // Check if required type matches the type of the actual bean instance.
    if (requiredType != null && !requiredType.isInstance(bean)) {
    
    
        try {
    
    
            T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
            if (convertedBean == null) {
    
    
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
            return convertedBean;
        }
        catch (TypeMismatchException ex) {
    
    
            if (logger.isDebugEnabled()) {
    
    
                logger.debug("Failed to convert bean '" + name + "' to required type '" +
                        ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    return (T) bean;
}

The code is quite long and the processing logic is quite complicated. I will break it down and explain it below.

Get beanName

final String beanName = transformedBeanName(name);

What is passed here is name, not necessarily beanName, it may be aliasName, or it may be FactoryBean (with "&" prefix), so here you need to call the transformedBeanName()method to convert the name, mainly as follows:

protected String transformedBeanName(String name) {
    
    
    return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}

// 去除 FactoryBean 的修饰符
public static String transformedBeanName(String name) {
    
    
    Assert.notNull(name, "'name' must not be null");
    String beanName = name;
    while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
    
    
        beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
    }
    return beanName;
}

// 转换 aliasName
public String canonicalName(String name) {
    
    
    String canonicalName = name;
    // Handle aliasing...
    String resolvedName;
    do {
    
    
        resolvedName = this.aliasMap.get(canonicalName);
        if (resolvedName != null) {
    
    
            canonicalName = resolvedName;
        }
    }
    while (resolvedName != null);
    return canonicalName;
}

The main processing process includes two steps:

  1. Remove the FactoryBean modifier. If the name is prefixed with "&", then the "&" will be removed, for example, name = "&studentService"it will be name = "studentService".
  2. Gets the final beanName represented by the specified alias. It is mainly a process of cyclically obtaining beanName. For example, if alias A points to a bean named B, B will be returned. If alias A points to alias B and alias B points to a bean named C, C will be returned.

Get singleton bean from cache

A singleton will only be created once in the same Spring container. Subsequent bean acquisitions are obtained directly from the singleton cache. Of course, here we only try to load, first try to load from the cache, and then try to load from the singletonFactory again because when creating There will be dependency injection when creating a single bean. In order to avoid circular dependencies when creating dependencies, Spring's principle of creating beans is to create the bean's ObjectFactory and add it to the cache early before the bean is created. Once the next bean is created, If you need to rely on the previous bean when creating, use ObjectFactory directly; even if there is no circular dependency, it is just simple dependency injection. For example, B depends on A. If A has been initialized, when B is initialized, it needs to recursively call getBean to obtain A. This is A It is already in the cache and can be retrieved directly from here. Next, let’s look at the method getSingleton(beanName) to obtain a singleton bean and enter the method body:

@Override
@Nullable
public Object getSingleton(String beanName) {
    
    
    //参数true是允许早期依赖
    return getSingleton(beanName, true);
}
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    
    
    //检查缓存中是否存在实例,这里就是上面说的单纯的依赖注入,如B依赖A,如果A已经初始化完成,B进行初始化时,需要递归调用getBean获取A,这是A已经在缓存里了,直接可以从这里取到
    Object singletonObject = this.singletonObjects.get(beanName);
    //如果缓存为空且单例bean正在创建中,则锁定全局变量,为什么要判断bean在创建中呢?这里就是可以判断是否循环依赖了。
    //A依赖B,B也依赖A,A实例化的时候,发现依赖B,则递归去实例化B,B发现依赖A,则递归实例化A,此时会走到原点A的实例化,第一次A的实例化还没完成,只不过把实例化的对象加入到缓存中,但是状态还是正在创建中,由此回到原点发现A正在创建中,由此可以判断是循环依赖了
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    
    
        synchronized (this.singletonObjects) {
    
    
            //如果此bean正在加载,则不处理
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
    
    
                //当某些方法需要提前初始化的时候会直接调用addSingletonFactory把对应的ObjectFactory初始化策略存储在singletonFactory中
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
    
    
                    //使用预先设定的getObject方法
                    singletonObject = singletonFactory.getObject();
                    记录在缓存中,注意earlySingletonObjects和singletonFactories是互斥的
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

Next, we will sort out this method based on the source code, so that it is easier to understand. This method first tries to get the instance from singletonObjects. If it cannot be obtained, then obtain it from earlySingletonObjects. If it still cannot be obtained, then try to obtain the beanName from singletonFactories. The corresponding ObjectFactory, and then call the getObject method of this ObjectFactory to create a bean, put it in earlySingletonObjects, and remove the ObjectFactory from singletonFactoryes, and all subsequent memory operations are only used for circular dependency detection, that is, allowEarlyReference is It will only be used when true.
This involves many different maps for storing beans. Let’s briefly explain:

1.singletonObjects: used to save the relationship between BeanName and create bean instances, beanName–>bean Instance

2.singletonFactories: used to save the relationship between BeanName and the factory that created the bean, banName–>ObjectFactory

3.earlySingletonObjects: It is also the relationship between saving BeanName and creating bean instances. The difference from singletonObjects is that when a singleton bean is placed here, then when the bean is still in the creation process, you can use the getBean method. Obtained, its purpose is to detect circular references.

4.registeredSingletons: used to save all currently registered beans.

Get an object from a bean instance

After obtaining the bean, you need to obtain the instance object. The getObjectForBeanInstance method is used here. getObjectForBeanInstance is a frequently used method, whether it is to obtain the bean from the cache or to load the bean according to different scope strategies. In short, after we get the bean instance, the first step is to call this method to check the correctness. In fact, it is Check whether the obtained bean is a bean of FactoryBean type. If so, you need to call getObject() in the FactoryBean instance corresponding to the bean as the return value. Next let’s take a look at the source code of this method:

protected Object getObjectForBeanInstance(
        Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
    
    
    //如果指定的name是工厂相关的(以&开头的)
    if (BeanFactoryUtils.isFactoryDereference(name)) {
    
    
        //如果是NullBean则直接返回此bean
        if (beanInstance instanceof NullBean) {
    
    
            return beanInstance;
        }
        //如果不是FactoryBean类型,则验证不通过抛出异常
        if (!(beanInstance instanceof FactoryBean)) {
    
    
            throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
        }
    }
    // Now we have the bean instance, which may be a normal bean or a FactoryBean.
    // If it's a FactoryBean, we use it to create a bean instance, unless the
    // caller actually wants a reference to the factory.
    //如果获取的beanInstance不是FactoryBean类型,则说明是普通的Bean,可直接返回
    //如果获取的beanInstance是FactoryBean类型,但是是以(以&开头的),也直接返回,此时返回的是FactoryBean的实例
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
    
    
        return beanInstance;
    }
    Object object = null;
    if (mbd == null) {
    
    
        object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
    
    
        // Return bean instance from factory.
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // Caches object obtained from FactoryBean if it is a singleton.
        if (mbd == null && containsBeanDefinition(beanName)) {
    
    
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        //到了这里说明获取的beanInstance是FactoryBean类型,但没有以"&"开头,此时就要返回factory内部getObject里面的对象了
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}

Then let's take a look at the real core function implemented in the getObjectFromFactoryBean(factory, beanName, !synthetic) method and continue to follow the code:

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    
    
    // 为单例模式且缓存中存在
    if (factory.isSingleton() && containsSingleton(beanName)) {
    
    

        synchronized (getSingletonMutex()) {
    
    
            // 从缓存中获取指定的 factoryBean
            Object object = this.factoryBeanObjectCache.get(beanName);

            if (object == null) {
    
    
                // 为空,则从 FactoryBean 中获取对象
                object = doGetObjectFromFactoryBean(factory, beanName);

                // 从缓存中获取
                Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                if (alreadyThere != null) {
    
    
                    object = alreadyThere;
                }
                else {
    
    
                    // 需要后续处理
                    if (shouldPostProcess) {
    
    
                        // 若该 bean 处于创建中,则返回非处理对象,而不是存储它
                        if (isSingletonCurrentlyInCreation(beanName)) {
    
    
                            return object;
                        }
                        // 前置处理
                        beforeSingletonCreation(beanName);
                        try {
    
    
                            // 对从 FactoryBean 获取的对象进行后处理
                            // 生成的对象将暴露给bean引用
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        }
                        catch (Throwable ex) {
    
    
                            throw new BeanCreationException(beanName,
                                    "Post-processing of FactoryBean's singleton object failed", ex);
                        }
                        finally {
    
    
                            // 后置处理
                            afterSingletonCreation(beanName);
                        }
                    }
                    // 缓存
                    if (containsSingleton(beanName)) {
    
    
                        this.factoryBeanObjectCache.put(beanName, object);
                    }
                }
            }
            return object;
        }
    }
    else {
    
    
        // 非单例
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        if (shouldPostProcess) {
    
    
            try {
    
    
                object = postProcessObjectFromFactoryBean(object, beanName);
            }
            catch (Throwable ex) {
    
    
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        return object;
    }
}

This method should be one of the core methods in creating bean instance objects. Here we focus on three methods: beforeSingletonCreation(), afterSingletonCreation(), postProcessObjectFromFactoryBean(). Some friends may think that the first two methods are not very important. LZ can definitely tell you that these two methods are very important operations because they record the loading status of the bean and are the key to detecting whether the current bean is being created. Plays a key role in resolving bean circular dependencies. The before method is used to mark that the current bean is being created, and the after method is used to remove it. In fact, it was mentioned at the beginning of this blog isSingletonCurrentlyInCreation()that it is used to detect whether the current bean is being created, as follows:

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

It is based on whether the singletonsCurrentlyInCreation collection contains beanName, and the elements of the collection must be beforeSingletonCreation()added in, as follows:

protected void beforeSingletonCreation(String beanName) {
    
    
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
    
    
        throw new BeanCurrentlyInCreationException(beanName);
    }
}

afterSingletonCreation()To remove, you must remove the singletonsCurrentlyInCreation collection, as follows:

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

Let’s take a look at the real core method doGetObjectFromFactoryBean

private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
        throws BeanCreationException {
    
    

    Object object;
    try {
    
    
        if (System.getSecurityManager() != null) {
    
    
            AccessControlContext acc = getAccessControlContext();
            try {
    
    
                object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
            }
            catch (PrivilegedActionException pae) {
    
    
                throw pae.getException();
            }
        }
        else {
    
    
            object = factory.getObject();
        }
    }
    catch (FactoryBeanNotInitializedException ex) {
    
    
        throw new BeanCurrentlyInCreationException(beanName, ex.toString());
    }
    catch (Throwable ex) {
    
    
        throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
    }

    // Do not accept a null value for a FactoryBean that's not fully
    // initialized yet: Many FactoryBeans just return null then.
    if (object == null) {
    
    
        if (isSingletonCurrentlyInCreation(beanName)) {
    
    
            throw new BeanCurrentlyInCreationException(
                    beanName, "FactoryBean which is currently in creation returned null from getObject");
        }
        object = new NullBean();
    }
    return object;
}

We have introduced the calling method of FactoryBean before. If the bean is declared as FactoryBean type, when extracting the bean, what is extracted is not the FactoryBean, but the bean returned by the corresponding getObject method in FactoryBean, and doGetObjectFromFactroyBean really implements this function.

After calling the doGetObjectFromFactoryBean method, there is no direct return. The getObjectFromFactoryBean method also calls the object = postProcessObjectFromFactoryBean(object, beanName); method. In the subclass AbstractAutowireCapableBeanFactory, there is an implementation of this method:

@Override
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
    
    
    return applyBeanPostProcessorsAfterInitialization(object, beanName);
}
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {
    
    
    Object result = existingBean;
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
    
    
        Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
    
    
            return result;
        }
        result = current;
    }
    return result;
}

As for the use of post-processors, we have not yet touched on it. There will be a lot of introduction in the follow-up. Here we only need to understand that there is such a rule in Spring's bean acquisition rules: try to ensure that all beans will call the registered BeanPostProcessor's postProcessAfterInitialization after initialization. Methods are used for processing. In the actual development process, you can design your own business processing for this feature.

Guess you like

Origin blog.csdn.net/Tyson0314/article/details/133293854