读完这篇文章你将会收获到
DisposableBean
的destroy
执行Spring
如何缓存FactoryBean
产生的单例bean
- 如何解决
FctoryBean
的getObject
的循环依赖
不多BB , 上图
SingletonBeanRegistry
今天我们来扯一下 SingletonBeanRegistry
, 我们向 Spring
容器注册 bean
的时候就是用到这个接口的方法
public interface SingletonBeanRegistry { void registerSingleton(String beanName, Object singletonObject); @Nullable Object getSingleton(String beanName); boolean containsSingleton(String beanName); String[] getSingletonNames(); int getSingletonCount(); // 并发控制 现在的实现都是 使用 第一级缓存的 singletonObjects 对象 Object getSingletonMutex(); } 复制代码
DefaultSingletonBeanRegistry
我们先看看这个接口的默认实现类 DefaultSingletonBeanRegistry
我们前几篇文章说的三级缓存就是在这里定义的
/** * 第一级缓存 */ Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); /** * 第三级缓存 */ Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); /** * 第二级缓存 **/ Map<String, Object> earlySingletonObjects = new HashMap<>(16); /** * 只要是加入到三级缓存中到 beanName 都会被注册到这个 set 无论是第三级缓存或者是第一级缓存 */ Set<String> registeredSingletons = new LinkedHashSet<>(256); /** * 正在处于一个创建状态的 bean、存放的是 beanName */ Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); /** * 不用在创建的时候检查循环依赖的 beanName 名称 */ Set<String> inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); /** * 收集一些并不影响主流程的异常,可用于后续再次抛出的时候做一些关联,或者只是收集而不抛出 */ @Nullable Set<Exception> suppressedExceptions; /** * 表明是否正处于一个正在销毁 singleton 的过程 */ boolean singletonsCurrentlyInDestruction = false; /** * beanName:需要执行destroyMethod 的bean */ Map<String, Object> disposableBeans = new LinkedHashMap<>(); /** * * key: 外部的 beanName * value 外部 bean 依赖的一些内部 bean */ Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16); /** * key bean name * value 所有依赖 key的 bean */ Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64); /** * key bean name * value 这个key 所依赖的bean */ Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64); 复制代码
上面除了三级缓存以外,还有其他一些属性定义
getSingletonMutex
我们再来看看其如何实现 SingletonBeanRegistry
接口的方法
@Override public final Object getSingletonMutex() { return this.singletonObjects; } 复制代码
返回第一级缓存这个 Map
作为同步锁的对象,子类需要使用 synchronized
的时候就要获取这个同步锁对象
registerSingleton
@Override public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException { Assert.notNull(beanName, "Bean name must not be null"); Assert.notNull(singletonObject, "Singleton object must not be null"); synchronized (this.singletonObjects) { Object oldObject = this.singletonObjects.get(beanName); if (oldObject != null) { throw new IllegalStateException("xxxxx"); } addSingleton(beanName, singletonObject); } } 复制代码
protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { // 加入到第一级缓存 this.singletonObjects.put(beanName, singletonObject); // 从第三级缓存中移除 this.singletonFactories.remove(beanName); // 从第二级缓存中移除 this.earlySingletonObjects.remove(beanName); // 注册这个beanName this.registeredSingletons.add(beanName); } } 复制代码
先是对参数的检验、然后使用同步锁,再判断该 beanName
是否已经在第一级缓存中、如果已经存在了、则抛出异常,不管在缓存中的 bean
是否跟参数中的 singletonObject
是同一个对象
然后加入到第一级缓存中并注册这个 beanName
、然后从第二级第三级缓存中移除这个 beanName
getSingleton
@Override @Nullable public Object getSingleton(String beanName) { // allowEarlyReference 可以返回第三级缓存的对象 return getSingleton(beanName, true); } 复制代码
@Nullable 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 factory 创建出的 bean if (singletonObject == null && allowEarlyReference) { // 获取缓存中的 ObjectFactory ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); // 将对象缓存到 earlySingletonObject中 this.earlySingletonObjects.put(beanName, singletonObject); // 从工厂缓冲中移除 this.singletonFactories.remove(beanName); } } } } return singletonObject; } 复制代码
上面这个方法我们已经见过了很多次 , 分别从第一级而后第二级、再到第三级获取 bean
、如果从第三级的话、那么就将其升级到第二级并从第三级移除。
其他
下面这三个方法就比较简单了、不做介绍了、相信大家都能看一眼就知道干啥了
@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(); } } 复制代码
我们再来看一个往第三级缓存中存放 ObjectFactory
的实现
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } } 复制代码
我们再来看看注册 DisposableBean
的方法吧
public void registerDisposableBean(String beanName, DisposableBean bean) { synchronized (this.disposableBeans) { this.disposableBeans.put(beanName, bean); } } 复制代码
而执行 destroy
的话内容比较长
protected void destroyBean(String beanName, @Nullable DisposableBean bean) { Set<String> dependencies; synchronized (this.dependentBeanMap) { // 找出所有依赖这个 beanName 的其他 bean dependencies = this.dependentBeanMap.remove(beanName); } if (dependencies != null) { for (String dependentBeanName : dependencies) { // 最终还是回调到这个方法 destroySingleton(dependentBeanName); } } // 如果 DisposableBean 不为null if (bean != null) { try { bean.destroy(); } catch (Throwable ex) { } } // 处理内部 bean 了 Set<String> containedBeans; synchronized (this.containedBeanMap) { // 找出这个 beanName 的所有内部 bean containedBeans = this.containedBeanMap.remove(beanName); } if (containedBeans != null) { for (String containedBeanName : containedBeans) { destroySingleton(containedBeanName); } } // dependentBeanMap key 为被依赖者、value 为依赖 key 的 bean // 这一步的操作就是因为 beanName 可能存在 别人的 value 中、这个时候我们也要去清理掉 // 第一步的时候已经清除了 key 为 beanName 的情况 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); if (dependenciesToClean.isEmpty()) { it.remove(); } } } // dependenciesForBeanMap key 为依赖者,value 为 key 依赖的 bean 集合 this.dependenciesForBeanMap.remove(beanName); } 复制代码
FactoryBeanRegistrySupport
我们在来看看这个类,这个类是干啥的
当我们向 Spring
注册的 bean
是 FactoryBean
的话、那么这个 FactoryBean
当然是存放在三级缓存中啦、但是这个 FactoryBean
产生的 bean
也得有个地方缓存起来吧(如果是个单例的话,是吧)
/** * beanName: bean(factory bean 创建出来的) * Cache of singleton objects created by FactoryBeans: FactoryBean name to object. */ private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16); 复制代码
我们这里介绍一个上几篇文章说过的一个方法、但是其中的妙处、我现在算是看懂了
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { // 为单例模式且 beanName 已经注册了在 Spring 中 if (factory.isSingleton() && containsSingleton(beanName)) { synchronized (getSingletonMutex()) { // 从缓存中获取指定的 bean(这个bean 是从 factory bean 创建出来的) Object object = this.factoryBeanObjectCache.get(beanName); if (object == null) { // 为空则从 factory bean 中获取对象 object = doGetObjectFromFactoryBean(factory, beanName); Object alreadyThere = this.factoryBeanObjectCache.get(beanName); if (alreadyThere != null) { // 已经存放到 缓存中了、后续的操作就不需要了 object = alreadyThere; } else { // 需要做一些后置处理 if (shouldPostProcess) { // 如果这个bean正在创建中、 if (isSingletonCurrentlyInCreation(beanName)) { // Temporarily return non-post-processed object, not storing it yet.. return object; } // 前置处理 主要是将这个bean 加入到正在创建中的队列 singletonsCurrentlyInCreation beforeSingletonCreation(beanName); try { // 对 从 factoryBean 获取的对象进行后处理 // 生成对象将暴露给 bean 引用 并回调 beanPostProcessor object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", ex); } finally { // 后置处理 将其从 singletonsCurrentlyInCreation 移除 afterSingletonCreation(beanName); } } // 他的 factory bean 已经存在 缓存中了、那么这个 factory bean 产生的bean 应该也要缓存一下 if (containsSingleton(beanName)) { this.factoryBeanObjectCache.put(beanName, object); } } } return object; } } else { // 非单例 ....... } } 复制代码
其实有个挺让人迷惑的一个地方
Object object = this.factoryBeanObjectCache.get(beanName); if (object == null) { // 为空则从 factory bean 中获取对象 object = doGetObjectFromFactoryBean(factory, beanName); Object alreadyThere = this.factoryBeanObjectCache.get(beanName); if (alreadyThere != null) { // 已经存放到 缓存中了、后续的操作就不需要了 object = alreadyThere; } 复制代码
我上一步已经判断了 factoryBeanObjectCache
里面没有这个 beanName
了,而 doGetObjectFromFactoryBean
这个方法只是单纯的去调用 FactoryBean
里面的 getObject
方法、并无其他操作,那么为啥 alreadyThere
它会有不为 null
的情况呢 ?
我们先设定、FactoryBean
的 beanName
为 beanA
吧,还有一个普通的 beanB
、它是依赖 beanA
的。
那么假如我在 beanA
的 getObject
的方法里面调用 getBean
方法获取 beanB
, 这个时候就构成了一个循环依赖,当创建好 beanB
的时候、进行属性注入,发现要 beanA
、这个时候就会继续走上面的流程、也就是 alreadyThere == null
的情况、这个时候会将 beanA
放置到 factoryBeanObjectCache
中、最终创建好了 beanB
, 返回到 doGetObjectFromFactoryBean
这里的方法、这个时候就会产生了两个 beanA
(如果你正常的在 getObject
new
某个对象的话) , 是不是就出现了 alreadyThere
不为 null
的情况了
来个 demo
看看吧
public class CatFactoryBean implements FactoryBean<Cat>, BeanFactoryAware { private BeanFactory beanFactory; @Override public Cat getObject() throws Exception { beanFactory.getBean("chicken"); return new Cat(); } @Override public Class<?> getObjectType() { return Cat.class; } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } } 复制代码
public class Chicken { private Cat cat; public Chicken() { } public void destroyMethod() { System.out.println("destroy method"); } public void setCat(Cat cat) { this.cat = cat; } } 复制代码
public static void main(String[] args) { Resource resource = new ClassPathResource("coderLi.xml"); DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory); xmlBeanDefinitionReader.loadBeanDefinitions(resource); Object cat = defaultListableBeanFactory.getBean("cat"); defaultListableBeanFactory.destroySingletons(); } 复制代码
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="com.demo.data.Chicken" id="chicken" destroy-method="destroyMethod"> <property name="cat" ref="cat"/> </bean> <bean class="com.demo.data.CatFactoryBean" id="cat"/> </beans> 复制代码