在开始阅读 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<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
beanName 到对象工厂映射容器:
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
旧单例对象的缓存容器:
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
已注册 beanName 容器:
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
当前正在创建的 beanName 容器:
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
禁止创建对象的 beanName 过滤器容器:
private final Set<String> inCreationCheckExclusions =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
异常的列表,可用于关联相关原因。在创建对象时记录出现的异常,以便于抛出:
private Set<Exception> suppressedExceptions;
标记单例工厂已销毁:
private boolean singletonsCurrentlyInDestruction = false;
一次性对象(用完即止)容器:
private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
bean名间的包含与被包含的关系容器:
private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);
被依赖者被哪些对象依赖容器:
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
依赖者依赖哪些对象的容器:
private final Map<String, Set<String>> 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<String> 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<String> dependentBeans =
this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
if (!dependentBeans.add(dependentBeanName)) { // 添加依赖者
return;
}
}
synchronized (this.dependenciesForBeanMap) {
// 创建依赖者依赖哪些对象的集合,A 类实例依赖哪些实例
Set<String> 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<String> alreadySeen) {
// 排除环形依赖 A->C->A不处理会循环下面的步骤,继续以A开始查找
if (alreadySeen != null && alreadySeen.contains(beanName)) {
return false;
}
String canonicalName = canonicalName(beanName); // 获取名称
// 被依赖者被哪些对象依赖集合
Set<String> 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<String> 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<String> containedBeans;
synchronized (this.containedBeanMap) {
// 销毁被包含集合
containedBeans = this.containedBeanMap.remove(beanName);
}
/**
* 每一个包含关系都有对应的依赖关系,这是一一对应的,即同生共死
* 创建对象间包含关系同时会创建依赖关系,在销毁时先断掉依赖关系再断掉包含关系
* 所以切断依赖关系操作中会执行destory,这里还有必要执行这样的操作吗?
*/
if (containedBeans != null) {
for (String containedBeanName : containedBeans) { // 移除每一个包含者
destroySingleton(containedBeanName); // 包含链的处理
}
}
// 被依赖者可以依赖某些对象,需要从其依赖的对象集合中删除被依赖者名称
synchronized (this.dependentBeanMap) {
for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, Set<String>> entry = it.next();
Set<String> 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 是被依赖者。需要处理依赖者与被依赖者的双向关系:
3、依赖关系可以传递:B->A 且 A->C,即 B->C。
4、销毁指定的名称操作,需要销毁与之包含、依赖的关系集合。
5、当一个对象被销毁时,依赖它的对象同时也会被销毁,这样做的是为了程序的健壮性。可以换个角度思考下,如果被依赖的对象不存在了,那依赖的对象还有存在的必要吗?或者还能完成它协议的职责吗?