Spring IoC bean 的加载

前言

本系列所有基于 Spring 5.2.2.BUILD-SNAPSHOT 版本。由于 Spring 整个体系太过于庞大,因此只会进行关键部分的源码解析。html

本篇文章主要介绍 Spring IoC 容器是怎么加载 bean 的。java

正文

咱们先看一下Spring IoC BeanDefinition 的加载和注册一文中获取 bean 的实例代码:git

public class BeanDefinitionDemo {

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        reader.loadBeanDefinitions("META-INF/bean-definition.xml");
        User user = beanFactory.getBean("user", User.class);
        System.err.println(user);
    }

}

经过 beanFactory.getBean() 这个方法就获取了在 XML 中定义的 bean,下面咱们就重点分析这个方法背后作了什么操做。github

在正式开始以前,咱们先了解一下 FactoryBean 及其用法。spring

FactoryBean 介绍

FactoryBean 接口对于 Spring 框架来讲占有重要的地位,Spring 自身就提供了70多个 FactoryBean 的实现。它们隐藏了一下复杂 bean 的细节,给上层应用带来了便利。下面是该接口的定义:缓存

public interface FactoryBean<T> {

    // 返回由FactoryBean建立的bean实例,若是isSingleton()返回true,
    // 则该实例会放到Spring容器中单例缓存池中
    @Nullable
    T getObject() throws Exception;
	
    // 返回FactoryBean建立的bean类型
    @Nullable
    Class<?> getObjectType();

    // 返回由FactoryBean建立的bean实例的做用域是singleton仍是prototype
    default boolean isSingleton() {
        return true;
    }

}

当配置文件中 <bean>class 属性配置的实现类时 FactoryBean 时,经过 getBean() 返回的不是 FactoryBean 自己,而是 FactoryBean#getObject() 所返回的对象,至关于 FactoryBean#getObject() 代理了 getBean()。下面用简单的代码演示一下:框架

首先定义一个 Car 实体类:less

public class Car {
	
    private Integer maxSpeed;
    private String brand;
    private Double price;

    public Integer getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(Integer maxSpeed) {
        this.maxSpeed = maxSpeed;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }
}

上面的实体类,若是用传统方式配置,每个属性都会对应一个 <property> 元素标签。若是用 FactoryBean 的方式实现就会灵活一点,下面经过逗号分隔的方式一次性的为 Car 的全部属性配置值。dom

public class CarFactoryBean implements FactoryBean<Car> {
	
    private String carInfo;
	
    @Override
    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;
    }

    @Override
    public Class<?> getObjectType() {
        return Car.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public String getCarInfo() {
        return carInfo;
    }

    public void setCarInfo(String carInfo) {
        this.carInfo = carInfo;
    }
}

接下来,咱们在 XML 中配置。ide

<bean id="car" class="com.leisurexi.ioc.domain.CarFactoryBean">
    <property name="carInfo" value="超级跑车,400,2000000"/>
</bean>

最后看下测试代码和运行结果:

@Test
public void factoryBeanTest() {
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
    reader.loadBeanDefinitions("META-INF/factory-bean.xml");
    Car car = beanFactory.getBean("car", Car.class);
    System.out.println(car);
    CarFactoryBean carFactoryBean = beanFactory.getBean("&car", CarFactoryBean.class);
    System.out.println(carFactoryBean);
}

能够看到若是 beanName 前面加上 & 获取的是 FactoryBean 自己,不加获取的 getObject() 返回的对象。

FactoryBean 的特殊之处在于它能够向容器中注册两个 bean,一个是它自己,一个是 FactoryBean.getObject() 方法返回值所表明的 bean

bean 的加载

AbstractBeanFactory#getBean

public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
    // 调用doGetBean方法(方法以do开头实际作操做的方法)
    return doGetBean(name, requiredType, null, false);
}

