【Spring详解五】bean的加载

news2025/3/26 21:16:12

五、bean的加载

当我们显示或者隐式地调用 getBean() 时,则会触发加载 bean 阶段。示例代码如下:
public class AppTest {
    @Test
    public void MyTestBeanTest() {
        BeanFactory bf = new XmlBeanFactory( new ClassPathResource("spring-config.xml"));
        MyTestBean myTestBean = (MyTestBean) bf.getBean("myTestBean");
    }
}

(1)BeanFactory

从上图我们看到:  
(1) BeanFactory作为一个主接口不继承任何接口,暂且称为一级接口。
(2)有3个子接口继承了它,进行功能上的增强。这3个子接口称为二级接口。
(3) ConfigurableBeanFactory可以被称为三级接口,对二级接口 HierarchicalBeanFactory进行了再次增强,它还继承了另一个外来的接口 SingletonBeanRegistry
(4) ConfigurableListableBeanFactory是一个更强大的接口,继承了上述的所有接口,无所不包,称为四级接口。(这4级接口是BeanFactory的基本接口体系。继续,下面是继承关系的2个抽象类和2个实现类:)
(5) AbstractBeanFactory作为一个抽象类,实现了三级接口ConfigurableBeanFactory大部分功能。
(6) AbstractAutowireCapableBeanFactory同样是抽象类,继承自AbstractBeanFactory,并额外实现了二级接口 AutowireCapableBeanFactory
(7) DefaultListableBeanFactory继承自AbstractAutowireCapableBeanFactory,实现了最强大的四级接口ConfigurableListableBeanFactory,并实现了一个外来接口 BeanDefinitionRegistry,它并非抽象类。
(8)最后是最强大的 XmlBeanFactory,继承自DefaultListableBeanFactory,重写了一些功能,使自己更强大。
BeanFactory提供的方法及其简单,仅提供了六种方法供客户调用:
  • boolean containsBean(String beanName) 判断工厂中是否包含给定名称的bean定义,若有则返回true
  • Object getBean(String) 返回给定名称注册的bean实例。根据bean的配置情况,如果是singleton模式将返回一个共享实例,否则将返回一个新建的实例,如果没有找到指定bean,该方法可能会抛出异常
  • Object getBean(String, Class) 返回以给定名称注册的bean实例,并转换为给定class类型
  • Class getType(String name) 返回给定名称的bean的Class,如果没有找到指定的bean实例,则排除NoSuchBeanDefinitionException异常
  • boolean isSingleton(String) 判断给定名称的bean定义是否为单例模式
  • String[] getAliases(String name) 返回给定bean名称的所有别名
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);  
}
BeanFactory,以Factory结尾,表示它是一个工厂类(接口), 它负责生产和管理bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactoryXmlBeanFactoryApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。
  • BeanFactory:Spring IOC容器的鼻祖,是IOC容器的基础接口,所有的容器都是从它这里继承实现而来。可见其地位。BeanFactory提供了最基本的IOC容器的功能,即所有的容器至少需要实现的标准。
  • XmlBeanFactory:实现了最基本的IOC容器的功能。 XMLBeanFactory 继承自DefaultListableBeanFactory 。
  • DefaultListableBeanFactory实际包含了基本IOC容器所具有的所有重要功能,是一个完整的IOC容器
  • ApplicationContext包含BeanFactory的所有功能,通常建议比BeanFactory优先。
  BeanFactory体系结构是典型的 工厂方法模式,即什么样的工厂生产什么样的产品。BeanFactory是最基本的抽象工厂,而其他的IOC容器只不过是具体的工厂,对应着各自的Bean定义方法。但同时,其他容器也针对具体场景不同,进行了扩充,提供具体的服务。 如下:
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;

(2) FactoryBean

一般情况下,Spring通过 反射机制利用 的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory. FactoryBean的工厂类接口,用户可以通过实现该接口 定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占有重要的地位,Spring自身就 提供了70多个FactoryBean的实现。它们 隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean的形式。
以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean接口的Bean,根据该Bean的ID 从BeanFactory中获取的实际上是 FactoryBean的getObject()返回的对象,而不是FactoryBean本身,如果要 获取FactoryBean对象,请在id前面加一个&符号来获取。后面我们会从源码来分析这一块
package org.springframework.beans.factory;  
public interface FactoryBean<T> {  
    T getObject() throws Exception;  
    Class<?> getObjectType();  
    boolean isSingleton();  
}
在该接口中还定义了以下3个方法:
  • T getObject():返回由FactoryBean创建的Bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中;
  • boolean isSingleton():返回由FactoryBean创建的Bean实例的作用域是singleton还是prototype;
  • Class getObjectType():返回FactoryBean创建的Bean类型。
当配置文件中的class属性配置的 实现类是FactoryBean时,通过 getBean()方法返回的 不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的对象,相当于 FactoryBean#getObject()代理了getBean()方法
例:如果使用传统方式配置下面Car的时,Car的每个属性分别对应一个元素标签。
public class Car {  
    private int maxSpeed ;  
    private String brand ;  
    private double price ;  
    //get set 方法
}
如果用FactoryBean的方式实现就灵活点,下例通过逗号分割符的方式一次性的为Car的所有属性指定配置值:
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;  
    }  
}
有了这个CarFactoryBean后,就可以在配置文件中使用下面这种自定义的配置方式配置CarBean了:
<bean d="car" class="com.wangjiafu.spring.CarFactoryBean" P:carInfo="大奔,600,1000000"/>
当调用 getBean("car")时,Spring通过反射机制发现CarFactoryBean实现了FactoryBean的接口,这时Spring容器就调用接口方法 CarFactoryBean#getObject()方法返回。如果 希望获取CarFactoryBean的实例,则需要 在使用getBean(beanName)方法时在beanName前显示的加上"&"前缀:如 getBean("&car");

5.1 getBean(String beanName)

使用 getBean(String beanName)方法就可以 取得bean的实例;我们来看 getBean() 方法, XmlBeanFactory使用的是 AbstractBeanFactory的实现,具体代码如下:
# AbstractBeanFactory
public Object getBean(String name) throws BeansException {
   return doGetBean(name, null, null, false);
}

@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;
}
代码相当复杂,步骤大致如下:
  1. 获取beanName :这里传入的参数有可能是别名,也有可能是FactoryBean,所以需要进行一系列的解析,这些解析内容包括如下内容。
    1. 去除FactroyBean的修饰符,也就是如果name=“&aa”,那么会首先去除&而使name=“aa”。
    2. 去除alisa所表示的最终beanName,例如别名A指向名称为B的bean则返回B;若别名A指向别名B,别名B又指向名称为C的bean则返回C。
  2. 缓存中获取单例 :单例在Spring的同一个容器中只会被创建一次,后续在获取bean,就直接从单例缓存中获取了。当然这里也尝试加载,如果不成功则再次尝试从singletonFactories中加载。因为在创建单例bean的时候会在存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,在Spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建时候需要依赖上一个bean直接使用ObjectFactory
  3. 从bean的实例中获取对象 :如果从缓存中得到了bean的原始状态,则需要对bean进行实例化。这里必须强调一下,缓存中记录的只是最原始的bean状态,并不一定是最终想要的bean。使用 getObjectForBeanInstance() 完成这个工作。
  4. 原型模式的依赖检查 :只有在单例情况下才会尝试解决循环依赖,如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候,就是产生当A还未创建完的时候因为对于B的创建再次返回创建A,造成循环依赖,也就是情况:isPrototypeCurrentlyInCreation(beanName) 判断为true。
  5. 检测parentBeanFactory :从代码上看,如果缓存没有数据的话直接转到父类工厂上去加载了,这是为什么呢?它是在检测如果加载的XML配置文件中不包含beanName所对应的配置,就只能到parentBeanFactory去尝试加载了,然后再去递归的调用 getBean() 方法。
  6. 将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition :因为从XML配置文件读取到的Bean的信息是存储在GenericBeanDefinition中的,但是所有的Bean后续处理都是针对RootBeanDefinition的,所以这里需要进行一个转换,转换的同时如果父类bean不为空的话,则会一并合并父类的属性
  7. 寻找依赖 :因为bean的初始化过程中可能会用到某些属性,而某些属性可能是动态配置且配置成依赖于其他的bean,那么这个时候就有必要先加载依赖的bean,所以,在Spring加载顺序中在初始化某一个bean的时候首先会初始化这个bean所对应的依赖
  8. 针对不同Scope进行bean的创建 :在Spring中存在不同的scope,其中默认的是singleton,但是还有注入prototype,request之类的,在这个步骤中,Spring会根据不同的配置进行不同的初始化策略。
  9. 类型转换 :程序到这里返回bean后基本结束了,通常对该方法的调用参数requireType是为空的,但是可能会存在这样的情况返回的bean其实是一个String,但是requireType却传入Integer类型,那么这时候本步骤就会起作用了,它的功能就是将返回的bean转换为requireType所指定的类型。当然,String转换为Integer是最简单的一种转换,在Spring中提供了各种各样的转换器,用户也可以自己扩展转换器来满足自己的需求。

5.1.1 获取 beanName

AbstractBeanFactory.class
这里传递的是 name,不一定就是 beanName,可能是 aliasName,也有可能是 FactoryBean(带“&”前缀),所以这里需要调用 transformedBeanName() 方法对 name 进行一番转换,主要如下:
# AbstractBeanFactory
protected String transformedBeanName(String name) {
    return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}

# BeanFactoryUtils
String FACTORY_BEAN_PREFIX = "&"; //BeanFactory.FACTORY_BEAN_PREFIX
// 去除 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;
}

# SimpleAliasRegistry
// 转换 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;
}
主要处理过程包括两步:
  • 去除 FactoryBean 的修饰符。如果 name 以 “&” 为前缀,那么会去掉该 “&”,例如,name = "&studentService",则会是 name = "studentService"。
  • 取指定的 alias 所表示的最终 beanName。主要是一个循环获取 beanName 的过程,例如别名 A 指向名称为 B 的 bean 则返回 B,若 别名 A 指向别名 B,别名 B 指向名称为 C 的 bean,则返回 C。

5.1.2 缓存中获取单例bean_解决循环依赖

AbstractBeanFactory.class
单例在Spring的同一个容器内只会被创建一次,后续再获取bean直接从单例缓存中获取,当然这里也只是尝试加载, 首先尝试从缓存中加载,然后 再次尝试从 singletonFactorry 加载,因为在创建单例bean的时候会存在依赖注入的情况,而在 创建依赖的时候为了避免循环依赖,Spring创建bean的原则是 不等bean创建完成就会创建bean的 ObjectFactory 提早曝光加入到缓存中,一旦 下一个bean创建时需要依赖上个bean,则直接使用ObjectFactory;就算没有循环依赖,只是单纯的依赖注入,如B依赖A,如果A已经初始化完成,B进行初始化时,需要递归调用getBean获取A,这是A已经在缓存里了,直接可以从这里取到。接下来我们看下获取单例bean的方法getSingleton(beanName),进入方法体:
# DefaultSingletonBeanRegistry
@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;
}
接下来我们根据源码再来梳理下这个方法,这样更易于理解:
  1. 先尝试从singletonObjects里面获取实例,如果获取不到再从earlySingletonObjects里面获取,如果还获取不到,再尝试从singletonFactories里面获取beanName对应的ObjectFactory
  2. 然后再调用这个 ObjectFactory#getObject() 方法创建bean,并放到earlySingletonObjects里面去,并且从singletonFactoryes里面remove掉这个ObjectFactory,而对于后续所有的内存操作都只为了循环依赖检测时候使用,即allowEarlyReference为true的时候才会使用。
