【小家Spring】Spring的单例Bean定注册中心SingletonBeanRegistry详解

前言

上一篇重点介绍了bean定义信息的注册: 【小家Spring】Spring的Bean定义注册中心BeanDefinitionRegistry详解

本文着眼于Spring的Bean中最重要的类型:单例Bean。研究它的注册中心:SingletonBeanRegistry

SingletonBeanRegistry

此接口是针对Spring中的单例Bean设计的。提供了统一访问单例Bean的功能。比如我们熟悉的接口ConfigurableBeanFactory就继承了此接口

ConfigurableListableBeanFactory是它的子接口,DefaultListableBeanFactory是它的实现类。 AbstractBeanFactory、AbstractAutowireCapableBeanFactory也是ConfigurableListableBeanFactory的子接口 基本上可以说除了HierarchicalBeanFactory没有继承此接口,其余的都有直接或间接的实现~~~~

我们能够发现,最终真正实现这个接口的,都是BeanFactory

// @since 2.0 Spring2之后才出来这个接口
public interface SingletonBeanRegistry {

	//  以指定的名字  把Object放进去
	// 1、给定的Object必须是被完全初始化了的(比如new出来的)
	// 2、此注册接口不会提供任何用以初始化的回调函数(比如:InitializingBean、afterPropertiesSet都是不会执行的)
	// 3、如果此接口的实现类是一个BeanFactory,最好最好最好将你的类注册成Bean Definition而不是直接使用对象(这样就可以使你定义的Bean收到initialization和destruction回调)
	void registerSingleton(String beanName, Object singletonObject);

	// 仅仅返回已经初始化完成的Bean,对于还没有初始化的Bean Definition不予以考虑
	// 但是要注意,此方法**并不支持使用别名**对Bean进行查找,如果只有别名的话,要先通过BeanFactory的接口获取到Bean对应的全限定名称(transformedBeanName())
	@Nullable
	Object getSingleton(String beanName);

	// 检查此实例是否包含指定名字的并且!!!已经初始化完成的单例Bean(不支持别名查找)
	// BeanFactory#containsBean是containsSingleton(beanName) || containsBeanDefinition(beanName)
	boolean containsSingleton(String beanName);
	// 返回容器内所有单例类的名字
	String[] getSingletonNames();
	// 返回容器内注册的单例类数量
	int getSingletonCount();

	//@since 4.2 mutex:互斥量  互斥体
	Object getSingletonMutex();
}

同样的,按照它的继承结构,着重分析几个典型实现。

DefaultSingletonBeanRegistry

注意:这个和DefaultSingletonBeanRegistry不一样,这个类非常非常的重要,并且做的事情也很多。甚至认为是Spring容器 所谓的容器的核心内容。 他里面有非常多的缓存,需要解决Bean依赖问题、Bean循环引用问题、Bean正在创建中问题。。。

它继承SimpleAliasRegistry类和实现了SingletonBeanRegistry接口,因此这个类可以有别名注册的功能和单例bean注册的功能,并且他还支持注册DisposableBean实例;它依赖ObjectFactory接口和DisposableBean接口(关闭注册表时调用到了destroy方法)。