/**
* @param name          bean的名称
* @param requiredType  bean的类型
* @param args          显示传入的构造参数
* @param typeCheckOnly 是否仅仅作类型检查
*/
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    // 获取bean的实际名称,见下文详解
    final String beanName = transformedBeanName(name);
    Object bean;

    // 直接尝试从缓存获取或 singletonFactories 中的 ObjectFactory 中获取,见下文详解
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        // 检查bean是不是FactoryBean的实现。不是直接返回bean,
        // 是的话首先检查beanName是否以&开头,若是是返回FactoryBean自己,
        // 不是调用FactoryBean#getObject()返回对象,见下文详解
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    else {
        // 只有在单例状况下才会去尝试解决循环依赖,原型模式下,若是存在A中有
        // B属性,B中有A属性,那么当依赖注入时,就会产生当A还未建立完的时候
        // 对于B的建立而在此返回建立A,形成循环依赖
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        // 检查当前bean的BeanDefinition是否在当前的bean工厂中,
        // 不在递归调用父工厂的getBean()去获取bean
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            String nameToLookup = originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                    nameToLookup, requiredType, args, typeCheckOnly);
            }
            else if (args != null) {
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else if (requiredType != null) {
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
            else {
                return (T) parentBeanFactory.getBean(nameToLookup);
            }
        }
        // 若是不是仅仅作类型检查,则是建立bean,这里要进行记录
        if (!typeCheckOnly) {
            // 记录bean已经建立过
            markBeanAsCreated(beanName);
        }

        try {
            // 合并BeanDefinition,见下文详解
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            // 实例化bean前先实例化依赖bean,也就是depends-on属性中配置的beanName
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dep : dependsOn) {
                    // 检查是否循环依赖,即当前bean依赖dep,dep依赖当前bean,见下文详解
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    // 将dep和beanName的依赖关系放入到缓存中,见下文详解
                    registerDependentBean(dep, beanName);
                    try {
                        // 获取依赖dep对应的bean实例,若是还未建立实例,则先去建立
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }

            // 若是 bean 的做用域是单例
            if (mbd.isSingleton()) {
                // 建立和注册单例 bean,见下文详解
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        // 建立 bean 实例
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
                        destroySingleton(beanName);
                        throw ex;
                    }
                });
                // 获取bean实例
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
            // bean 的做用域是原型
            else if (mbd.isPrototype()) {
                Object prototypeInstance = null;
                try {
                    // 原型 bean 建立前回调,
                    // 默认实现是将 beanName 保存到 prototypesCurrentlyInCreation 缓存中
                    beforePrototypeCreation(beanName);
                    // 建立 bean 实例
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    // 原型 bean 建立后回调,
                    // 默认实现是将 beanName 从prototypesCurrentlyInCreation 缓存中移除
                    afterPrototypeCreation(beanName);
                }
                // 获取bean实例
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }
            // 自定义做用域
            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 {
                    // 其余 Scope 的 bean 建立
                    // 新建了一个 ObjectFactory,而且重写了 getObject 方法
                    Object scopedInstance = scope.get(beanName, () -> {
                        // 调用原型 bean 建立前回调
                        beforePrototypeCreation(beanName);
                        try {
                            // 建立 bean 实例,下篇文章详解
                            return createBean(beanName, mbd, args);
                        }
                        finally {
                            // 调用原型 bean 建立后回调
                            afterPrototypeCreation(beanName);
                        }
                    });
                    // 获取bean实例
                    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;
        }
    }

    // 检查所需的类型是否与实际 bean 实例的类型匹配
    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) {
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    // 返回 bean 实例
    return (T) bean;
}

上面方法就是获取 bean 的整个流程,下面咱们对其调用的其它主要方法来一一分析。

转换对应的 beanName

AbstractBeanFactory#transformedBeanName

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

// BeanFactoryUtils.java
public static String transformedBeanName(String name) {
    Assert.notNull(name, "'name' must not be null");
    // 若是name不是&开头,直接返回
    if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
        return name;
    }
    // 去除name的&前缀
    return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
        do {
            beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
        }
        while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
        return beanName;
    });
}

// SimpleAliasRegistry.java
public String canonicalName(String name) {
    String canonicalName = name;
    String resolvedName;
    // 若是name是别名,则会循环去查找bean的实际名称
    do {
        resolvedName = this.aliasMap.get(canonicalName);
        if (resolvedName != null) {
            canonicalName = resolvedName;
        }
    }
    while (resolvedName != null);
    return canonicalName;
}