这里涉及到很多个存储bean的不同map,简单解释下:
  • singletonObjects : 用于保存BeanName和创建bean实例之间的关系,beanName–>bean Instance
  • earlySingletonObjects : 也是保存BeanName和bean实例之间的关系,与singletonObjects的不同之处在于,在这个Map里的Bean不是完整的,甚至还不能称之为“Bean”,只是一个Instance。即当一个单例bean被放到这里面后,那么当bean还在创建过程中,就可以通过getBean方法获取到了,其目的是用来检测循环引用
  • singletonFactories : 用于保存BeanName和创建bean的工厂之间的关系,banName–>ObjectFactory
  • registeredSingletons : 用来保存当前所有已注册的bean
#DefaultSingletonBeanRegistry

/** Cache of singleton objects: bean name to bean instance. */
//一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

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

/** Cache of early singleton objects: bean name to bean instance. */
//二级缓存
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

/** Set of registered singletons, containing the bean names in registration order. */
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
那么Spring 是如何通过上面介绍的三级缓存来解决循环依赖的呢?这里只用 A,B 形成的循环依赖来举例:
  1. 实例化 A,此时 A 还未完成 属性填充(AbstractAutowireCapableBeanFactory#populateBean)和 初始化方法(AbstractAutowireCapableBeanFactory#initializeBean)的执行,A 只是一个半成品。
  2. 为 A 创建一个 Bean工厂,并放入到 singletonFactories 中(DefaultSingletonBeanRegistry#addSingletonFactory)。
  3. 发现 A 需要注入 B 对象,但是一级、二级、三级缓存均未发现对象 B(DefaultSingletonBeanRegistry#getSingleton)。
  4. 实例化 B,此时 B 还未完成属性填充和初始化方法的执行,B 只是一个半成品。
  5. 为 B 创建一个 Bean工厂,并放入到 singletonFactories 中。
  6. 发现 B 需要注入 A 对象,此时在一级、二级未发现对象A,但是在三级缓存中发现了对象 A,从三级缓存中得到对象 A,并将对象 A 放入二级缓存中,同时删除三级缓存中的对象 A。(注意,此时的 A还是一个半成品,并没有完成属性填充和执行初始化方法)
  7. 将对象 A 注入到对象 B 中。
  8. 对象 B 完成属性填充,执行初始化方法,并放入到一级缓存中,同时删除二级缓存中的对象 B。(此时对象 B 已经是一个成品)
  9. 对象 A 得到对象B,将对象 B 注入到对象 A 中。(对象 A 得到的是一个完整的对象 B)
  10. 对象 A完成属性填充,执行初始化方法,并放入到一级缓存中,同时删除二级缓存中的对象 A。

5.1.3 从bean的实例中获取对象_FactoryBean处理

AbstractBeanFactory.class
缓存中记录的只是bean的原始状态,并不一定是最终想要的bean,举个例子:假如我们需要对 FactoryBean进行处理,那么这里得到的其实是 FactoryBean的初始状态,但是我们真正需要的是 FactoryBean中定义的 factory-method 方法中返回的bean,所以要使用 getObjectForBeanInstance() 完成这个工作。getObjectForBeanInstance() 是个频繁使用的方法,无论是从缓存中获得bean还是根据不同的scope策略加载bean。总之,我们得到bean的实例后,要做的第一步就是调用这个方法来检测一下bean的正确性,其实就是 检测获得Bean是不是FactoryBean类型的bean,如果是,那么需要调用该bean对应的 FactoryBean#getObject() 作为返回值。
接下来我们看下此方法的源码:
# AbstractBeanFactory
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;
}
从上面的代码来看,这个方法大多是些辅助代码以及功能性判断,而真正的核心工作委托给了 getObjectFromFactoryBean(factory, beanName, !synthetic)方法,我们来看看 getObjectForBeanInstance() 中所做的工作:
  • 对FactoryBean正确性的验证
  • 对非FactoryBean不做任何处理
  • 对bean进行转换
  • 将从Factory中解析bean的工作委托给getObjectFromFactoryBean(factory, beanName, !synthetic)方法
接着我们来看看真正的核心功能 getObjectFromFactoryBean(factory, beanName, !synthetic)方法中实现的,继续跟进代码:
# FactoryBeanRegistrySupport
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;
    }
}
该方法应该就是创建 bean 实例对象中的核心方法之一了。这里我们关注三个方法: beforeSingletonCreation()afterSingletonCreation()postProcessObjectFromFactoryBean()。前面两个方法是非常重要的操作,他们记录着 bean 的加载状态,是检测当前 bean 是否处于创建中的关键之处,对解决 bean 循环依赖起着关键作用。before 方法用于标志当前 bean 处于创建中,after 则是移除。
isSingletonCurrentlyInCreation()用于检测当前 bean 是否处于创建之中,如下:
# DefaultSingletonBeanRegistry
public boolean isSingletonCurrentlyInCreation(String beanName) {
    return this.singletonsCurrentlyInCreation.contains(beanName);
}
是根据 this.singletonsCurrentlyInCreation 集合中是否包含了 beanName,集合的元素则是在 beforeSingletonCreation() 中添加的,如下:
# DefaultSingletonBeanRegistry
protected void beforeSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
    }
}
afterSingletonCreation() 为移除,则一定就是对 this.singletonsCurrentlyInCreation 集合 remove 了,如下:
# DefaultSingletonBeanRegistry
protected void afterSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
        throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
    }
}
我们再来看看真正的核心方法 doGetObjectFromFactoryBean() ,其中调用了 FactoryBean#getObject 方法 :
# FactoryBeanRegistrySupport
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 {
            //直接调用 FactoryBean#getObject 方法
            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;
}
以前我们曾经介绍过 FactoryBean的调用方法,如果bean声明为FactoryBean类型,则 当提取bean时候提取的不是FactoryBean,而是FactoryBean中对应的getObject()方法返回的bean,而 doGetObjectFromFactroyBean() 则是实现这个功能。
而调用完 doGetObjectFromFactoryBean() 方法后,并没有直接返回, getObjectFromFactoryBean() 方法中还调用了 object = postProcessObjectFromFactoryBean(object, beanName) 方法,在子类 AbstractAutowireCapableBeanFactory,有这个方法的实现。
源码如下:
# AbstractAutowireCapableBeanFactory
@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;
}
对于 后处理器的使用,我们目前还没接触,后续会有大量篇幅介绍,这里我们只需要了解在Spring获取bean的规则中有这样一条:尽可能保证 所有bean初始化后都会 调用注册的 BeanPostProcessor #postProcessAfterInitialization() 方法进行处理,在实际开发过程中大可以针对此特性设计自己的业务处理。

5.1.4 获取单例

AbstractBeanFactory.class
之前我们已经讲解过从缓存中获取单例的过程,那么,如果缓存中不存在已经加载的单例bean就需要从头开始bean的加载过程了,而Spring中使用 getSingleton 的重载方法实现bean的加载过程。
下面我们进入到 DefaultSingletonBeanRegistry # getSingleton() 方法中:
#DefaultSingletonBeanRegistry
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");

    // 全局加锁
    synchronized (this.singletonObjects) {
        // 从缓存中检查对应的bean是否已经加载过一遍
        // 因为 singleton 模式其实就是复用已经创建的 bean 所以这步骤必须检查
        Object singletonObject = this.singletonObjects.get(beanName);
        //  为空,开始加载过程
        if (singletonObject == null) {
            // 省略 部分代码

            // 加载前置处理
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            // 省略代码
            try {
                // 初始化 bean
                // 这个过程就是我上面讲的调用匿名内部类的方法,其实是调用 createBean() 方法
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            // 省略 catch 部分
            }
            finally {
                // 后置处理
                afterSingletonCreation(beanName);
            }
            // 加入缓存中
            if (newSingleton) {
                addSingleton(beanName, singletonObject);
            }
        }
        // 直接返回
        return singletonObject;
    }
}
上述代码中其实使用了 回调方法,使得程序可以在单例创建的前后做一些准备及处理操作,而真正获取单例bean的方法其实并不是在此方法中实现的,其实现逻辑是在ObjectFactory类型的实例singletonFactory中实现的。而这些准备及处理操作包括如下内容:
  1. 从缓存中检查对应的bean是否已经加载过一遍 ;
  2. 如果没有加载,则记录beanName的正在加载状态 ;
  3. 加载单例前记录加载状态。 可能你会觉得 beforeSingletonCreation(beanName) 方法是个空实现,里面没有任何逻辑,但其实这个函数中做了一个很重要的操作:记录加载状态,也就是通过 this.singletonsCurrentlyInCreation.add(beanName) 当前正要创建的bean记录在缓存中,这样便可以对循环依赖进行检测。 在上节已经讲过。
  4. 通过调用参数传入的 ObjectFactory#getObject() 方法实例化bean ;
  5. 加载单例后的处理方法调用。 同步骤3的记录加载状态相似,当bean加载结束后需要调用 afterSingletonCreation(beanName) 移除缓存中对该bean的正在加载状态的记录 ;
  6. 将结果记录至缓存并删除加载bean过程中所记录的各种辅助状态;
  7. 返回处理结果
我们看方法 addSingleton() 方法:
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);
    }
}
一个 put、一个 add、两个 remove。 singletonObjects 是单例 bean 的缓存, singletonFactories 是单例 beanFactory 的缓存, earlySingletonObjects 是“早期”创建的单例 bean 的缓存, registeredSingletons 是已经注册的单例缓存。
从上面步骤4可以看出,bean的加载逻辑其实是在传入的 ObjectFactory 类型的 singletonFactory 中实现的:
if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, () -> {
        try {
            return createBean(beanName, mbd, args);
        }
        catch (BeansException ex) {
            destroySingleton(beanName);
            throw ex;
        }
    });
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
ObjectFactory的核心部分其实只是调用了 createBean(beanName, mbd, args) 方法,所以我们还需要到 createBean(beanName, mbd, args) 中探寻真理。

5.1.5 准备创建bean

AbstractBeanFactory.class
如上所示, createBean() 是真正创建bean的地方,此方法是定义在 AbstractAutowireCapableBeanFactory中,我们看下其源码:
# AbstractAutowireCapableBeanFactory
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {

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

    //锁定class,根据设置的class属性或者根据className来解析Class,确保此时的 bean 已经被解析了
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName); 
    // 如果获取的class 属性不为null,则克隆该 BeanDefinition
    // 主要是因为该动态解析的 class 无法保存到到共享的 BeanDefinition
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    try {
        // 验证和准备覆盖方法
        mbdToUse.prepareMethodOverrides();
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                beanName, "Validation of method overrides failed", ex);
    }

    try {
        // 给 BeanPostProcessors 一个机会用来返回一个代理类而不是真正的类实例
        // AOP 的功能就是基于这个地方
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                "BeanPostProcessor before instantiation of bean failed", ex);
    }

    try {
        // 执行真正创建 bean 的过程
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
        throw ex;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
    }
}
从代码中可以总结出函数完成的具体步骤及功能:
  1. 根据设置的class属性或者根据className来解析Class ;
  2. 对override属性进行标记及验证 ;
  3. 应用初始化前的后处理器,解析指定bean是否存在初始化前的短路操作 ;
  4. 创建bean 。
