Spring FactoryBean 缓存

相关文章web

读完这篇文章你将会收获到spring

  • DisposableBeandestroy 执行
  • Spring 如何缓存 FactoryBean 产生的单例 bean
  • 如何解决 FctoryBeangetObject 的循环依赖

很少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 接口的方法ide

@Override
public final Object getSingletonMutex() {  return this.singletonObjects; } 复制代码

返回第一级缓存这个 Map 做为同步锁的对象,子类须要使用 synchronized 的时候就要获取这个同步锁对象post

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 是同一个对象this

而后加入到第一级缓存中并注册这个 beanName、而后从第二级第三级缓存中移除这个 beanNamespa

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 注册的 beanFactoryBean 的话、那么这个 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 的状况呢 ?

咱们先设定、FactoryBeanbeanNamebeanA 吧,还有一个普通的 beanB、它是依赖 beanA 的。

那么假如我在 beanAgetObject 的方法里面调用 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> 复制代码
image-20200607175242277
image-20200607175242277

好啦,但愿你也有所收获喔

此次必定?
此次必定?
相关文章
相关标签/搜索