//共享bean实例的通用注册表 实现了SingletonBeanRegistry. 允许注册表中注册的单例应该被所有调用者共享,通过bean名称获得。 
// 可以注册bean之间的依赖关系,执行适当的注入、关闭顺序
// 这个类主要用作基类的BeanFactory实现, 提供基本的管理 singleton bean 实例功能
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
	
	// ==========它里面维护了非常非常多的Map、List等  这些构成了我们所谓的容器==========
	
	// 很显然:所有的单例bean最终都会到这里来
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
	//缓存了bean的name 和  ObjectFactory。  因为最终的Bean都是通过ObjectFactory的回调方法来创建的
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
	// 缓存了已经存在单例,用于解决循环依赖的方法 循环依赖
	// 是存放singletonFactory 制造出来的 singleton 的缓存早期单例对象缓存
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
	// 已经注册好的单例bean的名称们  和 singletonObjects保持同步
    private final Set<String> registeredSingletons = new LinkedHashSet<String>(256);

	// ===================以上四个缓存是这个类存放单例bean的主要Map  ===========================

	// 目前正在创建中的单例bean的名称的集合   存着正在初始化的Bean级不要再次发起初始化了 ===注意是正在===
	private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
	// 直接缓存当前不能加载的bean
	// 这个值是留给开发者自己set的,Spring自己不会往里面放值~~~~
	private final Set<String> inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

	//存放异常出现的相关的原因的集合
    private Set<Exception> suppressedExceptions;  
	//标志,指示我们目前是否在销毁单例中</span><span>  
    private boolean singletonsCurrentlyInDestruction = false;  

	// 一次性Bean  也就是说Bean是DisposableBean接口的实现
	// 实现DisposableBean接口的类,在类销毁时,会调用destroy()方法,开发人员可以重新该方法完成自己的工作
	// 目前像里添加的只有`AbstractBeanFactory#registerDisposableBeanIfNecessary`  其实还是来自于  doCreateBean方法
	private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
	private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);
		
	// 查找依赖的类   我依赖了哪些们
	private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
	//被依赖的bean key为beanName    我被哪些们依赖了
	private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);

	// 添加一个单例对象
	@Override
	public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
		
		// 此处加锁
		synchronized (this.singletonObjects) {
			Object oldObject = this.singletonObjects.get(beanName);
			
			// 注意:此处是如果此单例bean已经存在了,直接抛出异常~~~~~
			if (oldObject != null) {
				throw new IllegalStateException("Could not register object [" + singletonObject +
						"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
			}
			addSingleton(beanName, singletonObject);
		}
	}
	// 添加进去一个实例,实际上它做了好几步操作呢
	// singletonObjects和singletonFactories是对立关系  不会同时存在
	protected void addSingleton(String beanName, Object singletonObject) {
		// 注意此处继续上锁
		synchronized (this.singletonObjects) {
			// 添加进map缓存起来
			this.singletonObjects.put(beanName, singletonObject);
			// 因为已经添加进去了,所以Factories就可议移除了~~~
			this.singletonFactories.remove(beanName);
			//已经存在单例(循环依赖)也可以移除了~~~
			this.earlySingletonObjects.remove(beanName);
			// beanName放进单例注册表中  
			this.registeredSingletons.add(beanName);
		}
	}

	// 注意:它是一个protected方法,并不是接口方法。子类会向这里添加工厂的~~~
	protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		synchronized (this.singletonObjects) {
			// 首先判断一下:这个bean没有被产生才需要添加工厂,否则啥都不做~~~
			//  判断singletonObjects内名字为beanName是否被占用,若没有,进行注册操作  
			if (!this.singletonObjects.containsKey(beanName)) {
				this.singletonFactories.put(beanName, singletonFactory);
				//已经存在单例(循环依赖)也可以移除了~~~ 
				this.earlySingletonObjects.remove(beanName);
				// 注意注意注意:此处beanName也缓存了哦~~~一定要注意
				this.registeredSingletons.add(beanName);
			}
		}
	}

	// SingletonBeanRegistry接口的getSingleton方法的实现 
	@Override
	@Nullable
	public Object getSingleton(String beanName) {
		return getSingleton(beanName, true);
	}
	// allowEarlyReference:是否要创建早期引用
	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 先根据这个beanName去查找,找到value值
		Object singletonObject = this.singletonObjects.get(beanName);
	
		// 此处:如果此单例不存在,也不要立马就返回null了  还有工作需要处理呢
		// 这里的条件是:如果单例不存在,并且并且这个bean正在chuangjianzhong~~~(在这个singletonsCurrentlyInCreation集合了,表示它正在创建中) 
		// 什么时候放进这个集合表示创建中呢?调用beforeSingletonCreation()方法,因为他是protected方法,所以只允许本类和子类调用~
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				// 这里再去earlySingletonObjects去看一下,看是否有呢   如果有直接返回即可
				singletonObject = this.earlySingletonObjects.get(beanName);
	
				// 如果还未null,并且 并且allowEarlyReference是允许的  也就是说是允许创建一个早期引用的(简单的说就是先可以把引用提供出去,但是并还没有完成真正的初始化~~~~)
				// 这里ObjectFactory就发挥很大的作用了~~~
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					// 若有对应的ObjectFactory 那就可以继续处理
					// 备注:singletonFactories这个Map只有调用`addSingletonFactory()`方法的时候才往里添加
					// 它是一个protected方法,目前Spring还只有在`AbstractAutowireCapableBeanFactory#doCreateBean`里有过调用
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						// 注意此处:把生产出来的放进earlySingletonObjects里面去,表示生产出来了一个引用
						this.earlySingletonObjects.put(beanName, singletonObject);
						// 然后把nFactories可以移除了,因为引用已经产生了~~~
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}
	
	// 这个方法蛮重要的。首先它不是接口方法,而是一个单纯的public方法~~~
	// 它的调用处只有一个地方:AbstractBeanFactory#doGetBean  在真正 `if (mbd.isSingleton()) { sharedInstance = getSingleton(...) }`
	// 它第二个参数传的是ObjectFactory~~~~~~~实现有创建Bean实例的逻辑~~~
	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		// 在锁内工作~~~~
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			// 很显然如果都不为null了,那还做什么呢  直接返回吧
			if (singletonObject == null) {
				// 如果目前在销毁singellton 那就抛异常呗~~~~
				if (this.singletonsCurrentlyInDestruction) {
					//  抛异常
				}
				// 标记这个bean正在被创建~~~~
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				
				try {
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				} catch (IllegalStateException ex) {
					... // 省略	
				} finally {
					// 释放这个状态  说明这个bean已经创建完成了
					afterSingletonCreation(beanName);
				}
			
				// 如果是新创建了  这里执行一下添加  缓存起来~~~~
				// 如果是旧的  是不用添加的~~~~
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

	// 这两个方法 一个在Bean创建开始之前还行。一个在创建完成后执行 finally里执行

	// 表示;beforeSingletonCreation()方法用于记录加载的状态  表示该Bean当前正在初始化中~~~
	// 调用this.singletonsCurrentlyInCreation.add(beanName)将当前正要创建的bean记录在缓存中,这样便可以对循环依赖进行检测啦
	// afterSingletonCreation显然就是
	protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}
	protected void afterSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
			throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
		}
	}

	// 直接检查 singleton object 存储器了,其他的存储器不做检查
	@Override
	public boolean containsSingleton(String beanName) {
		return this.singletonObjects.containsKey(beanName);
	}
	@Override
	public String[] getSingletonNames() {
		synchronized (this.singletonObjects) {
			return StringUtils.toStringArray(this.registeredSingletons);
		}
	}
	@Override
	public int getSingletonCount() {
		synchronized (this.singletonObjects) {
			return this.registeredSingletons.size();
		}
	}
	// 这个方法  只是简单的把这个Map返回出去了~~~~~
	@Override
	public final Object getSingletonMutex() {
		return this.singletonObjects;
	}
}