5.1.5.1 处理override属性
AbstractAutowireCapableBeanFactory.class
查看源码中 AbstractBeanDefinition 类的 prepareMethodOverrides() 方法:
# AbstractBeanDefinition
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
   // Check that lookup methods exist and determine their overloaded status.
   if (hasMethodOverrides()) {
       //获取对应类中方法名的个数
       //如果个数为1时,标记MethodOverride暂未被覆盖,避免参数类型检查的开销
      getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
   }
}

protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
   int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
   if (count == 0) {
      throw new BeanDefinitionValidationException(
            "Invalid method override: no method with name '" + mo.getMethodName() +
            "' on class [" + getBeanClassName() + "]");
   }
   else if (count == 1) {
      // Mark override as not overloaded, to avoid the overhead of arg type checking.
      mo.setOverloaded(false);
   }
}
通过以上两个函数的代码实现了之前反复提到过的,在Spring配置中存在 lookup-method和replace-method两个配置功能,而 这个配置的加载其实就是将配置统一存放在BeanDefinition中的methodOverrides属性中,这两个功能的实现原理其实是在 bean实例化的时候如果检测到存在methodOverrides属性,会 动态地为当前bean生成代理并使用对应的拦截器为bean做增强处理
5.1.5.2 实例化的前置处理
AbstractAutowireCapableBeanFactory.class
resolveBeforeInstantiation() 的作用是给 BeanPostProcessors 后置处理器 返回一个代理对象的机会,其实在调用该方法之前 Spring 一直都没有创建 bean ,那么这里返回一个 bean 的代理类有什么作用呢?作用体现在后面的 if 判断:
if (bean != null) {
    return bean;
}
如果代理对象不为空,则直接返回代理对象,这一步骤有非常重要的作用,Spring 后续实现 AOP 就是基于这个地方判断的。
我们进入 resolveBeforeInstantiation() 来看:
# AbstractAutowireCapableBeanFactory
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}
这个方法核心就在于 applyBeanPostProcessorsBeforeInstantiation()applyBeanPostProcessorsAfterInitialization() 两个方法, before 为实例化前的后处理器应用after 为实例化后的后处理器应用。这两个方法实现非常简单,无非是对后处理器中所有 InstantiationAwareBeanPostProcessor 类型的后处理器进行 postProcessBeforeInstantiation() 方法和 BeanPostProcess #postProcessAfterInitialization() 方法的调用。
# AbstractAutowireCapableBeanFactory
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
   for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
      Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
      if (result != null) {
         return result;
      }
   }
   return null;
}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
      throws BeansException {

   Object result = existingBean;
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
      Object current = processor.postProcessAfterInitialization(result, beanName);
      if (current == null) {
         return result;
      }
      result = current;
   }
   return result;
}
  • applyBeanPostProcessorsBeforeInstantiation() 实例化前的后处理器的应用 :bean的实例化前调用,就是将AbstractBeanDefinition转换为BeanWrapper前的处理,给子类一个修改BeanDefinition的机会,也就是说当程序经过这个方法后,bean可能已经不是我们认识的bean了,而是或许成为了一个经过处理的代理bean,可能通过cglib生成的,也可以是其他技术生成的
  • applyBeanPostProcessorsAfterInitialization() 实例化后的后处理器的应用 :在讲解 '从缓存中获取单例bean' 的时候提到过,Spring中的规则是在bean的初始化后尽可能保证将注册的后处理器的 postProcessAfterInitialization() 方法应用到该bean中,因为如果返回的bean不为空,那么便不会再次经历普通bean的创建过程,所以只能在这里应用后处理器的 postProcessAfterInitialization() 方法。

5.1.6 循环依赖

5.1.6.1 什么是循环依赖
循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。如下图所示:
public class TestA {
    private TestB testB;
}
public class TestB {
    private TestC testC;
}
public class TestC {
    private TestA testA;
}
注意,这里不是函数的循环调用,是对象的相互依赖关系。循环调用其实就是一个死循环,除非有终结条件。
Spring中循环依赖场景有:
  1. 构造器的循环依赖
  2. field属性的循环依赖 (又叫setter循环依赖)。
对于 构造器的循环依赖,Spring 是无法解决的,只能 抛出 BeanCurrentlyInCreationException 异常表示循环依赖,所以下面我们分析的都是 基于 field 属性的循环依赖。Spring 只解决 scope 为 singleton 的循环依赖,对于scope 为 prototype 的 bean Spring 无法解决,直接抛出 BeanCurrentlyInCreationException 异常。
5.1.6.2 如何检测循环依赖
检测循环依赖相对比较容易,Bean在创建的时候可以给该Bean打标,如果 递归调用回来发现正在创建中的话,即说明存在循环依赖了。
也就是上文中提到的三级缓存中的 earlySingletonObjects :,它保存 BeanName和bean的早期引用(bean还在创建过程中)之间的关系。
5.1.6.3 如何解决循环依赖
我们先从加载 bean 最初始的方法 doGetBean() 开始。
在 doGetBean() 中,首先会根据 beanName 从单例 bean 缓存中获取,如果不为空则直接返回。
# AbstractBeanFactory
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}
这个方法主要是从三个缓存中获取,分别是:singletonObjects、earlySingletonObjects、singletonFactories,三者定义如下:
  • singletonObjects : 用于保存BeanName和创建bean实例之间的关系,beanName–>bean Instance
  • earlySingletonObjects : 也是保存BeanName和bean实例之间的关系,与singletonObjects的不同之处在于,在这个Map里的Bean不是完整的,甚至还不能称之为“Bean”,只是一个Instance。即当一个单例bean被放到这里面后,那么当bean还在创建过程中,就可以通过getBean方法获取到了,其目的是用来检测循环引用
  • singletonFactories : 用于保存BeanName和创建bean的工厂之间的关系,banName–>ObjectFactory
他们就是 Spring 解决 singleton bean 的关键因素所在,我称他们为三级缓存, 第一级为 singletonObjects第二级为 earlySingletonObjects第三级为 singletonFactories。这里我们可以通过 getSingleton() 看到他们是如何配合的,这分析该方法之前,提下其中的 isSingletonCurrentlyInCreation()allowEarlyReference
  • isSingletonCurrentlyInCreation()判断当前 singleton bean 是否处于创建中。bean 处于创建中也就是说 bean 在初始化但是没有完成初始化,有一个这样的过程其实和 Spring 解决 bean 循环依赖的理念相辅相成,因为 Spring 解决 singleton bean 的核心就在于提前曝光 bean。
  • allowEarlyReference:从字面意思上面理解就是允许提前拿到引用。其实真正的意思是是否允许从 singletonFactories 缓存中通过 getObject() 拿到对象,为什么会有这样一个字段呢?原因就在于 singletonFactories 才是 Spring 解决 singleton bean 的诀窍所在,这个我们后续分析。
getSingleton() 整个过程如下:
  1. 首先从一级缓存 singletonObjects 获取 ;
  2. 如果没有且当前指定的 beanName 正在创建,就再从二级缓存中 earlySingletonObjects 获取 ;
  3. 如果还是没有获取到且允许从 singletonFactories 通过 getObject() 获取,则从三级缓存 singletonFactories 获取 singletonFactory,
  4. 如果获取到 singletonFactory ,则通过其 getObject() 获取对象,并将其加入到二级缓存 earlySingletonObjects 中 从三级缓存 singletonFactories 删除,这样就从三级缓存升级到二级缓存了。
上面是从缓存中获取,但是缓存中的数据从哪里添加进来的呢?一直往下跟会发现在 AbstractAutowireCapableBeanFactory #doCreateBean() 中,有这么一段代码:
# AbstractAutowireCapableBeanFactory
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
    //.....
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        if (logger.isDebugEnabled()) {
            logger.debug("Eagerly caching bean '" + beanName +
                            "' to allow for resolving potential circular references");
        }
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }
    //.....
}
也就是我们上一篇文章中讲的最后一部分,提前将创建好但还未进行属性赋值的的Bean放入缓存中。
如果 earlySingletonExposure == true 的话,则调用 addSingletonFactory() 将他们添加到缓存中,但是一个 bean 要具备如下条件才会添加至缓存中:
  • 单例
  • 运行提前暴露 bean
  • 当前 bean 正在创建中