尝试从单例缓存获取 bean

AbstractBeanFactory#getSingleton

public Object getSingleton(String beanName) {
    // allowEarlyReference设置为true表示容许早期依赖
    return getSingleton(beanName, true);
}

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 先从一级缓存中,检查单例缓存是否存在
    Object singletonObject = this.singletonObjects.get(beanName);
    // 若是为空,而且当前bean正在建立中,锁定全局变量进行处理
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            // 从二级缓存中获取
            singletonObject = this.earlySingletonObjects.get(beanName);
            // 二级缓存为空 && bean容许提早曝光
            if (singletonObject == null && allowEarlyReference) {
                // 从三级缓存中获取bean对应的ObjectFactory
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    // 调用预先设定的getObject(),获取bean实例
                    singletonObject = singletonFactory.getObject();
                    // 放入到二级缓存中,并从三级缓存中删除
                    // 这时bean已经实例化完但还未初始化完
                    // 在该bean未初始化完时若是有别的bean引用该bean,能够直接从二级缓存中取出返回
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

上面方法主要就是尝试从缓存中获取 bean,缓存有三级,这也是 Spring 解决循环依赖的关键所在;后续会在 循环依赖 中重点讲述。

获取 bean 实例对象

AbstractBeanFactory#getObjectForBeanInstance

protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

    // name 是否以 & 开头
    if (BeanFactoryUtils.isFactoryDereference(name)) {
        // 若是是 null 直接返回
        if (beanInstance instanceof NullBean) {
            return beanInstance;
        }
        // beanName 以 & 开头,但又不是 FactoryBean 类型,抛出异常
        if (!(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
        }
        // 设置 isFactoryBean 为 true
        if (mbd != null) {
            mbd.isFactoryBean = true;
        }
        // 返回 bean 实例
        return beanInstance;
    }

    // name 不是 & 开头,而且不是 FactoryBean 类型,直接返回
    if (!(beanInstance instanceof FactoryBean)) {
        return beanInstance;
    }

    // 到这里就表明name不是&开头,且是FactoryBean类型
    // 即获取FactoryBean.getObject()方法返回值所表明的bean
    Object object = null;
    if (mbd != null) {	
        mbd.isFactoryBean = true;
    }
    else {
        // 从缓存中获取实例
        object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
        // 将 beanInstance 强转成 FactoryBean
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // 合并 BeanDefinition
        if (mbd == null && containsBeanDefinition(beanName)) {
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        // 获取实例
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}

// FactoryBeanRegistrySupport.java
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    // 若是是单例 bean,而且已经存在缓存中
    if (factory.isSingleton() && containsSingleton(beanName)) {
        // 加锁
        synchronized (getSingletonMutex()) {
            // 从缓存中获取
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) {
                // 调用 FactoryBean 的 getObject() 获取实例
                object = doGetObjectFromFactoryBean(factory, beanName);
                Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                // 若是该 beanName 已经在缓存中存在,则将 object 替换成缓存中的
                if (alreadyThere != null) {
                    object = alreadyThere;
                }
                else {
                    if (shouldPostProcess) {
                        // 若是当前 bean 还在建立中,直接返回
                        if (isSingletonCurrentlyInCreation(beanName)) {
                            return object;
                        }
                        // 单例 bean 建立前回调
                        beforeSingletonCreation(beanName);
                        try {
                            // 对从 FactoryBean 得到给定对象的后置处理,默认按原样返回
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        }
                        catch (Throwable ex) {
                            throw new BeanCreationException(beanName,
                                                            "Post-processing of FactoryBean's singleton object failed", ex);
                        }
                        finally {
                            // 单例 bean 建立后回调
                            afterSingletonCreation(beanName);
                        }
                    }
                    if (containsSingleton(beanName)) {
                        // 将 beanName 和 object 放到 factoryBeanObjectCache 缓存中
                        this.factoryBeanObjectCache.put(beanName, object);
                    }
                }
            }
            // 返回实例
            return object;
        }
    }
    else {
        // 调用 FactoryBean 的 getObject() 获取实例
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        if (shouldPostProcess) {
            try {
                // 对从 FactoryBean 得到给定对象的后置处理,默认按原样返回
                object = postProcessObjectFromFactoryBean(object, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        // 返回实例
        return object;
    }
}

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

    Object object;
    try {
        // 调用 getObject() 获取实例
        object = factory.getObject();
    }
    // 省略异常处理...

    // 若是 object 为 null,而且当前 singleton bean 正在建立中,抛出异常
    if (object == null) {
        if (isSingletonCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName, "FactoryBean which is currently in creation returned null from getObject");
        }
        object = new NullBean();
    }
    // 返回 object 实例
    return object;
}

上面代码总结起来就是:若是 beanName& 开头,直接返回 FactoryBean 实例;不然调用 getObject() 方法获取实例,而后执行 postProcessObjectFromFactoryBean() 回调,能够在回调方法中修改实例,默认按原样返回。

合并 bean 定义元信息

AbstractBeanFactory#getMergedLocalBeanDefinition

下文将合并后的 BeanDefinition 简称为 MergedBeanDefinition

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
    // 从缓存获取MergedBeanDefinition
    RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
    // 若是存在MergedBeanDefinition,而且不是过时的,直接返回
    if (mbd != null && !mbd.stale) {
        return mbd;
    }
    // 获取已经注册的BeanDefinition而后去合并
    return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}

protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
		throws BeanDefinitionStoreException {
    // 顶级bean获取合并后的BeanDefinition
    return getMergedBeanDefinition(beanName, bd, null);
}

/**
 * @param containingBd 若是是嵌套bean该值为顶级bean,若是是顶级bean该值为null
 */
protected RootBeanDefinition getMergedBeanDefinition(
		String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
		throws BeanDefinitionStoreException {
	// 加锁
    synchronized (this.mergedBeanDefinitions) {
        // 本次的RootBeanDefinition
        RootBeanDefinition mbd = null;
        // 之前的RootBeanDefinition
        RootBeanDefinition previous = null;

        // 若是bean是顶级bean,直接获取MergedBeanDefinition
        if (containingBd == null) {
            mbd = this.mergedBeanDefinitions.get(beanName);
        }
		// 没有MergedBeanDefinition || BeanDefinition过时了
        if (mbd == null || mbd.stale) {
            previous = mbd;
            // 若是bean没有parent
            if (bd.getParentName() == null) {
                // 若是bd自己就是RootBeanDefinition直接复制一份,不然建立一个
                if (bd instanceof RootBeanDefinition) {
                    mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
                }
                else {
                    mbd = new RootBeanDefinition(bd);
                }
            }
            else {	
                // bean有parent
                BeanDefinition pbd;
                try {
                    // 获取parent bean的实际名称
                    String parentBeanName = transformedBeanName(bd.getParentName());
                    if (!beanName.equals(parentBeanName)) {
                        // 当前beanName不等于它的parentBeanName
                      	// 获取parent的MergedBeanDefinition
                        pbd = getMergedBeanDefinition(parentBeanName);
                    }
                    else {
                        // 若是parentBeanName与bd的beanName相同,则拿到父BeanFactory
                        // 只有在存在父BeanFactory的状况下,才容许parentBeanName与本身相同
                        BeanFactory parent = getParentBeanFactory();
                        if (parent instanceof ConfigurableBeanFactory) {
                            // 若是父BeanFactory是ConfigurableBeanFactory类型
                            // 则经过父BeanFactory获取parent的MergedBeanDefinition
                            pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
                        }
                        else {
                            // 若是父BeanFactory不是ConfigurableBeanFactory,抛出异常
                            throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName + "': cannot be resolved without an AbstractBeanFactory parent");
                        }
                    }
                }
                catch (NoSuchBeanDefinitionException ex) {
                    throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName, "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
                }
                // 使用父MergedBeanDefinition构建一个新的RootBeanDefinition对象(深拷贝)
                mbd = new RootBeanDefinition(pbd);
                // 覆盖与parent相同的属性
                mbd.overrideFrom(bd);
            }
            
            // 若是bean没有设置scope属性,默认是singleton
            if (!StringUtils.hasLength(mbd.getScope())) {
                mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
            }

            // 当前bean是嵌套bean && 顶级bean的做用域不是单例 && 当前bean的做用域是单例
            // 这里总结起来就是,若是顶层bean不是单例的,那么嵌套bean也不能是单例的
            if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
                // 设置当前bean的做用域和顶级bean同样
                mbd.setScope(containingBd.getScope());
            }

            // 当前bean是顶级bean && 缓存bean的元数据(该值默认为true)
            if (containingBd == null && isCacheBeanMetadata()) {
                // 将当前bean的MergedBeanDefinition缓存起来
                this.mergedBeanDefinitions.put(beanName, mbd);
            }
        }
        // 之前的RootBeanDefinition不为空,拷贝相关的BeanDefinition缓存
        if (previous != null) {
            copyRelevantMergedBeanDefinitionCaches(previous, mbd);
        }
        return mbd;
    }
}