getSingleton的时候,spring的默认实现是,先从 singleton object 的存储器中去寻找,如果找不到,再从 early singleton object 存储器中寻找,再找不到,那就在寻找对应的 singleton factory,造出所需的 singleton object,然后返回

管理bean的依赖问题, 使用如下三个属性进行管理:

Map<String, Set<String>> containedBeanMap // 依赖的bean name为key , 就是依赖类 -> 查找 被依赖的类
Map<String, Set<String>> dependentBeanMap // 依赖的原始bean name为key
Map<String, Set<String>> dependenciesForBeanMap // 被依赖的bean name为key

这就是DefaultSingletonBeanRegistry,它实现了接口的所有方法。它还有实现很多Bean依赖之间关系的逻辑,此处不展开了~~~

DefaultSingletonBeanRegistry既有管理SingletonBean 的功能,又提供了别名的功能DefaultSingletonBeanRegistry是一个通用的存储共享bean实例的地方,通过bean的名字获得bean。同时,它也给提供一次性bean的注册功能

FactoryBeanRegistrySupport

FactoryBeanRegistrySupport是 工厂bean(FactoryBean)注册的一个超类,它是一个抽象类,内部多了一个成员变量:

private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);

它负责缓存由工厂bean产生的单例bean。它还额外增加了一些方法,用于通过 工厂bean获取 工厂bean所创建的对象的一些信息,下面看看源码:

// 可议看到它是一个首相类,并且继承自`DefaultSingletonBeanRegistry `
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {

	private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);

	// 获取factoryBean的类型。  它相对于factoryBean.getObjectType()主要是增加了一些安全校验   这里相关源码我都省略了
	@Nullable
	protected Class<?> getTypeForFactoryBean(final FactoryBean<?> factoryBean) {
		return factoryBean.getObjectType();
	}
	// 直接从缓存中拿  工厂Bean制造出来的对象
	@Nullable
	protected Object getCachedObjectForFactoryBean(String beanName) {
		return this.factoryBeanObjectCache.get(beanName);
	}
	
	// 核心方法:从工厂Bean里面拿到这个对象~
	protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
		// 是单例,并且已经存在该beanName了
		if (factory.isSingleton() && containsSingleton(beanName)) {
			
			// 仍然采用这把锁  互斥锁
			synchronized (getSingletonMutex()) {
				Object object = this.factoryBeanObjectCache.get(beanName);
				// 显然只有factoryBeanObjectCache里不存在此bean,才需要继续去工厂Bean里面找~
				if (object == null) {
					// 其实就基本相当于 factory.getObject()
					object = doGetObjectFromFactoryBean(factory, beanName);
					...
					this.factoryBeanObjectCache.put(beanName, object);
				}
				return object;
			}
		}
		...
	}


	/**
	 * Post-process the given object that has been obtained from the FactoryBean.
	 * The resulting object will get exposed for bean references.
	 * <p>The default implementation simply returns the given object as-is.
	 * Subclasses may override this, for example, to apply post-processors.
	 * @param object the object obtained from the FactoryBean.
	 * @param beanName the name of the bean
	 * @return the object to expose
	 * @throws org.springframework.beans.BeansException if any post-processing failed
	 */
	protected Object postProcessObjectFromFactoryBean(Object object, String beanName) throws BeansException {
		return object;
	}

	/**
	 * Overridden to clear the FactoryBean object cache as well.
	 */
	@Override
	protected void removeSingleton(String beanName) {
		synchronized (getSingletonMutex()) {
			super.removeSingleton(beanName);
			this.factoryBeanObjectCache.remove(beanName);
		}
	}
	// 这里复写了父类的方法。注意:调用了super的方法
	@Override
	protected void clearSingletonCache() {
		synchronized (getSingletonMutex()) {
			super.clearSingletonCache();
			this.factoryBeanObjectCache.clear();
		}
	}
	// 获取安全上下文
	protected AccessControlContext getAccessControlContext() {
		return AccessController.getContext();
	}

}

