• 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

Spring IoC bean 的加载

开发技术 开发技术 1个月前 (06-26) 65次浏览

前言

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

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

正文

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

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,下面我们就重点分析这个方法背后做了什么操作。

在正式开始之前,我们先了解一下 FactoryBean 及其用法。

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 实体类:

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 的所有属性配置值。

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 中配置。

<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);
}

Spring IoC bean 的加载

可以看到如果 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 属性。

Spring IoC bean 的加载

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

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

Spring IoC 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 是否相等,不同线程是否不等。

结果如下图:

Spring IoC 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。

参考


程序员灯塔 , 版权所有
转载请注明原文链接:https://www.wangt.cc/2020/06/spring-ioc-bean-%e7%9a%84%e5%8a%a0%e8%bd%bd/
喜欢 (0)