上面代码主要是获取 MergedBeanDefinition ,主要步骤以下:

  1. 首先从缓存中获取 beanMergedBeanDefinition,若是存在而且未过时直接返回。

  2. 不存在或者已过时的 MergedBeanDefinition ,获取已经注册的 BeanDefinition 去做为顶级 bean 合并。

  3. bean 没有 parent (就是 XML 中的 parent 属性),直接封装成 RootBeanDefinition

  4. beanparent ,先去获取父 MergedBeanDefinition ,而后覆盖和合并与 parent 相同的属性。

    注意:这里只有 abstractscopelazyInitautowireModedependencyCheckdependsOnfactoryBeanNamefactoryMethodNameinitMethodNamedestroyMethodName 会覆盖,而 constructorArgumentValuespropertyValuesmethodOverrides 会合并。

  5. 若是没有设置做用域,默认做用域为 singleton

  6. 缓存 MergedBeanDefinition

上文中提到若是 beanparent,会合并一些属性,这里咱们稍微展现一下合并后的 propertyValues:

首先定义一个 SuperUser 继承上面定义的 User,以下:

public class SuperUser extends User {

    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "SuperUser{" +
            "address='" + address + '\'' +
            '}';
    }

}

而后咱们在 XML 文件中配置一下,以下:

<bean id="superUser" class="com.leisurexi.ioc.domain.SuperUser" parent="user">
    <property name="address" value="北京"/>
</bean>

而后下图是我 Debug 的截图,能够看到 superUserpropertyValues 合并了 useridname 属性。

上文还提到了嵌套 bean ,下面咱们简单看一下什么是嵌套 bean

在 Spring 中,若是某个 bean 所依赖的 bean 不想被 Spring 容器直接访问,可使用嵌套 bean。和普通的 bean 同样,使用 bean 元素来定义嵌套的 bean,嵌套 bean 只对它的外部 bean 有效,Spring 没法直接访问嵌套 bean ,所以定义嵌套 bean 也无需指定 id 属性。以下配置片断是一个嵌套 bean 示例:

采用上面的配置形式能够保证嵌套 bean 不能被容器访问,所以不用担忧其余程序修改嵌套 bean。外部 bean 的用法和使用结果和之前没有区别。

嵌套 bean 提升了 bean 的内聚性,可是下降了程序的灵活性。只有在肯定无需经过 Spring 容器访问某个 bean 实例时,才考虑使用嵌套 bean 来定义。

寻找依赖

DefaultSingletonBeanRegistry#isDependent

protected boolean isDependent(String beanName, String dependentBeanName) {
    // 加锁
    synchronized (this.dependentBeanMap) {
        // 检测beanName和dependentBeanName是否有循环依赖
        return isDependent(beanName, dependentBeanName, null);
    }
}