它有个唯一子类:AbstractBeanFactory,它可议说是整个BeanFactory实现的大脑。因为AbstractBeanFactory继承自FactoryBeanRegistrySupport,所以不仅仅有注册单例Bean的能力,也有注册工厂Bean的能力了。

到后面的抽象子类AbstractAutowireCapableBeanFactory,再到实现类DefaultListableBeanFactory就都有这个功能了。

这里面还有一个继承分支:ConfigurableBeanFactory有直接继承此接口。同时AbstractBeanFactoryConfigurableListableBeanFactory也都继续继承了ConfigurableBeanFactory

而对于ConfigurableListableBeanFactory它只有唯一实现类:DefaultListableBeanFactory

手动注册单例Bean的方式

基本上我们只要能拿到Bean工厂(一般都可以通过注入的方式拿到),就可以调用SingletonBeanRegistry的相关方法对容器内的单例Bean做一些列的操作~~~

总结

仔细想想,为什么这个类DefaultSingletonBeanRegistry要使用三个存储器呢:

  1. singletonObjects:就是直观的存储着 singleton 的
  2. singletonFactories:是存储的制造 singleton 的工厂
  3. earlySingletonObject:这是一个 早期 singletonFactory 制造出来的 singleton 的缓存

这样处理的好处,是解决依赖、循环依赖的问题。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏知了一笑

Java描述设计模式(07):适配器模式

缺省(接口)适配(Default Adapter)模式为一个接口提供缺省实现,这样子类型可以从这个缺省实现进行扩展,而不必从原有接口进行扩展。

6420
来自专栏kubernetes中文社区

不管你是开发还是运维,微服务这些你得知道!

这几年在Java工程师招聘时,会看到很多人的简历都写着使用了Spring Cloud做微服务实现,使用Docker做自动化部署,并且也会把这些做为自己的亮点。而...

17610
来自专栏全栈开发之路

SpringMVC学习

Spring MVC是一个基于MVC架构的用来简化web应用程序开发的应用开发框架,它是Spring的一部分,它和Struts2一样都属于表现层的框架。

7710
来自专栏java达人

透过源码学习设计模式5—状态模式和Spring状态机

状态模式即允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类,换句话说状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属...

73520
来自专栏吟风者

Spring Boot 自定义事件

系统启动时,执行顺序为:application starting > application prepared > application ready

9810
来自专栏JAVA葵花宝典

那些年,我们见过的 Java 服务端乱象

移动互联网的快速发展,出现了许多新机遇,很多创业者伺机而动;随着行业竞争加剧,互联网红利逐渐消失,很多创业公司九死一生。笔者在初创公司摸爬滚打数年,接触了各式各...

9610
来自专栏全栈开发之路

SSH架构/spring-security安全认证/LDAP账号打通

参考:https://blog.csdn.net/shan9liang/article/details/8803989

10330
来自专栏后端开发你必须学会的干货

SpringIoC和SpringMVC的快速入门

IoC和AOP是Spring框架的两大特性,IoC和MVC的流程密不可分,可以看作是面向对象编程的实现;而AOP特性则是面向切面编程的体现,也是前者的补充,所以...

6420
来自专栏Java研发军团

SpringBoot注解大全,收藏一波!!!

@SpringBootApplication:包含了@ComponentScan、@Configuration和@EnableAutoConfiguration...

10140
来自专栏吉林乌拉

Spring Boot入门篇

很长时间不写博客了,究其原因则是这几个月工作及生活都发生了很多事情,导致不得分心处理这些。最近难得忙里偷闲,决定还是继续更新吧。毕竟一件事情做久了,如果突然中断...

10350

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励