Spring 源码: SingletonBeanRegistry 接口

在开始阅读 SingletonBeanRegistry 类源码前,先来思考下:

  • 在对象维度上,每一个实例都有唯一标识符,就类似我们的身份证号码,一一绑定。
  • 在实例工厂维度上,每一个工厂都有唯一标识符,可以通过该唯一标识符来使用工厂生产制定的对象。
  • 在对象关系维度上,对象间存在包含与被包含、依赖与被依赖的关系。

先来了解下什么是 spring bean,Spring Bean是什么解释很清楚了。

SingletonBeanRegistry:制定创建单例协议,其中包括增查:

public interface SingletonBeanRegistry {

    // 在bean注册表中以给定的bean名称将给定的现有对象注册为单例对象
    void registerSingleton(String beanName, Object singletonObject);

    // 返回在给定名称下注册的(原始)单例对象
    Object getSingleton(String beanName);

    // 检查此注册表是否包含具有给定名称的单例实例
    boolean containsSingleton(String beanName);

    // 返回在此注册中心注册的单例bean的名称
    String[] getSingletonNames();

    // 返回在此注册中心注册的单例bean的数量
    int getSingletonCount();

    // 获取系统当前作为互斥目的的单例对象
    Object getSingletonMutex();
}

SingletonBeanRegistry 的实现类:

AbstractAutowireCapableBeanFactory.java
AbstractBeanFactory.java
ConfigurableBeanFactory.java
ConfigurableListableBeanFactory.java
DefaultListableBeanFactory.java
DefaultSingletonBeanRegistry.java
FactoryBeanRegistrySupport.java

DefaultSingletonBeanRegistry 实现 SingletonBeanRegistry 接口,其主要的职责对单例的管理(增删改查、缓存)、维护对象间的关系:

内部使用 Map 和 Set 容器来维护各种关系,包括:

beanName 到实例的映射容器:

private final Map singletonObjects = new ConcurrentHashMap<>(256);

beanName 到对象工厂映射容器:

 private final Map> singletonFactories = new HashMap<>(16);

旧单例对象的缓存容器:

private final Map earlySingletonObjects = new HashMap<>(16);

 已注册 beanName 容器:

private final Set registeredSingletons = new LinkedHashSet<>(256);

 当前正在创建的 beanName 容器:

private final Set singletonsCurrentlyInCreation =
	Collections.newSetFromMap(new ConcurrentHashMap<>(16));

禁止创建对象的 beanName 过滤器容器:

private final Set inCreationCheckExclusions =
            Collections.newSetFromMap(new ConcurrentHashMap<>(16));

异常的列表,可用于关联相关原因。在创建对象时记录出现的异常,以便于抛出:

private Set suppressedExceptions;

标记单例工厂已销毁:

private boolean singletonsCurrentlyInDestruction = false;

一次性对象(用完即止)容器:

private final Map disposableBeans = new LinkedHashMap<>();

bean名间的包含与被包含的关系容器:

private final Map> containedBeanMap = new ConcurrentHashMap<>(16);

被依赖者被哪些对象依赖容器:

private final Map> dependentBeanMap = new ConcurrentHashMap<>(64);

依赖者依赖哪些对象的容器:

private final Map> dependenciesForBeanMap = new ConcurrentHashMap<>(64);

注册单例,该过程是线程安全的,会调用 addSingleton() 方法修改对应的容器状态:

public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
    synchronized (this.singletonObjects) {  // 同步操作
        Object oldObject = this.singletonObjects.get(beanName);
        if (oldObject != null) {  //存在则抛出IllegalStateException
            throw new IllegalStateException("Could not register object [" + singletonObject +
                    "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
        }
        addSingleton(beanName, singletonObject);
    }
}

addSingleton() 方法修改单例容器、工厂容器、早期容器、已注册容器状态,这里会移除旧容器里指定 beanName 绑定的对象,清除其占用的空间:

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);  // 添加beanName到已注册集合中
    }
}

当一个对象的属性指向另一个对象,表明两个对象存在包含与被包含关系,这种对象间的关系需要保存:

public class A {
    private B b;
}