addSingletonFactory() 代码如下:
# DefaultSingletonBeanRegistry
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);
        }
    }
}
从这段代码我们可以看出 singletonFactories 这个三级缓存才是解决 Spring Bean 循环依赖的诀窍所在。同时这段代码发生在 createBeanInstance() 方法之后,也就是说这个 bean 其实已经被创建出来了,但是它 还不是很完美(没有进行属性填充和初始化),但是对于其他依赖它的对象而言已经足够了(可以根据 对象引用定位到堆中对象),能够被认出来了,所以 Spring 在这个时候选择将该对象提前曝光出来让大家认识认识。
介绍到这里我们发现三级缓存 singletonFactories 和 二级缓存 earlySingletonObjects 中的值都有出处了,那一级缓存在哪里设置的呢?在类 DefaultSingletonBeanRegistry 中可以发现这个 addSingleton() 方法,源码如下:
# DefaultSingletonBeanRegistry
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);
    }
}
添加至一级缓存,同时从二级、三级缓存中删除。
这个方法在我们创建 bean 的链路中有哪个地方引用呢?其实在 '创建bean' 过程提到过了,在 AbstractBeanFactory #doGetBean() 处理不同 scope 时,如果是 singleton,则调用 getSingleton(),如下:
# AbstractBeanFactory
protected <T> T doGetBean(
      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
      throws BeansException {
    //.....
    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);
    }
    //.....
}
# DefaultSingletonBeanRegistry
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    synchronized (this.singletonObjects) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            //....
            try {
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            //.....
            if (newSingleton) {
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}
至此,Spring 关于 singleton bean 循环依赖已经分析完毕了。所以我们基本上可以确定 Spring 解决循环依赖的方案了:Spring 在创建 bean 的时候并不是等它完全完成,而是在创建过程中 将创建中的 bean 的 ObjectFactory 提前曝光(即加入到 singletonFactories 缓存中),这样一旦下一个 bean 创建的时候需要依赖 bean ,则 直接使用 ObjectFactory 的 getObject() 获取了,也就是 getSingleton() 中的代码片段了。
到这里,关于 Spring 解决 bean 循环依赖就已经分析完毕了。最后来描述下就上面那个循环依赖 Spring 解决的过程:
  1. 首先 A 完成初始化第一步并将自己提前曝光出来(通过 ObjectFactory 将自己提前曝光);
  2. 在A初始化的时候,发现自己依赖对象 B,此时就会去尝试 get(B) ,这个时候发现 B 还没有被创建出来,然后 B 就走创建流程 ;
  3. 在 B 初始化的时候,同样发现自己依赖 C,此时就会去尝试 get(C),C 也没有被创建出来,这个时候 C 又开始初始化进程 ;
  4. 但是在C初始化的过程中,发现自己依赖 A,于是尝试 get(A),这个时候由于 A 已经添加至缓存中(一般都是添加至三级缓存 singletonFactories ),通过 ObjectFactory 提前曝光,所以可以通过 ObjectFactory.getObject() 拿到 A 对象 ;
  5. C 拿到 A 对象后顺利完成初始化,然后将自己添加到一级缓存中,回到 B ,B 也可以拿到 C 对象,完成初始化,A 可以顺利拿到 B 完成初始化。到这里整个链路就已经完成了初始化过程了。

5.1.7 创建bean

AbstractAutowireCapableBeanFactory.class
如果没有代理对象,就只能走常规的路线进行 bean 的创建了,该过程由 doCreateBean() 实现,如下:
# AbstractAutowireCapableBeanFactory
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
        throws BeanCreationException {

    // BeanWrapper是对Bean的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装bean的属性描述器
    BeanWrapper instanceWrapper = null;
    // 单例模型,则从未完成的 FactoryBean 缓存中删除
    if (mbd.isSingleton()) {anceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }

    // 使用合适的实例化策略来创建新的实例:工厂方法、构造函数自动注入、简单初始化
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }

    // 包装的实例对象
    final Object bean = instanceWrapper.getWrappedInstance();
    // 包装的实例对象的类型
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }

    // 检测是否有后置处理
    // 如果有后置处理,则允许后置处理修改 BeanDefinition
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                // applyMergedBeanDefinitionPostProcessors
                // 后置处理修改 BeanDefinition
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Post-processing of merged bean definition failed", ex);
            }
            mbd.postProcessed = true;
        }
    }

    // 解决单例模式的循环依赖
    // 单例模式 & 允许循环依赖&当前单例 bean 是否正在被创建
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
            isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        if (logger.isDebugEnabled()) {
            logger.debug("Eagerly caching bean '" + beanName +
                    "' to allow for resolving potential circular references");
        }
        // 提前将创建的 bean 实例加入到ObjectFactory 中
        // 这里是为了后期避免循环依赖
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    /*
     * 开始初始化 bean 实例对象
     */
    Object exposedObject = bean;
    try {
        // 对 bean 进行填充,将各个属性值注入,其中,可能存在依赖于其他 bean 的属性
        // 则会递归初始依赖 bean
        populateBean(beanName, mbd, instanceWrapper);
        // 调用初始化方法,比如 init-method 
        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) {
        // 获取 earlySingletonReference
        Object earlySingletonReference = getSingleton(beanName, false);
        // 只有在存在循环依赖的情况下,earlySingletonReference 才不会为空
        if (earlySingletonReference != null) {
            // 如果 exposedObject 没有在初始化方法中被改变,也就是没有被增强
            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 " +
                                    "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                }
            }
        }
    }
    try {
        // 注册 DisposeableBean
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }

    return exposedObject;
}
大概流程如下:
  1. 如果是单例则需要首先清除缓存;
  2. createBeanInstance() 实例化 bean,将BeanDefinition转换为BeanWrapper ;
  3. MergedBeanDefinitionPostProcessor的应用,bean合并后的处理,Autowire正是通过此方法实现诸如类型的解析;
  4. 解决单例模式的循环依赖,提前将bean 的 ObjectFactory 提前曝光(即加入到 singletonFactories 缓存中),这里是为了后期避免循环依赖
  5. populateBean() 属性填充 ;
  6. initializeBean() 初始化 bean ;
  7. 循环依赖检查,之前提到过,在Spring中解决循环依赖只对单例有效,而对于prototype的bean,Spring没有好的解决办法,唯一做的就是抛出异常,在这个步骤里面会检测已经加载的bean是否已经出现了依赖循环,并判断是否需要抛出异常。
  8. 注册DisposeableBean,如果配置了destroy-method,这里需要注册以便于在销毁时候调用 ;
  9. 完成创建并返回。
5.1.7.1 createBeanInstance() 方法——创建bean实例
AbstractAutowireCapableBeanFactory.class
我们首先从 createBeanInstance() 方法开始( 工厂方法、构造函数自动注入)。方法代码如下:
# AbstractAutowireCapableBeanFactory
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // 解析 bean,将 bean 类名解析为 class 引用
    Class<?> beanClass = resolveBeanClass(mbd, beanName);

    if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
    }

    // 如果存在 Supplier 回调,则使用给定的回调方法初始化策略
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }

    // 如果工厂方法不为空,则使用工厂方法初始化策略,这里推荐看Factory-Method实例化Bean
    if (mbd.getFactoryMethodName() != null)  {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        // constructorArgumentLock 构造函数的常用锁
        synchronized (mbd.constructorArgumentLock) {
            // 如果已缓存的解析的构造函数或者工厂方法不为空,则可以利用构造函数解析
            // 因为需要根据参数确认到底使用哪个构造函数,该过程比较消耗性能,所以采用缓存机制
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }
    // 已经解析好了,直接注入即可
    if (resolved) {
        // 自动注入,调用构造函数自动注入
        if (autowireNecessary) {
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            // 使用默认构造函数构造
            return instantiateBean(beanName, mbd);
        }
    }

    // 确定解析的构造函数
    // 主要是检查已经注册的 SmartInstantiationAwareBeanPostProcessor
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null ||
            mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
        // 构造函数自动注入
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    //使用默认构造函数注入
    return instantiateBean(beanName, mbd);
}
实例化 bean 是一个复杂的过程,其主要的逻辑为:
  1. 如果存在 Supplier 回调,则调用 obtainFromSupplier() 进行初始化 ;
  2. 如果存在工厂方法,则使用工厂方法进行实例化 ;
  3. 解析构造函数并进行构造函数的实例化 :因为一个bean对应的类中可能会有多个构造函数,每个构造函数的参数不同,Spring会根据参数及类型去判断最终会使用哪个构造函数进行实例化。但是,判断的过程是个比较消耗性能的步骤,所以采用缓存机制,如果已经解析过则不需要重复解析,而是直接从 RootBeanDefinition 的属性 resolvedConstructorOrFactoryMethod 缓存的值去取,否则需要再次解析,并将解析的结果添加至 RootBeanDefinition 的属性 resolvedConstructorOrFactoryMethod 中 。
    1. 首先判断缓存,如果缓存中存在,即已经解析过了,则直接使用已经解析了的,根据 constructorArgumentsResolved 参数判断是使用构造函数自动注入还是默认构造函数注入 ;
    2. 如果缓存中没有,则需要先确定到底使用哪个构造函数来完成解析工作,因为一个类有多个构造函数,每个构造函数都有不同的构造参数,所以需要根据参数来锁定构造函数并完成初始化,如果存在参数则使用相应的带有参数的构造函数,否则使用默认构造函数。

(1)autowireConstructor()_带参构造函数的实例化

对于实例的创建Spring中分为两种情况,一种是 通用的实例化,另一种是 带有参数的实例化。带有参数的实例化过程相当复杂,因为存在着不确定性,所以在判断对应参数上做了大量的工作。
# ConstructorResolver
public BeanWrapper autowireConstructor(final String beanName,final RootBeanDefinition mbd,Constructor [] chosenCtors,final Object [] explicitArgs)
// explicitArgs通过getBean方法传入,如果getBean方法调用的时候指定方法参数那么直接使用
// 如果getBean方法时候没有指定则尝试从配置文件中解析
// 尝试从缓存中获取
// 配置的构造函数参数
// 如果缓存中存在
// 解析参数类型,缓存中的值可能是原始值也可能是最终值
// 如果没有缓存
// 提取配置文件中的配置的构造函数参数
// 用于承载解析后的构造函数参数的值
// 能解析到的参数个数
// 排序给定的构造函数,public构造函数优先参数数量降序,非public构造函数参数数量降序
// 如果已找到选用的构造函数或者需要参数个数小于当前构造函数参数给则终止,以为已经按照参数个数降序排列
// 有参数则根据构造对应参数类型的参数
// 注释上获取参数名称
// 获取参数名探索器
// 获取指定构造函数的参数名称
// 根据名称和数据类型创建参数持有者
// 构造函数没有参数的情况
// 探测是否有不确定性的构造函数存在,例如不同构造函数的参数为父子关系
// 将解析的构造函数加入缓存
// 将构造的实例加入BeanWrapper
}
总览一下整个函数,其实现的功能考虑了一下几个方面:
  • 构造函数参数确定
    • 1.1 根据explicitArgs参数判断,如果传入的explicitArgs参数不为空,那便可以直接确认参数,因为explicitArgs参数是在调用Bean的时候用户指定的,在BeanFactory类中存在这样的方法:Object getBean(String name,Object … args) throws BeanException ;在获取bean的时候,用户不但可以指定bean的名称还可以指定bean所对应类的构造函数或者工厂方法的方法参数,主要用于静态工厂方法的调用,而这里需要给定完全匹配的参数的,所以,便可以判断,如果传入参数explicitArgs不为空,则可以确定构造函数参数就是它。
    • 1.2 缓存中获取,除此之外,确定参数的办法如果之前已经分析过,也就是说构造函数已经记录在缓存中,那么便可以直接拿来使用。而且,这里要提到的是,在缓存中缓存的可能是参数的最终类型也可能是参数的初始类型。
    • 1.3 配置文件获取,如果不能根据传入参数explicitArgs确认构造函数的参数也无法在缓存中得到相关信息,那么只能进行新一轮的分析了。分析从配置文件的构造韩式信息开始,经过之前的分析,Spring配置文件中的信息经过转换会通过BeanDefinition实例承载,也就是参数mbd中包含,那么可以通过调用mbd.getConstructorArgumentValues()来获取配置的构造函数信息。有了配置中的信息便可以获取对应的参数值信息了,获取参数值的信息包括指定值,如:直接指定构造函数中某个值为原始类型String类型,或者是一个对其他bean的引用,而这一处理委托给了resolveConstructorArgments方法,并返回能解析到的参数的个数。
  • 构造函数的确定:经过第一步后已经确定了构造函数的参数,接下来的任务就是根据构造函数参数在所有的构造函数中锁定对应的构造函数,而且匹配的方法就是根据参数个数匹配,所以在匹配之前需要对构造函数按照public构造函数优先参数数量降序,非public构造函数参数数量降序。这样可以在遍历的情况下迅速判断排在后面的构造函数参数个数是否符合条件,由于在配置文件中并不是唯一限制使用参数位置索引的方式去创建,同样还支持指定参数名称进行设定参数值的情况,那么这种情况就需要首先确定构造函数中的参数名称,获取参数名称可以有两种方式,一种是通过注解的方式直接获取,另一种方式就是使用Spring提供的工具类ParameterNameDiscoverer来获取,构造函数、参数名称、参数类型、参数值、确定后就可以锁定构造函数以及转换对应的参数类型了。
  • 根据确定的构造函数转换对应的参数类型,主要是使用Spring中提供的类型转换器或者用户自定义的类型转换器进行转换。
  • 构造函数不确定性的验证,当然,有时候及时构造函数、参数名称、参数类型、参数值都确定后也不一定会直接锁定构造函数,不同构造函数的参数为父子关系,所以Spring在最后又做了一次验证。
  • 根据实例化策略以及得到的构造函数及构造函数参数实例化Bean