private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
    // 若是当前bean已经检测过,直接返回false
    if (alreadySeen != null && alreadySeen.contains(beanName)) {
        return false;
    }
    // 解析别名,获取实际的beanName
    String canonicalName = canonicalName(beanName);
    // 获取canonicalName所依赖beanName集合
    Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
    // 若是为空,二者还未肯定依赖关系,返回false
    if (dependentBeans == null) {
        return false;
    }
    // 若是dependentBeanName已经存在于缓存中,二者已经肯定依赖关系,返回true
    if (dependentBeans.contains(dependentBeanName)) {
        return true;
    }
    // 循环检查,即检查依赖canonicalName的全部beanName是否被dependentBeanName依赖(即隔层依赖)
    for (String transitiveDependency : dependentBeans) {
        if (alreadySeen == null) {
            alreadySeen = new HashSet<>();
        }
        // 将已经检查过的记录下来,下次直接跳过
        alreadySeen.add(beanName);
        if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
            return true;
        }
    }
    return false;
}

DefaultSingletonBeanRegistry#registerDependentBean

public void registerDependentBean(String beanName, String dependentBeanName) {
    // 解析别名,获取实际的beanName
    String canonicalName = canonicalName(beanName);
    // 加锁
    synchronized (this.dependentBeanMap) {
        // 获取canonicalName依赖beanName集合,若是为空默认建立一个LinkedHashSet当作默认值
        Set<String> dependentBeans =
            this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
        // 若是dependentBeanName已经记录过了,直接返回
        if (!dependentBeans.add(dependentBeanName)) {
            return;
        }
    }
    // 加锁
    synchronized (this.dependenciesForBeanMap) {
        // 这里是和上面的dependentBeanMap倒过来,key为dependentBeanName
        Set<String> dependenciesForBean =
            this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
        dependenciesForBean.add(canonicalName);
    }
}

下面咱们举个A、B的 depends-on 属性都是对方的例子:

首先获取A,调用 isDependent() 方法,由于第一次获取A,因此 dependentBeanMap 中没有记录依赖关系,直接返回 false;接着调用registerDependentBean(),这里会向 dependentBeanMap 中反过来存储依赖关系,也就是以B为 key value 是一个包含A的 Set集合。

接着会调用 getBean() 方法获取B,首先调用 isDependent() 方法,由于在获取A时已经存储了B的依赖关系,因此获取到的dependentBeans 的集合中包含A,因此直接返回true,抛出循环引用异常。

这个方法又引入了一个跟 dependentBeanMap 相似的缓存 dependenciesForBeanMap。这两个缓存很容易搞混,这里再举一个简单的例子:A 依赖 B,那么 dependentBeanMap 存放的是 key 为 B,value 为含有 A 的 Set;而 dependenciesForBeanMap 存放的是key 为 A,value 为含有 B 的 Set

建立和注册单例 bean

DefaultSingletonBeanRegistry#getSingleton

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);
        // 缓存中不存在当前 bean,也就是当前 bean 第一次建立
        if (singletonObject == null) {
            // 若是当前正在销毁 singletons,抛出异常
            if (this.singletonsCurrentlyInDestruction) {
                throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
            }
            // 建立单例 bean 以前的回调
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            try {
                // 获取 bean 实例,在此处才会去真正调用建立 bean 的方法
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            // 省略异常处理...
            finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }
                // 建立单例 bean 以后的回调
                afterSingletonCreation(beanName);
            }
            if (newSingleton) {
                // 将 singletonObject 放入缓存
                addSingleton(beanName, singletonObject);
            }
        }
        // 返回 bean 实例
        return singletonObject;
    }
}

// 单例 bean 建立前的回调方法,默认实现是将 beanName 加入到当前正在建立 bean 的缓存中,
// 这样即可以对循环依赖进行检测
protected void beforeSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
    }
}

// 单例 bean 建立后的回调方法,默认实现是将 beanName 从当前正在建立 bean 的缓存中移除
protected void afterSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
        throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
    }
}

protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
        // 这边bean已经初始化完成了,放入一级缓存
        this.singletonObjects.put(beanName, singletonObject);
        // 移除三级缓存
        this.singletonFactories.remove(beanName);
        // 移除二级缓存
        this.earlySingletonObjects.remove(beanName);
        // 将 beanName 添加到已注册 bean 缓存中
        this.registeredSingletons.add(beanName);
    }
}

自定义做用域示例

