前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【小家Spring】Spring的单例Bean定注册中心SingletonBeanRegistry详解

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

作者头像
YourBatman
发布2019-09-03 15:30:52
8440
发布2019-09-03 15:30:52
举报
文章被收录于专栏:BAT的乌托邦BAT的乌托邦
前言

上一篇重点介绍了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 的缓存

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年04月26日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • SingletonBeanRegistry
    • DefaultSingletonBeanRegistry
      • 手动注册单例Bean的方式
        • 总结
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档