(2)instantiateBean()_默认构造函数的实例化

不带参数的构造函数的实例化过程使用的是 instantiateBean() ,我们跟进到 instantiateBean() 方法,源码如下:
# AbstractAutowireCapableBeanFactory
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
   try {
      Object beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
      BeanWrapper bw = new BeanWrapperImpl(beanInstance);
      initBeanWrapper(bw);
      return bw;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
   }
}
实例化过程中,反复提到了 实例化策略,这是做什么的呢?其实,经过前面的分析,我们已经得到了足以实例化的相关信息,完全可以使用最简单的反射方法来构造实例对象,但Spring却没有这么做。
接下来我们跟进到 Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) 方法,具体的实现是在 SimpleInstantiationStrategy中,具体代码如下:
# SimpleInstantiationStrategy
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    // 没有覆盖
    // 直接使用反射实例化即可
    if (!bd.hasMethodOverrides()) {
        // 重新检测获取下构造函数
        // 该构造函数是经过前面 N 多复杂过程确认的构造函数
        Constructor<?> constructorToUse;
        synchronized (bd.constructorArgumentLock) {
            // 获取已经解析的构造函数
            constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
            // 如果为 null,从 class 中解析获取,并设置
            if (constructorToUse == null) {
                final Class<?> clazz = bd.getBeanClass();
                if (clazz.isInterface()) {
                    throw new BeanInstantiationException(clazz, "Specified class is an interface");
                }
                try {
                    if (System.getSecurityManager() != null) {
                        constructorToUse = AccessController.doPrivileged(
                                (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
                    }
                    else {
                        //利用反射获取构造器
                        constructorToUse =  clazz.getDeclaredConstructor();
                    }
                    bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                }
                catch (Throwable ex) {
                    throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                }
            }
        }
        // 通过BeanUtils直接使用构造器对象实例化bean
        return BeanUtils.instantiateClass(constructorToUse);
    }
    else {
        // 生成CGLIB创建的子类对象
        return instantiateWithMethodInjection(bd, beanName, owner);
    }
}
流程如下:
  • 如果该 bean 没有配置 lookup-method、replaced-method 标签或者 @Lookup 注解,则直接通过反射的方式实例化 bean 即可 ;
  • 但是如果存在需要覆盖的方法或者动态替换的方法则需要使用 CGLIB 进行动态代理,因为可以在创建代理的同时将动态方法织入类中。
调用工具类 BeanUtilsinstantiateClass() 方法完成反射工作:
# BeanUtils
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
    Assert.notNull(ctor, "Constructor must not be null");
    try {
        ReflectionUtils.makeAccessible(ctor);
        return (KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
                KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
    }
    // 省略一些 catch 
}
CGLIB 动态代理 :
# SimpleInstantiationStrategy
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    throw new UnsupportedOperationException("Method Injection not supported in SimpleInstantiationStrategy");
}
方法默认是没有实现的,具体过程由其子类 CglibSubclassingInstantiationStrategy 实现:
# CglibSubclassingInstantiationStrategy
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    return instantiateWithMethodInjection(bd, beanName, owner, null);
}

protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
        @Nullable Constructor<?> ctor, @Nullable Object... args) {

    // 通过CGLIB生成一个子类对象
    return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
}
创建一个 CglibSubclassCreator 对象,调用其 instantiate() 方法生成其子类对象:
public Object instantiate(@Nullable Constructor<?> ctor, @Nullable Object... args) {
    // 通过 Cglib 创建一个代理类
    Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
    Object instance;
    // 没有构造器,通过 BeanUtils 使用默认构造器创建一个bean实例
    if (ctor == null) {
        instance = BeanUtils.instantiateClass(subclass);
    }
    else {
        try {
            // 获取代理类对应的构造器对象,并实例化 bean
            Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
            instance = enhancedSubclassConstructor.newInstance(args);
        }
        catch (Exception ex) {
            throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
                    "Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
        }
    }

    // 为了避免memory leaks异常,直接在bean实例上设置回调对象
    Factory factory = (Factory) instance;
    factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
            new CglibSubclassingInstantiationStrategy.LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
            new CglibSubclassingInstantiationStrategy.ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
    return instance;
}
当然这里还没有具体分析 CGLIB 生成子类的详细过程,具体的过程等后续分析 AOP 的时候再详细地介绍。
5.1.7.2 记录创建bean的ObjectFactory
AbstractAutowireCapableBeanFactory.class
在刚刚创建完Bean的实例后,也就是刚刚执行完 createBeanInstance(beanName, mbd, args) 方法进行构造器实例化后,doCreateBean方法中有下面一段代码:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
       throws BeanCreationException {
    //......
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
            isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        if (logger.isDebugEnabled()) {
            logger.debug("Eagerly caching bean '" + beanName +
                    "' to allow for resolving potential circular references");
        }
        //为避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂  
        //依赖处理:在Spring中会有循环依赖的情况,例如,当A中含有B的属性,而B中又含有A的属性时就会  
        //构成一个循环依赖,此时如果A和B都是单例,那么在Spring中的处理方式就是当创建B的时候,涉及  
        //自动注入A的步骤时,并不是直接去再次创建A,而是通过放入缓存中的ObjectFactory来创建实例,  
        //这样就解决了循环依赖的问题。
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }
    //......
}

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);
       }
    }
}
  • earlySingletonExposure:从字面的意思就是提早曝光的单例。需要确认有哪些条件影响这个值;
  • mbd.isSingleton():是否是单例;
  • this.allowCirularReference:是否允许循环依赖,在配置文件中并没有找到如何配置,但是在AbstractRefreshableApplicationContext中提供了设置函数,可以通过硬编码的方法进行设置或者通过自定义名称空间进行设置;
  • isSingletonCurrentlyInCreation(beanName):该bean是否在创建中。在Spring中,会有个专门的属性默认为DefaultSingletonBeanRegistrysingletonsCurrentlyInCreation来记录bean的加载状态,在bean开始创建前会将beanName记录在属性中,在bean创建结束后会将beanName移除。那么我们跟随代码一路走下来可以对这个属性的记录并没有多少印象,这个状态是在哪里记录的呢?不同scope的记录位置不一样,我们以singleton为例,在singleton下记录属性的函数是在DefaultSingletonBeanRegistry类的 public Object getSingleton(String beanName,ObjectFactory singletonFactory) 函数的beforeSingletonCreation(beanName)afterSingletonCreation(beanName)中,在这两段函数中分别this.singletonsCurrentlyInCreation.add(beanName)this.singletonsCurrentlyInCreation.remove(beanName)来进行状态的记录与移除
变量 earlySingletonExposure 为是否是单例,是否允许循环依赖,是否对应的bean正在创建的条件的综合。当这3个条件都满足时会执行 addSingletonFactory() 操作,那么加入 SingletonFactory的作用是什么?又是在什么时候调用的?
我们还是以最简单AB循环为例,类A中含有属性B,而类B中又会含有属性A,那么 初始化beanA的过程如下:

上图展示了创建BeanA的流程,在创建A的时候首先会记录类A所对应额beanName,并将beanA的创建工厂加入缓存中,而在对A的属性填充也就是调用 pupulateBean() 方法的时候又会再一次的对B进行递归创建。同样的,因为在B中同样存在A属性,因此在实例化B的 populateBean() 方法中又会再次地初始化B,也就是图形的最后,调用 getBean(A) 。关键是在这里,我们之前分析过,在这个函数中并不是直接去实例化A,而是先去检测缓存中是否有已经创建好的对应的bean,或者是否已经创建的 ObjectFactory,而此时对于A的ObjectFactory我们早已经创建,所以便不会再去向后执行,而是直接调用ObjectFactory去创建A 。这里最关键的是ObjectFactory的实现。
其中 getEarlyBeanReference() 的代码如下:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {  
    Object exposedObject = bean;  
    if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {  
        for (BeanPostProcessor bp : getBeanPostProcessors()) {  
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {  
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;  
                exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);  
                if (exposedObject == null) {  
                    return exposedObject;  
                }  
            }  
        }  
    }  
    return exposedObject;  
}
getEarlyBeanReference() 函数中除了 后处理的调用外没有别的处理工作,根据分析,基本可以理清Spring处理循环依赖的解决办法,在B中创建依赖A时通过ObjectFactory提供的实例化方法来获取原始A,使B中持有的A仅仅是刚刚初始化并没有填充任何属性的A,而这初始化A的步骤还是刚刚创建A时进行的,但是因为A与B中的A所表示的属性地址是一样的所以在A中创建好的属性填充自然可以通过B中的A获取,这样就解决了循环依赖的问题。
5.1.7.3 populateBean() 方法——属性注入
AbstractAutowireCapableBeanFactory.class
其次我们来看 populateBean() 方法,源码如下:
# AbstractAutowireCapableBeanFactory
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {  
    PropertyValues pvs = mbd.getPropertyValues();  

    if (bw == null) {  
        if (!pvs.isEmpty()) {  
            throw new BeanCreationException(  
                    mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");  
        }  
        else {  
            // Skip property population phase for null instance.  
            return;  
        }  
    }  

    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the  
    // state of the bean before properties are set. This can be used, for example,  
    // to support styles of field injection.  
    boolean continueWithPropertyPopulation = true;  

    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {  
        for (BeanPostProcessor bp : getBeanPostProcessors()) {  
            if (bp instanceof InstantiationAwareBeanPostProcessor) {  
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;  
                //返回值为是否继续填充bean  
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {  
                    continueWithPropertyPopulation = false;  
                    break;  
                }  
            }  
        }  
    }  
    //如果后处理器发出停止填充命令则终止后续的执行  
    if (!continueWithPropertyPopulation) {  
        return;  
    }  

    if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||  
            mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {  
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);  

        // Add property values based on autowire by name if applicable.  
        //根据名称自动注入  
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {  
            autowireByName(beanName, mbd, bw, newPvs);  
        }  

        // Add property values based on autowire by type if applicable.  
        //根据类型自动注入  
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {  
            autowireByType(beanName, mbd, bw, newPvs);  
        }  

        pvs = newPvs;  
    }  
    //后处理器已经初始化  
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();  
    //需要依赖检查  
    boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);  

    if (hasInstAwareBpps || needsDepCheck) {  
        PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);  
        if (hasInstAwareBpps) {  
            for (BeanPostProcessor bp : getBeanPostProcessors()) {  
                if (bp instanceof InstantiationAwareBeanPostProcessor) {  
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;  
                    //对所有需要依赖检查的属性进行后处理  
                    pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);  
                    if (pvs == null) {  
                        return;  
                    }  
                }  
            }  
        }  
        if (needsDepCheck) {  
            //依赖检查,对应depends-on属性,3.0已经弃用此属性  
            checkDependencies(beanName, mbd, filteredPds, pvs);  
        }  
    }  
    //将属性应用到bean中  
    //将所有ProtertyValues中的属性填充至BeanWrapper中。  
    applyPropertyValues(beanName, mbd, bw, pvs);  
}
我们详细分析下populateBean的流程:
(1)首先进行 属性是否为空的判断 ;
(2)通过调用 InstantiationAwareBeanPostProcessor postProcessAfterInstantiation(bw.getWrappedInstance(), beanName) 方法来控制程序是否继续进行属性填充 ;
(3)根据注入类型(byName/byType)提取依赖的bean,并统一存入 AbstractAutowireCapableBeanFactory #PropertyValues 中 ;
(4)应用 InstantiationAwareBeanPostProcessorpostProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName) 方法,对属性获取完毕填充前的再次处理,典型的应用是 RequiredAnnotationBeanPostProcesser类中对属性的验证 ;
(5)调用 applyPropertyValues() 方法,将所有的 AbstractAutowireCapableBeanFactory #PropertyValues中的属性填充至 BeanWrapper中 。
上面步骤中有几个地方是我们比较感兴趣的,它们分别是依赖注入(autowireByName/autowireByType)以及属性填充,接下来进一步分析这几个功能的实现细节。
Spring 会根据注入类型( byName / byType )的不同,调用不同的方法(autowireByName() / autowireByType())来注入属性值。
(1)autowireByName()——根据名称注入
上文提到根据注入类型( byName / byType )的不同,调用不同的方法(autowireByName() / autowireByType()),提取依赖的bean,并统一存入 AbstractAutowireCapableBeanFactory #PropertyValues 中。
# AbstractAutowireCapableBeanFactory
protected void autowireByName(
        String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

    // 寻找bw中需要依赖注入的属性(Bean 对象中非简单属性)
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
        // 如果容器中包含指定名称的 bean,则将该 bean 注入到 bean中
        if (containsBean(propertyName)) {
            // 递归初始化相关 bean
            Object bean = getBean(propertyName);
            // 为指定名称的属性赋予属性值  
            pvs.add(propertyName, bean);
            // 属性依赖注入
            registerDependentBean(propertyName, beanName);
            if (logger.isDebugEnabled()) {
                logger.debug("Added autowiring by name from bean name '" + beanName +
                        "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
            }
        }
        else {
            if (logger.isTraceEnabled()) {
                logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
                        "' by name: no matching bean found");
            }
        }
    }
}
该方法逻辑很简单,获取该 bean 的非简单属性,什么叫做非简单属性呢?就是 类型为对象类型的属性,但是这里并不是将所有的对象类型都都会找到,比如 8 个原始类型,String 类型 ,Number类型、Date类型、URL类型、URI类型等都会被忽略,如下:
# AbstractAutowireCapableBeanFactory
protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
    Set<String> result = new TreeSet<>();
    PropertyValues pvs = mbd.getPropertyValues();
    PropertyDescriptor[] pds = bw.getPropertyDescriptors();
    for (PropertyDescriptor pd : pds) {
        if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
                !BeanUtils.isSimpleProperty(pd.getPropertyType())) {
            result.add(pd.getName());
        }
    }
    return StringUtils.toStringArray(result);
}
这里获取的就是 需要依赖注入的属性
autowireByName()函数的功能就是根据传入的参数中的 propertyValues中找出已经加载的bean,并递归实例化,然后加入到pvs中。
(2)autowireByType()——根据类型注入
autowireByType() 与 autowireByName() 对于我们理解与使用来说复杂程度相似,但是实现功能的复杂度却不一样,我们看下方法代码:
# AbstractAutowireCapableBeanFactory
protected void autowireByType(  
        String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {  

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

    Set<String> autowiredBeanNames = new LinkedHashSet<String>(4);  
    //寻找bw中需要依赖注入的属性  
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);  
    for (String propertyName : propertyNames) {  
        try {  
            PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);  
            // Don't try autowiring by type for type Object: never makes sense,  
            // even if it technically is a unsatisfied, non-simple property.  
            if (!Object.class.equals(pd.getPropertyType())) {  
                //探测指定属性的set方法  
                MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);  
                // Do not allow eager init for type matching in case of a prioritized post-processor.  
                boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass());  
                DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);  
                //解析指定beanName的属性所匹配的值,并把解析到的属性名称存储在autowiredBeanNames中,  
                Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);  
                if (autowiredArgument != null) {  
                    pvs.add(propertyName, autowiredArgument);  
                }  
                for (String autowiredBeanName : autowiredBeanNames) {  
                    //注册依赖  
                    registerDependentBean(autowiredBeanName, beanName);  
                    if (logger.isDebugEnabled()) {  
                        logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +  
                                propertyName + "' to bean named '" + autowiredBeanName + "'");  
                    }  
                }  
                autowiredBeanNames.clear();  
            }  
        }  
        catch (BeansException ex) {  
            throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);  
        }  
    }  
}
根据名称第一步与根据类型第一步都是寻找bw中需要依赖注入的属性,然后遍历这些属性并寻找类型匹配的bean,其中最复杂就是寻找类型匹配的bean。
spring中提供了 对集合类型的注入支持,如使用如下注解方式:
@Autowired
private List<Test> tests;
这种方式spring会把所有与Test匹配的类型找出来并注入到tests属性中,正是由于这一因素,所以在autowireByType函数,新建了局部遍历 autowireBeanNames,用于存储所有依赖的bean,如果 只是对非集合类的属性注入来说,此属性并无用处
对于寻找类型匹配的逻辑实现是封装在了resolveDependency函数中,其实现如下:
# DefaultListableBeanFactory
public Object resolveDependency(DependencyDescriptor descriptor, String beanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
    descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());  
    if (descriptor.getDependencyType().equals(ObjectFactory.class)) {  
        //ObjectFactory类注入的特殊处理  
        return new DependencyObjectFactory(descriptor, beanName);  
    }  
    else if (descriptor.getDependencyType().equals(javaxInjectProviderClass)) {  
        //javaxInjectProviderClass类注入的特殊处理  
        return new DependencyProviderFactory().createDependencyProvider(descriptor, beanName);  
    }  
    else {  
        //通用处理逻辑  
        return doResolveDependency(descriptor, descriptor.getDependencyType(), beanName, autowiredBeanNames, typeConverter);  
    }  
}  

protected Object doResolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName,  
        Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {  
    /* 
     * 用于支持Spring中新增的注解@Value 
     */  
    Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);  
    if (value != null) {  
        if (value instanceof String) {  
            String strVal = resolveEmbeddedValue((String) value);  
            BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);  
            value = evaluateBeanDefinitionString(strVal, bd);  
        }  
        TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());  
        return (descriptor.getField() != null ?  
                converter.convertIfNecessary(value, type, descriptor.getField()) :  
                converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));  
    }  
    //如果解析器没有成功解析,则需要考虑各种情况  
    //属性是数组类型  
    if (type.isArray()) {  
        Class<?> componentType = type.getComponentType();  
        //根据属性类型找到beanFactory中所有类型的匹配bean,  
        //返回值的构成为:key=匹配的beanName,value=beanName对应的实例化后的bean(通过getBean(beanName)返回)  
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType, descriptor);  
        if (matchingBeans.isEmpty()) {  
            //如果autowire的require属性为true而找到的匹配项却为空则只能抛出异常  
            if (descriptor.isRequired()) {  
                raiseNoSuchBeanDefinitionException(componentType, "array of " + componentType.getName(), descriptor);  
            }  
            return null;  
        }  
        if (autowiredBeanNames != null) {  
            autowiredBeanNames.addAll(matchingBeans.keySet());  
        }  
        TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());  
        //通过转换器将bean的值转换为对应的type类型  
        return converter.convertIfNecessary(matchingBeans.values(), type);  
    }  
    //属性是Collection类型  
    else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {  
        Class<?> elementType = descriptor.getCollectionType();  
        if (elementType == null) {  
            if (descriptor.isRequired()) {  
                throw new FatalBeanException("No element type declared for collection [" + type.getName() + "]");  
            }  
            return null;  
        }  
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType, descriptor);  
        if (matchingBeans.isEmpty()) {  
            if (descriptor.isRequired()) {  
                raiseNoSuchBeanDefinitionException(elementType, "collection of " + elementType.getName(), descriptor);  
            }  
            return null;  
        }  
        if (autowiredBeanNames != null) {  
            autowiredBeanNames.addAll(matchingBeans.keySet());  
        }  
        TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());  
        return converter.convertIfNecessary(matchingBeans.values(), type);  
    }  
    //属性是Map类型  
    else if (Map.class.isAssignableFrom(type) && type.isInterface()) {  
        Class<?> keyType = descriptor.getMapKeyType();  
        if (keyType == null || !String.class.isAssignableFrom(keyType)) {  
            if (descriptor.isRequired()) {  
                throw new FatalBeanException("Key type [" + keyType + "] of map [" + type.getName() +  
                        "] must be assignable to [java.lang.String]");  
            }  
            return null;  
        }  
        Class<?> valueType = descriptor.getMapValueType();  
        if (valueType == null) {  
            if (descriptor.isRequired()) {  
                throw new FatalBeanException("No value type declared for map [" + type.getName() + "]");  
            }  
            return null;  
        }  
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, descriptor);  
        if (matchingBeans.isEmpty()) {  
            if (descriptor.isRequired()) {  
                raiseNoSuchBeanDefinitionException(valueType, "map with value type " + valueType.getName(), descriptor);  
            }  
            return null;  
        }  
        if (autowiredBeanNames != null) {  
            autowiredBeanNames.addAll(matchingBeans.keySet());  
        }  
        return matchingBeans;  
    }  
    else {  
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);  
        if (matchingBeans.isEmpty()) {  
            if (descriptor.isRequired()) {  
                raiseNoSuchBeanDefinitionException(type, "", descriptor);  
            }  
            return null;  
        }  
        if (matchingBeans.size() > 1) {  
            String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor);  
            if (primaryBeanName == null) {  
                throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());  
            }  
            if (autowiredBeanNames != null) {  
                autowiredBeanNames.add(primaryBeanName);  
            }  
            return matchingBeans.get(primaryBeanName);  
        }  
        // We have exactly one match.  
        Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();  
        if (autowiredBeanNames != null) {  
            autowiredBeanNames.add(entry.getKey());  
        }  
        //已经确定只有一个匹配项  
        return entry.getValue();  
    }  
}

protected Map<String, Object> findAutowireCandidates(
        @Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
    //在BeanFactory找到所有Type类型的beanName
    String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
            this, requiredType, true, descriptor.isEager());
    Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);

    //遍历所有的beanName,通过getBean获取
    for (String candidate : candidateNames) {
        if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
            //
            addCandidateEntry(result, candidate, descriptor, requiredType);
        }
    }
    return result;
}

private void addCandidateEntry(Map<String, Object> candidates, String candidateName,
        DependencyDescriptor descriptor, Class<?> requiredType) {

    Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
    if (!(beanInstance instanceof NullBean)) {
        candidates.put(candidateName, beanInstance);
    }
}