在 A 类中,存在一个 B 类的属性,在这里需要记录 A 包含 B 的关系:

/**
 * 注册名称间的包含与被包含关系
 * @containedBeanName:被包含 B
 * @containingBeanName:包含 A
 */
public void registerContainedBean(String containedBeanName, String containingBeanName) {
	synchronized (this.containedBeanMap) { // 同步操作
		/**
		 * 创建一个与containingBeanName关联的容器,不存在则创建关联容器
		 * A 对象属性依赖的对象容器
		 */
		Set containedBeans =
				this.containedBeanMap.computeIfAbsent(containingBeanName, k -> new LinkedHashSet<>(8));
		if (!containedBeans.add(containedBeanName)) { // 添加关联
			return;
		}
	}
	registerDependentBean(containedBeanName, containingBeanName);
}

 在 A 类中,存在一个 B 类的属性,在这里需要记录 A 依赖哪些对象,B 被哪些对象依赖:

/**
 * 注册两个名称之间的依赖关系
 * @beanName:被依赖者(被包含)       B
 * @dependentBeanName:依赖者(包含)  A
 */
public void registerDependentBean(String beanName, String dependentBeanName) {
    String canonicalName = canonicalName(beanName); // 获取名称

    synchronized (this.dependentBeanMap) { // 同步操作
        // 创建被依赖者被哪些对象依赖集合,B 类实例被哪些实例依赖
        Set dependentBeans =
                this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
        if (!dependentBeans.add(dependentBeanName)) { // 添加依赖者
            return;
        }
    }

    synchronized (this.dependenciesForBeanMap) {
        // 创建依赖者依赖哪些对象的集合,A 类实例依赖哪些实例
        Set dependenciesForBean =
                this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
        dependenciesForBean.add(canonicalName); //添加被依赖者
    }
}

 上面提到对象间的依赖关系,接下来看如何查找 beanName 间的关系:

protected boolean isDependent(String beanName, String dependentBeanName) {
    synchronized (this.dependentBeanMap) {
        return isDependent(beanName, dependentBeanName, null);
    }
}

 依赖关系不仅仅与指定 beanName 的依赖容器里的对象依赖,还可以出现依赖链,与集合里的某个对象的依赖集合中的对象产生依赖关系:

/**
 * @beanName:被依赖者(被包含)
 * @dependentBeanName:依赖者(包含)
 * bean之间的依赖关系是可以传递的
 * A->B且B->C,则A->C
 */
private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set alreadySeen) {
    // 排除环形依赖 A->C->A不处理会循环下面的步骤,继续以A开始查找
    if (alreadySeen != null && alreadySeen.contains(beanName)) {
        return false;
    }
    String canonicalName = canonicalName(beanName); // 获取名称
    // 被依赖者被哪些对象依赖集合
    Set dependentBeans = this.dependentBeanMap.get(canonicalName);
    if (dependentBeans == null) { // 两者间不存在依赖关系
        return false;
    }
    if (dependentBeans.contains(dependentBeanName)) {
        return true; // 与指定依赖者存在依赖关系
    }
    // 遍历依赖集合,查找以依赖者为被依赖角色的依赖集合是否存在
    for (String transitiveDependency : dependentBeans) {
        if (alreadySeen == null) { // 记录已匹配过的名称,避免出现环形依赖的情况
            alreadySeen = new HashSet<>();
        }
        alreadySeen.add(beanName);
        // 递归检查
        if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
            return true;
        }
    }
    return false;
}

注册实例工厂到工厂容器:

/**
 * 往实例工厂容器存放工厂
 * 注意:只要工厂容器或单例容器二者包含指定id的实例,就会标记该实例已创建
 */
protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory) {
	synchronized (this.singletonObjects) {
		if (!this.singletonObjects.containsKey(beanName)) {//指定名称是否存在单例容器
			//添加到单例工厂容器
			this.singletonFactories.put(beanName, singletonFactory);
			this.earlySingletonObjects.remove(beanName); //把早期的缓存中删除
			this.registeredSingletons.add(beanName);// 添加名称到已注册集合中
		}
	}
}

 获取单例,首先会从单例缓存容器查找,没有的话则会从早期缓存容器查找,还是没存在则会从工厂容器里有没有对应的工厂类:

public Object getSingleton(String beanName) {
	return getSingleton(beanName, true);
}

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

在获取容器步骤中,如果不存在指定的缓存实例,则有可能该实例正在被创建:

// 指定名称的实例是否正在被创建
public boolean isSingletonCurrentlyInCreation(String beanName) {
	return this.singletonsCurrentlyInCreation.contains(beanName);
}

 获取指定 beanName 的实例的重载方法,注意该方法的第二个参数是一个工厂实例,如果不存在指定 beanName 的实例,则会通过工厂来创建:

public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
	synchronized (this.singletonObjects) { //同步
		Object singletonObject = this.singletonObjects.get(beanName); // 从容器中获取
		if (singletonObject == null) { // 不在容器中
			if (this.singletonsCurrentlyInDestruction) {
				//单例工厂已销毁,抛出BeanCreationNotAllowedException异常
			}
			beforeSingletonCreation(beanName); // 先添加到存放正在创建的容器
			boolean newSingleton = false;
			boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
			if (recordSuppressedExceptions) {
				this.suppressedExceptions = new LinkedHashSet<>(); // 创建异常列表
			}
			try {
				singletonObject = singletonFactory.getObject();
				newSingleton = true;
			}
			catch (IllegalStateException ex) { // 多线程同时创建同一个名称对象
				// Has the singleton object implicitly appeared in the meantime ->
				// if yes, proceed with it since the exception indicates that state.
				singletonObject = this.singletonObjects.get(beanName);
				if (singletonObject == null) {
					throw ex;
				}
			}
			catch (BeanCreationException ex) {
				//在创建过程中抛出异常,比如没找到对应的Class对象等情况
				if (recordSuppressedExceptions) {
					for (Exception suppressedException : this.suppressedExceptions) {
						ex.addRelatedCause(suppressedException);
					}
				}
				throw ex;
			}
			finally {
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = null; // 回收异常列表
				}
				afterSingletonCreation(beanName); // 记录正在创建实例容器的善后工作
			}
			if (newSingleton) { // 添加到单例容器
				addSingleton(beanName, singletonObject);
			}
		}
		return singletonObject;
	}
}

 使用工厂类创建实例步骤中会先做以下的校验:

1、首先不是所有 beanName 绑定的实例都可以被创建,所以需要记录哪些 beanName 不能被创建:

public void setCurrentlyInCreation(String beanName, boolean inCreation) {
	if (!inCreation) {
		this.inCreationCheckExclusions.add(beanName);
	}
	else {
		this.inCreationCheckExclusions.remove(beanName);
	}
}

2、当创建指定 beanName 实例到存放到容器的过程中,会出现一个空档期,在这个空档期内如何防止再次创建对应的实例?需要记录当前正在创建指定 beanName 实例的一个表格:

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

3、创建成功后会执行释放动作:把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");
	}
}

查找是否存在指定 beanName 的实例:

@Override
public boolean containsSingleton(String beanName) {
	return this.singletonObjects.containsKey(beanName);
}

获取已注册实例 beanName 列表:

public String[] getSingletonNames() {
	synchronized (this.singletonObjects) {
		return StringUtils.toStringArray(this.registeredSingletons);
	}
}

在这里使用一个容器存放需要销毁的 beanName 指定的实例:

public void registerDisposableBean(String beanName, DisposableBean bean) {
    synchronized (this.disposableBeans) {
        this.disposableBeans.put(beanName, bean);
    }
}

清理所有缓存的容器,首先会遍历销毁容器:

/**
 * 销毁单例容器
 * 首先处理销毁容器,清理对象间的依赖关系
 * 然后在清理其他容器
 */
