读完这篇文章你将会收获到web
getBean
方法中,
Spring
处理别名以及
factoryBean
的
name
Spring
如何从多级缓存中根据
beanName
获取
bean
Spring
如何处理用户获取普通
bean
和
factoryBean
从 Spring 容器的初始化 中,咱们了解到 Spring
是如何将 XML
文件转换为 BeanDefinition
并注册到 BeanDefinitionRegstry
。spring
今天咱们一块儿继续学习 Spring
的 bean
加载缓存
public static void main(String[] args) {
Resource resource = new ClassPathResource("coderLi.xml"); DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory); xmlBeanDefinitionReader.loadBeanDefinitions(resource); } 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd"> <beans> <bean class="com.demo.data.Person"> <description> 微信搜一搜:CoderLi </description> </bean> </beans> 复制代码
熟悉的味道、熟悉的配方
微信
咱们能够在上面的 Java 代码中加入如下的代码并发
System.out.println(defaultListableBeanFactory.getBean("com.demo.data.Person#0"));
复制代码
咱们根据默认的 beanName 从 Spring 容器中获取 Person 这个 bean 对象,固然咱们可使用默认的别名获取app
System.out.println(defaultListableBeanFactory.getBean("com.demo.data.Person"));
复制代码
对 Spring 别名不熟悉的朋友能够先看下个人这一篇文章 Spring-AliasRegistry编辑器
咱们直接进入到 AbstractBeanFactory#getBean(String)
方法中, AbstractBeanFactory
为 DefaultListableBeanFactory
的父类ide
@Override
public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } 复制代码
能够看到 do
开头的才是真正干活的老大 , AbstractBeanFactory#doGetBean
源码分析
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { // 找到这个参数的 bean name final String beanName = transformedBeanName(name); Object bean; // Eagerly check singleton cache for manually registered singletons. // 检查缓冲中是否有这个bean、spring中只是保存单例的bean Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { // 这里被我删除了一些spring 的log // 处理一下 factory bean 的状况、包括从 factory beans 的缓存中获取、或者从新调用 factory bean 的 get bean 方法 包括一些回调 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } .......... ........... 复制代码
由于这个方法实在太长了因此截取一部分、咱们一步步来分析post
transformedBeanName(name)
这个方法就是将咱们的 name 转换为真正的 beanName,由于咱们传进来的参数多是一个 alias 或者多是一个 factoryBean 的 beanName (前缀为&),而咱们在 Spring 中存放的 factoryBean 的 beanName 是没有 & 前缀的,因此须要处理掉这个前缀
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name)); } public static String transformedBeanName(String name) { Assert.notNull(name, "'name' must not be null"); // 是不是一个 factory bean 、若是不是的话就直接返回 if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { return name; } // 若是是的话就将其前缀 & 去掉 return transformedBeanNameCache.computeIfAbsent(name, beanName -> { do { beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()); } while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)); return beanName; }); } /** * 找到这个别名的最终的 bean Name、若是没有的话( * 也就是说参数中的name 就是人家的 bean name 那么就直接返回这个 参数就好了) * */ public String canonicalName(String name) { String canonicalName = name; // Handle aliasing... String resolvedName; do { resolvedName = this.aliasMap.get(canonicalName); if (resolvedName != null) { canonicalName = resolvedName; } } while (resolvedName != null); return canonicalName; } 复制代码
让咱们再看看下一个方法 DefaultSingletonBeanRegistry#getSingleton(String)
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; } 复制代码
上面的代码就是 Spring 尝试从缓存中加载单例。单例在 Spring 的同一个容器中只会被建立一次,后续再获取 bean,就直接从缓存中取了。
在介绍这个方法以前、咱们先认识下 DefaultSingletonBeanRegistry
这个类里面的成员变量吧
Map<String, Object> singletonObjects
这个很好理解、 key 就是 beanName ,value 就是 bean 实例
Map<String, ObjectFactory<?>> singletonFactories
key 为 beanName,value 为建立 bean 的工厂
Map<String, Object> earlySingletonObjects
key 为 beanName ,value 为 bean。可是和
singletonObjects
不一样的是,bean 被加入到
earlySingletonObjects
的时候、这个 bean 仍是处于一种建立中的状态,目的也很简单、Spring 用来解决某些场景下的循环依赖
咱们再回到代码中、分析一下它的逻辑
相似多级缓存的设计
在上面的方法中咱们看到 isSingletonCurrentlyInCreation(beanName)
这个方法、
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName); } 复制代码
singletonsCurrentlyInCreation
这个 Set 中,当建立一个 bean 以前会将其 对应的 beanName 放置到这个 Set 中、后面的分析会涉及到、这里先提一嘴
咱们第一次获取这个 bean 、返回为 null 是正常的
那假如咱们在代码中 getBean 了两次
defaultListableBeanFactory.getBean("com.demo.data.Person#0")
defaultListableBeanFactory.getBean("com.demo.data.Person#0") 复制代码
那么针对第二次的调用、返回的值就不是为 null 了
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) { // 处理一下 factory bean 的状况、包括从 factory beans 的缓存中获取、或者从新调用 factory bean 的 get bean 方法 包括一些回调 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } 复制代码
咱们先假设 sharedInstance 不为 null 也就是咱们第二次调用 getBean
,咱们进入到 getObjectForBeanInstance
方法中
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { // 我王大锤就是想要一个 factory bean if (BeanFactoryUtils.isFactoryDereference(name)) { // 若是这个是 NullBean 类型、表示这是一个 null 的 instance、直接返回 if (beanInstance instanceof NullBean) { return beanInstance; } // 获取到的 beanInstance 不是一个 factory、可是你tm name 又带有这个 & 很迷惑啊兄弟 if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass()); } if (mbd != null) { mbd.isFactoryBean = true; } return beanInstance; } // 王大锤不想要factory bean、而且spring 也帮他找到了一个普通的 bean、直接返回 if (!(beanInstance instanceof FactoryBean)) { return beanInstance; } // 王大锤要的是一个普通的bean 、可是spring 给他找到了一个 factory的bean、那么spring 是否是要作一些额外的处理 给王大锤返回一个普通的bean Object object = null; if (mbd != null) { mbd.isFactoryBean = true; } else { // 从缓存中 看看有没有 object = getCachedObjectForFactoryBean(beanName); } // 若是 bean factory 中仍是没有 if (object == null) { // Return bean instance from factory. FactoryBean<?> factory = (FactoryBean<?>) beanInstance; // 从 缓存中拿到 bean definition if (mbd == null && containsBeanDefinition(beanName)) { mbd = getMergedLocalBeanDefinition(beanName); } // 是不是用户定义的仍是程序自己须要建立的bean boolean synthetic = (mbd != null && mbd.isSynthetic()); object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; } 复制代码
咱们按步骤分析下上面的代码
getBean(name)
中的 name 若是包含前缀 & ,表面咱们是想要从 Spring 中获取一个 FactoryBean ,那么咱们就要判断咱们从缓存中获取的 beanInstance 是不是 一个 FactoryBean 、若是是的话就直接返回不是的话就要抛出异常了
getObjectFromFactoryBean
方法中了
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// 为单例模式且缓存中存在 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)) { 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 = doGetObjectFromFactoryBean(factory, beanName); if (shouldPostProcess) { try { // object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex); } } return object; } } 复制代码
啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊、代码很长长长..........咱们一点点来分析
第一步就是判断这个 factoryBean 是不是单例、若是不是的话,而且是用户本身定义的 bean、那么就须要调用 postProcessObjectFromFactoryBean
方法去作一个后续的处理
BeanPostProcessor
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; } 复制代码
若是这 beanFactory 是一个单例,那咱们就看看 factoryBeanObjectCache ( key 是 beanName,value 是 beanFactory 产生出来的 object 也是咱们正要获取的 bean ) 这个 Map 中是否存在这个 beanName 这个 bean
若是存在的话、就直接返回、若是不存在的话、那就 doGetObjectFromFactoryBean
,从这个方法中使用 FactoryBean#getObject 产生 bean
其实下面这段代码确实让人看不懂哦
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) { // 已经存放到 缓存中了、后续的操做就不须要了 object = alreadyThere; } 复制代码
而后咱们看到 beforeSingletonCreation
这个方法、就是上面 getSingleton
中 isSingletonCurrentlyInCreation
判断一个 bean 是否处于正在建立中
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } } public boolean isSingletonCurrentlyInCreation(String beanName) { return this.singletonsCurrentlyInCreation.contains(beanName); } 复制代码
而后又调用到 postProcessObjectFromFactoryBean
方法、最终回调的就是咱们经常使用的一个接口 BeanPostProcessor
最好调用 afterSingletonCreation(beanName)
方法、将其从 正在建立中的 bean 的集合中移除、最后的最后、将其加入到 factoryBeanObjectCache
集合中
今天咱们就先分析到这里、后续的话咱们在后面的文章继续探讨。今天咱们大体分析了 getBean 里面的这三个方法
singletonObjects
中看看有没有
earlySingletonObjects
singletonFactories
中看看有没有
&
)、那么咱们直接返回
BeanPostProcessor
上面的三个方法大体流程就是这样、但愿对各位有帮助
有兴趣进入群聊、一块儿交流一块儿划水