public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
        throws BeansException {
    //通过类型找到beanName,然后再找到其实例
    return beanFactory.getBean(beanName);
}
主要就是通过Type从BeanFactory中找到对应的benaName,然后通过 getBean() 获取实例。
(3)applyPropertyValues()——属性填充
程序运行到这里,已经 完成了对所有注入属性的获取,但是获取的属性是以 PropertyValues形式存在的, 还并没有应用到已经实例化的bean中,这一工作是在 applyPropertyValues() 中。继续跟踪到方法体中:
# AbstractAutowireCapableBeanFactory
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {  
    if (pvs == null || pvs.isEmpty()) {  
        return;  
    }  

    MutablePropertyValues mpvs = null;  
    List<PropertyValue> original;  

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

    if (pvs instanceof MutablePropertyValues) {  
        mpvs = (MutablePropertyValues) pvs;  
        //如果mpvs中的值已经被转换为对应的类型那么可以直接设置到beanwapper中  
        if (mpvs.isConverted()) {  
            // Shortcut: use the pre-converted values as-is.  
            try {  
                bw.setPropertyValues(mpvs);  
                return;  
            }  
            catch (BeansException ex) {  
                throw new BeanCreationException(  
                        mbd.getResourceDescription(), beanName, "Error setting property values", ex);  
            }  
        }  
        original = mpvs.getPropertyValueList();  
    }  
    else {  
        //如果pvs并不是使用MutablePropertyValues封装的类型,那么直接使用原始的属性获取方法  
        original = Arrays.asList(pvs.getPropertyValues());  
    }  

    TypeConverter converter = getCustomTypeConverter();  
    if (converter == null) {  
        converter = bw;  
    }  
    //获取对应的解析器  
    BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);  

    // Create a deep copy, resolving any references for values.  
    List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());  
    boolean resolveNecessary = false;  
    //遍历属性,将属性转换为对应类的对应属性的类型  
    for (PropertyValue pv : original) {  
        if (pv.isConverted()) {  
            deepCopy.add(pv);  
        }  
        else {  
            String propertyName = pv.getName();  
            Object originalValue = pv.getValue();  
            Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);  
            Object convertedValue = resolvedValue;  
            boolean convertible = bw.isWritableProperty(propertyName) &&  
                    !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);  
            if (convertible) {  
                convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);  
            }  
            // Possibly store converted value in merged bean definition,  
            // in order to avoid re-conversion for every created bean instance.  
            if (resolvedValue == originalValue) {  
                if (convertible) {  
                    pv.setConvertedValue(convertedValue);  
                }  
                deepCopy.add(pv);  
            }  
            else if (convertible && originalValue instanceof TypedStringValue &&  
                    !((TypedStringValue) originalValue).isDynamic() &&  
                    !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {  
                pv.setConvertedValue(convertedValue);  
                deepCopy.add(pv);  
            }  
            else {  
                resolveNecessary = true;  
                deepCopy.add(new PropertyValue(pv, convertedValue));  
            }  
        }  
    }  
    if (mpvs != null && !resolveNecessary) {  
        mpvs.setConverted();  
    }  

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

我们来看看具体的属性赋值过程:
public class MyTestBean {
    private String name ;

    public MyTestBean(String name) {
        this.name = name;
    }

    public MyTestBean() {
    }
    //...get set方法
}

<bean id="myTestBean"  class="chenhao.spring01.MyTestBean">
        <property name="name" value="chenhao"></property>
</bean>
如上 bw.setPropertyValues 最终都会走到如下方法:
@Override
public void setValue(final @Nullable Object value) throws Exception {
    //获取writeMethod,也就是我们MyTestBean的setName方法
    final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
            ((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :
            this.pd.getWriteMethod());
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            ReflectionUtils.makeAccessible(writeMethod);
            return null;
        });
        try {
            AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
                    writeMethod.invoke(getWrappedInstance(), value), acc);
        }
        catch (PrivilegedActionException ex) {
            throw ex.getException();
        }
    }
    else {
        ReflectionUtils.makeAccessible(writeMethod);
        //通过反射调用方法进行赋值
        writeMethod.invoke(getWrappedInstance(), value);
    }
}
Debug如下:
就是利用反射进行调用对象的set方法赋值。
至此,doCreateBean() 第二个过程:populateBean()属性填充 已经分析完成了,下面分析第三个过程:循环依赖的处理,其实循环依赖并不仅仅只是在 doCreateBean() 中处理,其实在整个加载 bean 的过程中都有涉及,所以下篇内容并不仅仅只局限于 doCreateBean() 。
5.1.7.4 initializeBean()方法——初始化bean
在 populateBean() 方法下面有一个initializeBean(beanName, exposedObject, mbd)方法,这个就是用来执行用户设定的初始化操作。
我们看下方法体:
# AbstractAutowireCapableBeanFactory
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            // 激活 Aware 方法
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        // 对特殊的 bean 处理:Aware、BeanClassLoaderAware、BeanFactoryAware
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        // 后处理器
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        // 激活用户自定义的 init 方法
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        // 后处理器
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
}
初始化 bean 的方法其实就是三个步骤的处理,而这三个步骤主要还是根据用户设定的来进行初始化,这三个过程为:
  1. 激活 Aware 方法;
  2. 后置处理器的应用;
  3. 激活自定义的 init 方法。
(1)invokeAwareMethods(beanName, bean)——激活 Aware 方法
我们先了解一下Aware方法的使用。Spring中提供了一些Aware接口,比如 BeanFactoryAwareApplicationContextAwareResourceLoaderAwareServletContextAware 等,实现这些Aware接口的bean在被初始化后,可以取得一些相对应的资源,例如实现 BeanFactoryAware的bean在初始化之后,Spring容器将会注入BeanFactory实例,而 实现ApplicationContextAware的bean,在bean被初始化后,将会被注入ApplicationContext实例等。我们先通过示例方法了解下Aware的使用。
定义普通bean,如下代码:
public class HelloBean {
    public void say()
    {
        System.out.println("Hello");
    }
}

//定义实现BeanFactoryAware的bean
public class MyBeanAware implements BeanFactoryAware {
    private BeanFactory beanFactory;
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
    public void testAware()
    {
        //通过hello这个bean id从beanFactory获取实例  
        HelloBean hello = (HelloBean)beanFactory.getBean("hello");
        hello.say();
    }
}

//applicationContext.xml 配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myBeanAware" class="com.chenhao.spring.MyBeanAware">
    </bean>
    <bean id="hello" class="com.chenhao.spring.HelloBean">
    </bean>
</beans>

//测试
public class Test {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        MyBeanAware test = (MyBeanAware)ctx.getBean("myBeanAware");
        test.testAware();
    }
}

//输出
hello
上面的方法我们获取到Spring中BeanFactory,并且可以根据BeanFactory获取所有的bean,以及进行相关设置。
还有其他Aware的使用都是大同小异,看一下 invokeAwareMethods(beanName, bean) 方法的源码:
# AbstractAutowireCapableBeanFactory
private void invokeAwareMethods(final String beanName, final Object bean) {  
    if (bean instanceof Aware) {  
        if (bean instanceof BeanNameAware) {  
            ((BeanNameAware) bean).setBeanName(beanName);  
        }  
        if (bean instanceof BeanClassLoaderAware) {  
            ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());  
        }  
        if (bean instanceof BeanFactoryAware) {  
            ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);  
        }  
    }
}
(2)applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)——处理器的应用
BeanPostPrecessor我们经常看到Spring中使用,这是Spring开放式架构的一个必不可少的亮点,给用户充足的权限去更改或者扩展Spring,而除了BeanPostProcessor外还有很多其他的PostProcessor,当然大部分都以此为基础,集成自BeanPostProcessor。BeanPostProcessor在调用用户自定义初始化方法前或者调用自定义初始化方法后分别会调用BeanPostProcessor的 postProcessBeforeInitialization()postProcessAfterinitialization() 方法,使用户可以根据自己的业务需求就行相应的处理。
# AbstractAutowireCapableBeanFactory
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)  
        throws BeansException {  

    Object result = existingBean;  
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {  
        result = beanProcessor.postProcessBeforeInitialization(result, beanName);  
        if (result == null) {  
            return result;  
        }  
    }  
    return result;  
}

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

    Object result = existingBean;  
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {  
        result = beanProcessor.postProcessAfterInitialization(result, beanName);  
        if (result == null) {  
            return result;  
        }  
    }  
    return result;  
}
(3)invokeInitMethods(beanName, wrappedBean, mbd)——激活自定义的init方法
客户定制的初始化方法除了我们熟知的使用配置 init-method 外,还有使自定义的bean 实现InitializingBean接口,并在 afterPropertiesSet() 中实现自己的初始化业务逻辑。init-method与afterPropertiesSet 都是在初始化bean时执行,执行顺序是 afterPropertiesSet() 先执行,而 init-method 后执行
在invokeInitMethods方法中就实现了这两个步骤的初始化调用。源码如下:
# AbstractAutowireCapableBeanFactory
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
        throws Throwable {

    // 是否实现 InitializingBean
    // 如果实现了 InitializingBean 接口,则只掉调用bean的 afterPropertiesSet()
    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isDebugEnabled()) {
            logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }
        if (System.getSecurityManager() != null) {
            try {
                AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                    ((InitializingBean) bean).afterPropertiesSet();
                    return null;
                }, getAccessControlContext());
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
            // 直接调用 afterPropertiesSet()
            ((InitializingBean) bean).afterPropertiesSet();
        }
    }

    if (mbd != null && bean.getClass() != NullBean.class) {
        // 判断是否指定了 init-method(),
        // 如果指定了 init-method(),则再调用制定的init-method
        String initMethodName = mbd.getInitMethodName();
        if (StringUtils.hasLength(initMethodName) &&
                !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                !mbd.isExternallyManagedInitMethod(initMethodName)) {
            // 利用反射机制执行初始化方法
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}
首先检测当前 bean 是否实现了 InitializingBean 接口,如果实现了则调用其 afterPropertiesSet(),然后再检查是否也指定了 init-method(),如果指定了则通过 反射机制调用指定的 init-method()
init-method() 测试用例 :
public class InitializingBeanTest {

    private String name;
    //... get/set方法
    public void setOtherName(){
        this.name = "wangjiafu";
        System.out.println("InitializingBeanTest setOtherName " + this.name);
    }
}

//applicationContext.xml 配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="initializingBeanTest" class="com.wangjiafu.spring.InitializingBeanTest"
            init-method="setOtherName">
        <property name="name" value="wangjiafu123"/>
    </bean>
</beans>

//测试
public class Test {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        InitializingBeanTest test = (InitializingBeanTest)ctx.getBean("initializingBeanTest");
    }
}