咱们实现一个 ThreadLocal 级别的做用域,也就是同一个线程内 bean 是同一个实例,不一样线程的 bean 是不一样实例。首先咱们继承 Scope 接口实现,其中方法。以下:

public class ThreadLocalScope implements Scope {

    /** scope 名称,在 XML 中的 scope 属性就配置此名称 */
    public static final String SCOPE_NAME = "thread-local";

    private final NamedThreadLocal<Map<String, Object>> threadLocal = new NamedThreadLocal<>("thread-local-scope");

    /**
    * 返回实例对象,该方法被 Spring 调用
    */
    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Map<String, Object> context = getContext();
        Object object = context.get(name);
        if (object == null) {
            object = objectFactory.getObject();
            context.put(name, object);
        }
        return object;
    }

    /**
    * 获取上下文 map
    */
    @NonNull
    private Map<String, Object> getContext() {
        Map<String, Object> map = threadLocal.get();
        if (map == null) {
            map = new HashMap<>();
            threadLocal.set(map);
        }
        return map;
    }

    @Override
    public Object remove(String name) {	
        return getContext().remove(name);
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
        // TODO
    }
	
    @Override
    public Object resolveContextualObject(String key) {
        Map<String, Object> context = getContext();
        return context.get(key);
    }

    @Override
    public String getConversationId() {
        return String.valueOf(Thread.currentThread().getId());
    }

}

上面的 ThreadLocalScope 重点关注下 get() 便可,该方法是被 Spring 调用的。

而后在 XML 中配置 beanscopethread-local。以下:

<bean id="user" name="user" class="com.leisurexi.ioc.domain.User" scope="thread-local">
    <property name="id" value="1"/>
    <property name="name" value="leisurexi"/>
</bean>

接着咱们测试一下。测试类:

@Test
public void test() throws InterruptedException {
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    // 注册自定义做用域
    beanFactory.registerScope(ThreadLocalScope.SCOPE_NAME, new ThreadLocalScope());
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
    reader.loadBeanDefinitions("META-INF/custom-bean-scope.xml");
    for (int i = 0; i < 3; i++) {
        Thread thread = new Thread(() -> {
            User user = beanFactory.getBean("user", User.class);
            System.err.printf("[Thread id :%d] user = %s%n", Thread.currentThread().getId(), user.getClass().getName() + "@" + Integer.toHexString(user.hashCode()));
            User user1 = beanFactory.getBean("user", User.class);
            System.err.printf("[Thread id :%d] user1 = %s%n", Thread.currentThread().getId(), user1.getClass().getName() + "@" + Integer.toHexString(user1.hashCode()));
        });
        thread.start();
        thread.join();
    }
}

说一下咱们这里的主要思路,新建了三个线程,查询线程内 user bean 是否相等,不一样线程是否不等。

结果以下图:

总结

本文主要介绍了 getBean() 方法流程,咱们能够从新梳理一下思路:

  1. 获取 bean 实际名称,若是缓存中存在直接取出实际 bean 返回。
  2. 缓存中不存在,判断当前工厂是否有 BeanDefinition ,没有递归去父工厂建立 bean
  3. 合并 BeanDefinition ,若是 depends-on 不为空,先去初始化依赖的 bean
  4. 若是 bean 的做用域是单例,调用 createBean() 方法建立实例,这个方法会执行 bean 的其它生命周期回调,以及属性赋值等操做;接着执行单例 bean 建立先后的生命周期回调方法,并放入 singletonObjects 缓存起来。
  5. 若是 bean 的做用域是原型,调用 createBean() 方法建立实例,并执行原型 bean 先后调用生命周期回调方法。
  6. 若是 bean 的做用域是自定义的,获取对应的 Scope 对象,调用重写的 get() 方法获取实例,并执行原型 bean 先后调用生命周期回调方法。
  7. 最后检查所需的类型是否与实际 bean 实例的类型匹配,若是不等进行转换,最后返回实例。

关于 createBean() 方法的细节,会在后续文章中进行分析。

最后,我模仿 Spring 写了一个精简版,代码会持续更新。地址:https://github.com/leisurexi/tiny-spring

参考

相关文章
相关标签/搜索