public void destroySingletons() {
    synchronized (this.singletonObjects) {
        this.singletonsCurrentlyInDestruction = true; // 设置销毁状态
    }

    String[] disposableBeanNames;
    synchronized (this.disposableBeans) { // 获取一次性容器
        disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
    }
    for (int i = disposableBeanNames.length - 1; i >= 0; i--) { // 销毁需要销毁的单例
        // 这一步处理的目的是执行DisposableBean.destory方法
        destroySingleton(disposableBeanNames[i]);
    }

    this.containedBeanMap.clear(); // 清除包含关系
    this.dependentBeanMap.clear(); // 清除被依赖者集合
    this.dependenciesForBeanMap.clear(); // 清除依赖者集合

    clearSingletonCache();
}

循环调用下面的函数删除指定的 beanName 关联的对象:

public void destroySingleton(String beanName) {
    // 对缓存容器、实例化单例工厂容器、早期缓存容器、记录容器清除工作
    removeSingleton(beanName);

    DisposableBean disposableBean;
    synchronized (this.disposableBeans) { // 从一次性集合中剔除
        disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
    }
    destroyBean(beanName, disposableBean);
}

首先会移除对应容器指定的 beanName:

protected void removeSingleton(String beanName) {
    synchronized (this.singletonObjects) {
        this.singletonObjects.remove(beanName); // 移除出单例缓存容器
        this.singletonFactories.remove(beanName); // 移除出单例工厂容器
        this.earlySingletonObjects.remove(beanName); // 移除出早期单例缓存容器
        this.registeredSingletons.remove(beanName); //移除出记录已创建单例缓存容器
    }
}

移除过程中必须移除被移除对象与其他对象间的包含、依赖、被依赖的关系:

protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
    // 首先对依赖bean的销毁
    Set dependencies;
    synchronized (this.dependentBeanMap) {
        // 移除被依赖者集合
        dependencies = this.dependentBeanMap.remove(beanName);
    }
    if (dependencies != null) {
        for (String dependentBeanName : dependencies) { // 移除每一个依赖者
            // 移除bean依赖链
            destroySingleton(dependentBeanName);
        }
    }

    if (bean != null) {
        try {
            bean.destroy(); // 执行bean的销毁动作
        }
        catch (Throwable ex) { }
    }

    // 销毁bean之间的包含关系
    Set containedBeans;
    synchronized (this.containedBeanMap) {
        // 销毁被包含集合
        containedBeans = this.containedBeanMap.remove(beanName);
    }
    /**
     * 每一个包含关系都有对应的依赖关系,这是一一对应的,即同生共死
     * 创建对象间包含关系同时会创建依赖关系,在销毁时先断掉依赖关系再断掉包含关系
     * 所以切断依赖关系操作中会执行destory,这里还有必要执行这样的操作吗?
     */
    if (containedBeans != null) {
        for (String containedBeanName : containedBeans) { // 移除每一个包含者
            destroySingleton(containedBeanName); // 包含链的处理
        }
    }

    // 被依赖者可以依赖某些对象,需要从其依赖的对象集合中删除被依赖者名称
    synchronized (this.dependentBeanMap) {
        for (Iterator>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {
            Map.Entry> entry = it.next();
            Set dependenciesToClean = entry.getValue();
            dependenciesToClean.remove(beanName); // 移除每一个set包含的名称
            if (dependenciesToClean.isEmpty()) {
                it.remove(); // 依赖容器为空,则清出缓存
            }
        }
    }

    // 从依赖者集合中删除指定名称
    this.dependenciesForBeanMap.remove(beanName);
}

思考:

1、包含与被包含关系决定依赖与被依赖关系。包含即依赖,被包含即被依赖的关系。

2、在注册bean之间的依赖关系时,例如:B->A,B 依赖 A,B 是依赖者,A 是被依赖者。需要处理依赖者与被依赖者的双向关系:

Spring 源码: SingletonBeanRegistry 接口_第1张图片

3、依赖关系可以传递:B->A 且 A->C,即 B->C。

4、销毁指定的名称操作,需要销毁与之包含、依赖的关系集合。

5、当一个对象被销毁时,依赖它的对象同时也会被销毁,这样做的是为了程序的健壮性。可以换个角度思考下,如果被依赖的对象不存在了,那依赖的对象还有存在的必要吗?或者还能完成它协议的职责吗?

Spring 源码: SingletonBeanRegistry 接口_第2张图片

你可能感兴趣的:(Spring)