//执行结果
InitializingBeanTest setOtherName wangjiafu
我们可以使用 标签的 default-init-method 属性来 统一指定初始化方法,这样就 省了需要在每个 标签中都设置 init-method 这样的繁琐工作了。比如在 default-init-method 规定所有初始化操作全部以 initMethod() 命名。如下图:
我们看看 invokeCustomInitMethod() 方法(利用反射机制执行初始化方法):
protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)
        throws Throwable {

    String initMethodName = mbd.getInitMethodName();
    Assert.state(initMethodName != null, "No init method set");
    Method initMethod = (mbd.isNonPublicAccessAllowed() ?
            BeanUtils.findMethod(bean.getClass(), initMethodName) :
            ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));

    if (initMethod == null) {
        if (mbd.isEnforceInitMethod()) {
            throw new BeanDefinitionValidationException("Could not find an init method named '" +
                    initMethodName + "' on bean with name '" + beanName + "'");
        }
        else {
            if (logger.isTraceEnabled()) {
                logger.trace("No default init method named '" + initMethodName +
                        "' found on bean with name '" + beanName + "'");
            }
            // Ignore non-existent default lifecycle methods.
            return;
        }
    }

    if (logger.isTraceEnabled()) {
        logger.trace("Invoking init method  '" + initMethodName + "' on bean with name '" + beanName + "'");
    }
    Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod);

    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            ReflectionUtils.makeAccessible(methodToInvoke);
            return null;
        });
        try {
            AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
                    methodToInvoke.invoke(bean), getAccessControlContext());
        }
        catch (PrivilegedActionException pae) {
            InvocationTargetException ex = (InvocationTargetException) pae.getException();
            throw ex.getTargetException();
        }
    }
    else {
        try {
            ReflectionUtils.makeAccessible(initMethod);
            initMethod.invoke(bean);
        }
        catch (InvocationTargetException ex) {
            throw ex.getTargetException();
        }
    }
}
我们看出最后是使用反射的方式来执行初始化方法。
5.1.7.5 registerDisposableBeanIfNecessary(beanName, bean, mbd)——注册DisposeableBean
AbstractAutowireCapableBeanFactory.class
Spring中不但提供了对于初始化方法的扩展入口,同样也提供了销毁方法的扩展入口,对于销毁方法的扩展,除了熟知的 destory-method 方法外,用户还可以注册后处理器 DestructionAwareBeanPostProcessor 来统一处理bean的销毁方法。代码如下:
# AbstractBeanFactory
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
   if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
      if (mbd.isSingleton()) {
          /*
           * 单例模式下注册需要销毁的bean,此方法中会处理实现DisposableBean的bean,
           * 并对所有的bean使用DestructionAwareBeanPostProcessor处理
           * DisposableBean DestructionAwareBeanPostProcessors。
           */
         // Register a DisposableBean implementation that performs all destruction
         // work for the given bean: DestructionAwareBeanPostProcessors,
         // DisposableBean interface, custom destroy method.
         registerDisposableBean(beanName, new DisposableBeanAdapter(
               bean, beanName, mbd, getBeanPostProcessorCache().destructionAware));
      }
      else {
         // 自定义scope的处理
         Scope scope = this.scopes.get(mbd.getScope());
         if (scope == null) {
            throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
         }
         scope.registerDestructionCallback(beanName, new DisposableBeanAdapter(
               bean, beanName, mbd, getBeanPostProcessorCache().destructionAware));
      }
   }
}

# DefaultSingletonBeanRegistry
/** Disposable bean instances: bean name to disposable instance. */
private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
public void registerDisposableBean(String beanName, DisposableBean bean) {
   synchronized (this.disposableBeans) {
      this.disposableBeans.put(beanName, bean);
   }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2301725.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ThinkPHP(TP)如何做安全加固,防webshell、防篡改、防劫持、TP漏洞防护

ThinkPHP是一款非常知名的PHP框架&#xff0c;很多知名CMS系统都是采用TP框架进行二次开发而来&#xff0c;当然ThinkPHP本身也可以直接建站&#xff0c;开源免费、功能强大&#xff0c;深受广大用户喜欢。 虽然ThinkPHP非常优秀&#xff0c;但是为了保障网站安全&#xff0c;我…

MySQL(1)基础篇

执行一条 select 语句&#xff0c;期间发生了什么&#xff1f; | 小林coding 目录 1、连接MySQL服务器 2、查询缓存 3、解析SQL语句 4、执行SQL语句 5、MySQL一行记录的存储结构 Server 层负责建立连接、分析和执行 SQL存储引擎层负责数据的存储和提取。支持InnoDB、MyIS…

分裂栅结构对碳化硅MOSFET重复雪崩应力诱导退化的抑制作用

标题 Suppression Effect of Split-Gate Structure on Repetitive Avalanche Stress Induced Degradation for SiC MOSFETs&#xff08;TED 24年&#xff09; 文章的研究内容 这篇文章的研究探讨了重复雪崩应力对碳化硅&#xff08;SiC&#xff09;MOSFET器件退化的影响&am…

JavaEE基础之- xml

目录 一、xml概述 1.什么是xml 2.W3C组织 3.XML的作用 4.XML与HTML比较 5.XML和properties&#xff08;属性文件&#xff09;比较 二、XML语法概述 1.文档展示 2.XML文档的组成部分 3.xml文档声明 3.1 什么是xml文档声明 3.2 xml文档声明结构 4.xml元素 4.1 xml元素的格…

网络运维学习笔记 012网工初级(HCIA-Datacom与CCNA-EI)某机构新增:GRE隧道与EBGP实施

文章目录 GRE隧道&#xff08;通用路由封装&#xff0c;Generic Routing Encapsulation&#xff09;协议号47实验&#xff1a;思科&#xff1a;开始实施&#xff1a; 华为&#xff1a;开始实施&#xff1a; eBGP实施思科&#xff1a;华为&#xff1a; GRE隧道&#xff08;通用路…

RK3568开发板/电脑/ubuntu处于同一网段互通

1.查看无线局域网适配器WLAN winR输入cmd打开电脑终端输入ipconfig或arp -a查看无线局域网IP地址&#xff0c;这就是WIFI. 这里的IPv4是192.168.0.147&#xff0c;默认网关是192.168.0.1&#xff0c;根据网关地址配以太网IP, ubuntu的IP,和rk3568的IP。 且IP范围为192.168.…

如何调用 DeepSeek API:详细教程与示例

目录 一、准备工作 二、DeepSeek API 调用步骤 1. 选择 API 端点 2. 构建 API 请求 3. 发送请求并处理响应 三、Python 示例&#xff1a;调用 DeepSeek API 1. 安装依赖 2. 编写代码 3. 运行代码 四、常见问题及解决方法 1. API 调用返回 401 错误 2. API 调用返回…

如何在Jenkins上查看Junit报告

在 Jenkins 上查看 JUnit 报告通常有以下几个步骤&#xff1a; 构建结果页面: 首先&#xff0c;确保你的 Jenkins 构建已经执行完毕&#xff0c;并且成功生成了 JUnit 报告。前往 Jenkins 主页面&#xff0c;点击进入相应的项目或流水线。 构建记录: 选择你想查看的特定构建记…

【深度学习】计算机视觉(CV)-图像生成-风格迁移(Style Transfer)

风格迁移&#xff08;Style Transfer&#xff09; 风格迁移是一种计算机视觉技术&#xff0c;可以将一张图像的内容和另一张图像的风格融合在一起&#xff0c;生成一张既保留原始内容&#xff0c;又带有目标风格的全新图像&#xff01;这种方法常用于艺术创作、图像增强、甚至…

在项目中调用本地Deepseek(接入本地Deepseek)

前言 之前发表的文章已经讲了如何本地部署Deepseek模型&#xff0c;并且如何给Deepseek模型投喂数据、搭建本地知识库&#xff0c;但大部分人不知道怎么应用&#xff0c;让自己的项目接入AI模型。 文末有彩蛋哦&#xff01;&#xff01;&#xff01; 要接入本地部署的deepsee…

JAVA中常用类型

一、包装类 1.1 包装类简介 java是面向对象的语言&#xff0c;但是八大基本数据类型不符合面向对象的特征。因此为了弥补这种缺点&#xff0c;为这八中基本数据类型专门设计了八中符合面向面向对象的特征的类型&#xff0c;这八种具有面向对象特征的类型&#xff0c;就叫做包…

使用 GPTQ 进行 4 位 LLM 量化

权重量化方面的最新进展使我们能够在消费级硬件上运行大量大型语言模型&#xff0c;例如 RTX 3090 GPU 上的 LLaMA-30B 模型。这要归功于性能下降最小的新型 4 位量化技术&#xff0c;例如GPTQ、GGML和NF4。 在本文中&#xff0c;我们将探索流行的 GPTQ 算法&#xff0c;以了解…

【黑马点评优化】2-Canel实现多级缓存(Redis+Caffeine)同步

【黑马点评优化】2-Canel实现多级缓存&#xff08;RedisCaffeine&#xff09;同步 0 背景1 配置MySQL1.1 开启MySQL的binlog功能1.1.1 找到mysql配置文件my.ini的位置1.1.2 开启binlog 1.2 创建canal用户 2 下载配置canal2.1 canal 1.1.5下载2.2 配置canal2.3 启动canal2.4 测试…

CPP集群聊天服务器开发实践(五):nginx负载均衡配置

1 负载均衡器的原理与功能 单台Chatserver可以容纳大约两万台客户端同时在线聊天&#xff0c;为了提升并发量最直观的办法需要水平扩展服务器的数量&#xff0c;三台服务器可以容纳六万左右的客户端。 负载均衡器的作用&#xff1a; 把client的请求按照负载均衡算法分发到具体…

百问网(100ask)的IMX6ULL开发板的以太网控制器(MAC)与物理层(PHY)芯片(LAN8720A)连接的原理图分析(包含各引脚说明以及工作原理)

前言 本博文承接博文 https://blog.csdn.net/wenhao_ir/article/details/145663029 。 本博文和博文 https://blog.csdn.net/wenhao_ir/article/details/145663029 的目录是找出百问网(100ask)的IMX6ULL开发板与NXP官方提供的公板MCIMX6ULL-EVK(imx6ull14x14evk)在以太网硬件…

组件库地址

react&#xff1a; https://react-vant.3lang.dev/components/dialoghttps://react-vant.3lang.dev/components/dialog vue用v2的 Vant 2 - Mobile UI Components built on Vue

2025.2.16机器学习笔记:TimeGan文献阅读

2025.2.9周报 一、文献阅读题目信息摘要Abstract创新点网络架构一、嵌入函数二、恢复函数三、序列生成器四、序列判别器损失函数 实验结论后续展望 一、文献阅读 题目信息 题目&#xff1a; Time-series Generative Adversarial Networks会议&#xff1a; Neural Information…

最新智能优化算法: 中华穿山甲优化( Chinese Pangolin Optimizer ,CPO)算法求解23个经典函数测试集,MATLAB代码

中华穿山甲优化&#xff08; Chinese Pangolin Optimizer &#xff0c;CPO&#xff09;算法由GUO Zhiqing 等人提出&#xff0c;该算法的灵感来自中华穿山甲独特的狩猎行为&#xff0c;包括引诱和捕食行为。 算法流程如下&#xff1a; 1. 开始 设置算法参数和最大迭代次数&a…

使用 DeepSeek + 语音转文字工具 实现会议整理

目录 简述 1. DeepSeek与常用的语音转文字工具 1.1 DeepSeek 1.2 讯飞听见 1.3 飞书妙记 1.4 剪映电脑版 1.5 Buzz 2. 安装Buzz 3. 使用DeepSeek Buzz提取并整理语音文字 3.1 使用 Buzz 完成语音转文字工作 3.2 使用 DeepSeek 进行文本处理工作 3.3 整理成思维导图…

【OS安装与使用】part4-ubuntu22.04安装anaconda

文章目录 一、待解决问题1.1 问题描述1.2 解决方法 二、方法详述2.1 必要说明2.2 应用步骤2.2.1 官网下载Anaconda&#xff08;1&#xff09;确认自己的系统型号与硬件架构&#xff08;2&#xff09;官网下载对应版本 2.2.2 安装Anaconda&#xff08;1&#xff09;基于shell脚本…