Spring读源码系列04----bean的加载---上
Posted 大忽悠爱忽悠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring读源码系列04----bean的加载---上相关的知识,希望对你有一定的参考价值。
Spring读源码系列04----bean的加载---上
- Bean的加载
- AbstractBeanFactory#getBean(String name)----根据名字获取bean
- FactoryBean的使用
- 缓存中获取单例bean
- 从Bean实例中获取对象---FactoryBean
- 获取单例
- DefaultSingletonBeanRegistry#getSingleton(String beanName, ObjectFactory<?> singletonFactory)-----加载单例bean
- DefaultSingletonBeanRegistry#beforeSingletonCreation---记录当前正要创建的bean到singletonsCurrentlyInCreation缓存中
- DefaultSingletonBeanRegistry#afterSingletonCreation---从singletonsCurrentlyInCreation缓存中移除当前bean正在加载的状态记录
- DefaultSingletonBeanRegistry#addSingleton---新创建的bean加入单例bean缓冲池中
- ObjectFactory#getObject---调用ObjectFactory的getObject方法新创建一个单例bean实例
- 准备创建bean
阅读本系列之前,建议先从本专栏的两个不同视角学习spring的系列作为入门学习点(这两个系列会持续更新),先大体理解spring的架构设计与精髓,然后再来阅读本系列,深入源码分析,而不再纸上谈兵。
从整体来学spring系列文章:
Spring复杂的BeanFactory继承体系该如何理解? ----上
Spring复杂的BeanFactory继承体系该如何理解? ----中
Spring复杂的BeanFactory继承体系该如何理解?—中下
Spring复杂的BeanFactory继承体系该如何理解?—下
该系列持续更新中…
独特视角学习spring系列文章:
该系列持续更新中…
本系列文章:
Spring读源码系列03----自定义标签解析(待续中)
Bean的加载
<bean id="peo" class="org.deepSpring.Peo"/>
public class DeepSpringStudy
public static void main(String[] args)
ClassPathResource classPathResource = new ClassPathResource("bean.xml");
XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(classPathResource);
Peo peo = (Peo) xmlBeanFactory.getBean("Peo");
peo.show();
public class XmlBeanFactory extends DefaultListableBeanFactory
正式开始之前,大家心中要有这幅继承图,不然后面会比较懵逼
AbstractBeanFactory#getBean(String name)----根据名字获取bean
AbstractBeanFactory#doGetBean—真正干活的方法
/**
* Return an instance, which may be shared or independent, of the specified bean.
*/
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException
//提取对应的beanName
//别名到真实的beanName,去掉FactoryBean的&
String beanName = transformedBeanName(name);
Object beanInstance;
//检查缓存中或者实例工厂中是否有对应的实例
//为什么首先会使用这段代码呢?
//因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖
//spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光
//(这里ObjectFactory是啥东西,后面会详细分析)
//也就是将ObjectFactory加入到缓存中,一旦下个bean创建时候需要依赖上个bean则直接使用ObjectFactory
//直接尝试从缓存获取或者singletonFactories中的ObjectFactory获取
Object sharedInstance = getSingleton(beanName);
//如果从缓存或者对象工厂获取到了对应的实例对象,并且此时构造参数为空--->因为这里必须是无参构造进行创建的
if (sharedInstance != null && args == null)
if (logger.isTraceEnabled())
if (isSingletonCurrentlyInCreation(beanName))
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
else
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
//getObjectForBeanInstance这个干啥的呢?
//因为有时候存在诸如BeanFactory的情况,并不是直接返回实例本身而是返回指定方法返回的实例
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
//如果缓存或者对象工厂中没有的话
else
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
//只有在单例情况下才会去尝试解决循环依赖,原型模式下,如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还没有创建完的时候因为对于B的创建再次返回创建A,造成循环依赖,也就是下面判断的情况
//isPrototypeCurrentlyInCreation--->返回指定的原型bean当前是否正在创建中
//其实内部会有一个ThreadLocal<Object> prototypesCurrentlyInCreation属性记录当前线程正在创建的原型bean
if (isPrototypeCurrentlyInCreation(beanName))
throw new BeanCurrentlyInCreationException(beanName);
// Check if bean definition exists in this factory.
//获取父容器---这里parentBeanFactory可以在创建BeanFactory通过参数传入
//如果没有设置,默认为NULL
BeanFactory parentBeanFactory = getParentBeanFactory();
//如果存在父容器并且
//containsBeanDefinition最终调用的是DefaultListableBeanFactory的
//this.beanDefinitionMap.containsKey(beanName);
//这个beanDefinitionMap在xml解析过程中每次得到一个BeanDefinition都会往里面注册一个
//总结:containsBeanDefinition判断当前容器中是否存在beanName对应的BeanDefinition
if (parentBeanFactory != null && !containsBeanDefinition(beanName))
//能进入该判断条件说明在当前容器中找不到,并且又存在父容器,所以尝试去父容器中寻找
// Not found -> check parent.
//获取原始的beanName---如果是别名的话,变为别名指向的beanName,如果要获取的是FactoryBean的name的话,也需要进行特殊处理
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory)
//去父容器中找---一般都是会继承AbstractBeanFactory
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
else if (args != null)
//携带构造参数进行查找
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
else if (requiredType != null)
//携带参数class类型进行查找
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
else
//直接按照名字查找
return (T) parentBeanFactory.getBean(nameToLookup);
//如果不是仅仅做类型检查则是创建bean,这里要进行记录
if (!typeCheckOnly)
//将指定的 bean 标记为已创建(或即将创建)。 这允许 bean 工厂优化其缓存以重复创建指定的 bean。
//这里是用一个Set<String> alreadyCreated集合来存放正在创建中的bean
markBeanAsCreated(beanName);
//我猜测应该是用来追踪状态的
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try
//增加追踪信息
if (requiredType != null)
beanCreation.tag("beanType", requiredType::toString);
//将存储XML配置文件的GenericBeanDefinition转换为RootBeanDefinition,如果指定beanName是子bean的话,同时还会合并父类的相关属性
//一会进行分析!!!
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
//当前RootBeanDefinition依赖的其他bean
// Guarantee initialization of beans that the current bean depends on.
//解析标签上的depends-on属性时会将解析到的beanName放入到beanDefinition中去
String[] dependsOn = mbd.getDependsOn();
//若存在依赖则需要递归实例化依赖的bean
if (dependsOn != null)
for (String dep : dependsOn)
//isDependent:如果能从dependentBeanMap集合中找到当前beanName依赖的beans集合,
//并且该集合包含了当前依赖的dep,说明出现了循环依赖
if (isDependent(beanName, dep))
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
//依赖关系注册--->dependenciesForBeanMap
registerDependentBean(dep, beanName);
try
//递归创建依赖的bean
getBean(dep);
catch (NoSuchBeanDefinitionException ex)
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
// Create bean instance.
//实例化依赖的bean后,便可以实例化mbd本身了
//singleton模式的创建
if (mbd.isSingleton())
//getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法一会进行分析
sharedInstance = getSingleton(beanName, () ->
try
//这个方法是核心
return createBean(beanName, mbd, args);
catch (BeansException ex)
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
);
//上面见过一次---如果缓存或者对象工厂有的话
//因为有时候存在诸如BeanFactory的情况,并不是直接返回实例本身而是返回指定方法返回的实例
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
// prototype模式的创建
else if (mbd.isPrototype())
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try
//这里是将当前正在创建中的PrototypeBean放入当前线程的prototypesCurrentlyInCreation--->ThreadLocal<Object>中去
//一开始当前线程只有一个正在创建的bean时,存放一个string,多余两个时,会变为set集合来存放
//当前正在创建的PrototypeBeans
beforePrototypeCreation(beanName);
//创建!!!----说明是核心方法
prototypeInstance = createBean(beanName, mbd, args);
finally
//将当前bean的创建状态从prototypesCurrentlyInCreation集合中移除掉
afterPrototypeCreation(beanName);
//因为有时候存在诸如BeanFactory的情况,并不是直接返回实例本身而是返回指定方法返回的实例
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
//如果当前bean的作用域不是单例也不是原型,那么进入下面的分支
//当然bean为其他类型
else
//在指定的scope上实例化bean
//获取当前beanDefinition绑定的scopeName
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName))
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
//从已注册的scopes集合上获取对应的scope
Scope scope = this.scopes.get(scopeName);
if (scope == null)
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
try
//调用scope的get(String name, ObjectFactory<?> objectFactory)方法来返回一个bean实例
//objectFactory是一个函数式接口,只有一个getObject方法
Object scopedInstance = scope.get(beanName, () ->
//同样也是记录当前bean的创建状态
//下面记录和移除创建状态的两个方法和Prototype使用的是一样的方法
//保存在prototypesCurrentlyInCreation中,对就是和上面Prototype一样的集合
beforePrototypeCreation(beanName);
try
//无论是什么scope,如果bean还没创建过,都需要调用createBean来创建bean实例对象
return createBean(beanName, mbd, args);
finally
//将当前bean的创建状态从prototypesCurrentlyInCreation集合中移除掉
afterPrototypeCreation(beanName);
);
//因为有时候存在诸如BeanFactory的情况,并不是直接返回实例本身而是返回指定方法返回的实例
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
catch (IllegalStateException ex)
throw new ScopeNotActiveException(beanName, scopeName, ex);
catch (BeansException ex)
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
finally
beanCreation.end();
//是否需要进行类型转换
return adaptBeanInstance(name, beanInstance, requiredType);
goGetBean方法流程小结
FactoryBean的使用
public interface FactoryBean<T>
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
//该方法可以不覆盖,则默认为单例bean
default boolean isSingleton()
return true;
举个栗子:
public class MyFactoryBean implements FactoryBean
@Override
public Object getObject() throws Exception
return new Bean();
@Override
public Class<?> getObjectType()
return Bean.class;
@Override
public boolean isSingleton()
//原本就是default方法,默认返回true
return FactoryBean.super.isSingleton();
<bean id="bean" class="org.deepSpring.MyFactoryBean"></bean>
如果希望获取FactoryBean本身,则需要在beanName前面加上&前缀
xmlBeanFactory.getBean("&bean");
缓存中获取单例bean
让我们回到doGetBean方法的这一行代码来:
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
DefaultSingletonBeanRegistry#getSingleton—尝试从缓存或者ObjectFactory中获取单例bean
public Object getSingleton(String beanName)
//true设置标识允许早期依赖
return getSingleton(beanName, true);
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference)
// Quick check for existing instance without full singleton lock
//从单例缓冲池中检查缓存中是否存在对应的单例bean实例
Object singletonObject = this.singletonObjects.get(beanName);
//如果单例缓冲池中找不到并且当前beanName处于正在创建阶段的话
//isSingletonCurrentlyInCreation是通过singletonsCurrentlyInCreation集合来判断当前bean是否处于创建状态的
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName))
//从早期单例对象的缓存获取缓存----这里earlySingletonObjects为什么存在,干啥的,暂时不管,后面进行揭秘
singletonObject = this.earlySingletonObjects.get(beanName);
//如果从单例缓冲池和早期单例缓冲池都找不到,并且如果可以创建早期引用###
if (singletonObject == null && allowEarlyReference)
synchronized (this.singletonObjects)
// Consistent creation of early reference within full singleton lock
//这里是单例模式的双重锁校验实现,不知道各位有没有看出来
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null)
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null)
//直接看这里就可以了------->
//当某些方法需要提前初始化的时候则会调用addSingletonFactory方法将对应的ObjectFactory初始化策略存储在singletonFactories
以上是关于Spring读源码系列04----bean的加载---上的主要内容,如果未能解决你的问题,请参考以下文章