上一篇,我们了解了Spring实例化bean的另外一种实例化bean的方式,也就是通过实现FactoryBean接口中的getObject方法,来自定义bean实例化的逻辑。这一篇,我们来看下Spring默认是如何来实例化bean的。
在第一次调用getBean方法时,缓存中肯定是获取不到bean实例的,所以会走到上图的分支。可以看到,首先会调用方法isProptoTypeCurrentInCreation进行判断,我们到方法isProptoTypeCurrentInCreation中看下:
可以看到,在方法isProptoTypeCurrentInCreation中有一个集合prototypesCurrentlyInCreation,主要的逻辑就是判断下集合中是否存在beanName。我们知道方法isSingletonCurrentlyInCrreation是用来判断当前spring中,是否存在名称beanName的单例bean正在创建,类似的。方法isPropotypeCurrentInCreation则是用来判断当前spring中,是否存在protoType类型的,且名称为beanName的bean正在创建。Spring创建bean的类型默认为单例,对于单例的bean Spring在容器中仅仅只会保留一份bean的实例,而prototype类型的bean,大家可以理解为每次调用getBean方法时都会去创建一个崭新的bean实例出来。正是因为prototype类型的bean,每次来获取时都会创建一个新的bean实例,所以Spring也就没必要为这种类型的bean进行缓存。对于循环依赖问题,单例类型的bean可以通过三级缓存来解决,但是prototype类型的bean因为是没有缓存的,所以prototype类型的bean是无法解决循环依赖的,哪怕是setter循环依赖。而prototype类型的bean实例,因为是没有缓存存放的,所以,一旦发现名称为beanName的bean正在创建,就会抛出异常来终止本次bean的创建。
如果Spring容器中不存在beanName对应的BeanDefinition,并且当前的Spring容器的父容器是存在的,就会到Spring的父容器中获取bean的实例了。我们先到方法originalBeanName中:
也就是在转换得到bean的实际名称beanName之后,在判断传进来的name是否有前缀&,如果又的话,就在bean实际名称beanName前添加符号&。通过这个我们应该知道通过方法originalBeanName修饰过的名称,要不就是从spring容器中获取一个普通的bean,要不就是获取一个实现接口FactoryBean的bean实例。
这个就比较简单了,就是通过父容器获取bean的实例。我们之前的容器初始化是没有设置父容器的,所以不会走这个流程的。
我们继续往后看:
其中参数typeCheckOnly在方法doGetBean被调用时就会传入,默认值为false。我们到方法markBeanAsCreated看下:
在方法markBeanAsCreated中,首先会判断alreadyCreated中是否存在beanName,第一次过来里面是没有的。而且,在方法markBeanAsCreated内部是做了double check,这个也是为了避免多线程并发的问题。这里最为关键的是在集合alreadyCreated中添加beanName。
我们继续往下看:
我们看到了一行关键的代码,通过方法getMergedLocalBeanDefinition的名称,我们可以基本知道方法是用来获取beanName对应的BeanDefinition,但是,在方法中getMergedLocalBeanDefinition返回了类型为 RootBeanDefinition的BeanDefinition。Spring默认是通过GenericBeanDefinition类型的BeanDefinition来封装Bean的信息的。
我们到getMergedLocalBeanDefinition方法中看下:
在getMergedLocalBeanDefinition方法中也有一个缓存mergedBeanDefinitions,它是用来存放beanName以及相应的BeanDefinition。我们第一次进入缓存中是没有的,也就是mbd为空。
而在调用getMergedBeanDefinition方法的同时也调用了getBeanDefinition,通过传入beanName来获取Spring容器中的BeanDefinition。我们来看下在方法getMergedBeanDefinition中,会做什么?
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
RootBeanDefinition previous = null;
// Check with full lock now in order to enforce the same merged instance.
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null || mbd.stale) {
previous = mbd;
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
mbd = new RootBeanDefinition(bd);
}
}
else {
// 处理父类bean的BeanDefinition
// Child bean definition: needs to be merged with parent.
BeanDefinition pbd;
try {
// 获取父类bean的实际名称
String parentBeanName = transformedBeanName(bd.getParentName());
// 如果父类bean的名称和当前bean的名称不同
if (!beanName.equals(parentBeanName)) {
// 递归调用,获取父类bean的RootBeanDefinition
pbd = getMergedBeanDefinition(parentBeanName);
}
// 如果父类bean的名称 和当前bean的名称不一样,那就到父类容器中获取BeanDefinition
else {
BeanFactory parent = getParentBeanFactory();
if (parent instanceof ConfigurableBeanFactory) {
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
}
else {
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without a ConfigurableBeanFactory parent");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// Deep copy with overridden values.
mbd = new RootBeanDefinition(pbd);
mbd.overrideFrom(bd);
}
// Set default singleton scope, if not configured before.
// 设置默认的bean 为单例类型
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(SCOPE_SINGLETON);
}
// A bean contained in a non-singleton bean cannot be a singleton itself.
// Let's correct this on the fly here, since this might be the result of
// parent-child merging for the outer bean, in which case the original inner bean
// definition will not have inherited the merged outer bean's singleton status.
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
// Cache the merged bean definition for the time being
// (it might still get re-merged later on in order to pick up metadata changes)
if (containingBd == null && isCacheBeanMetadata()) {
// 将封装好的RootBeanDefinition添加到缓存
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
if (previous != null) {
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
return mbd;
}
}
这个方法的逻辑主要涉及了以下几个步骤:
1、通过创建一个RootBeanDefinition,封装从Spring容器中获取到的BeanDefinition,因为容器中的BeanDefinition是GenericBeanDefinition类型的,是没有记录父子bean标签的关系的,Spring在实例化前需要通过RootBeanDefinition来组织。
2、如果说当前的bean配置了父类bean,那就先封装父类的bean的RootBeanDefinition,否则的话,直接封装当前bean对应的BeanDefinition即可。
3、将RootBeanDefinition中的类型设置为单例。
4、将封装好的RootBeanDefinition添加到缓存中。
我们们接着往下看:
可以看到,会调用checkMergedBeanDefinition方法,我们进去看下:
在方法checkMergedBeanDefinition中,只不过是判断下BeanDefinition对应的Bean是否是一个抽象类的BeanDefinition,抽象类是不能实例化对象的,所以就会抛出异常。
我们继续往下看:
首先会通过getDependsOn方法获取属性dependsOn的值,我们先看下BeanDefinition中的dependsOn是什么:
比如,我们当前要实例化User对象,而在User对象中配置了属性depends-on的值为User1,表示user的这个bean在实例时,需要依赖User1对象。所以在实例化User之前,Spring会先实例化User1这个对象,其中,BeanDefinition中的getDependsOn方法获取的值就是标签中属性的depends-on的值user1。
我们继续分析下面的代码:
首先会遍历bean依赖的所有bean的名称dep,我们到方法isDependent中看下:
接下来会进入到重载方法isDependent中,而且,重载方法中的逻辑也比较简单,首先会从dependentBeanMap中获取beanName对应集合dependentBeans。我们知道dependentBeans其实就是beanName依赖的那些bean名称集合,统一都被存在了集合dependentBeanMap中。接下来就会判断当前bean依赖的dependentBeanName,是否已经存在于beanName依赖的集合dependentBeans中。
我们可以举个例子,假如当前的user依赖的bean的集合元素为:user1、user2。它们存放于集合dependentBeans中,如果dependentBeanName的名称为user1,此时就和集合dependentBeans中的元素重复了,所以就直接返回true了。
除了检查dependentBeanName是否在beanName依赖的范围之内,还会进一步检查:
接下来会遍历,beanName依赖的那些bean的名称dependentBeans。我们还是以刚才的例子来看,user依赖bean的名称为user1、user2,假如user1依赖的bean集合元素为:user11、user12。此时,我们假设dependentBeanName的值为use11,首先就可以避开beanName直接依赖集合的检查,代码会执行到for循环这里,此时,在第一次遍历时就会发现dependentBeanName的名称,于user1依赖集合中的user11重复了,同样也会返回true。
通过这个我们可以知道,只要传入进来的dependentBeanName在这个beanName 的bean依赖链上,就会返回true。
我们回到前面的方法:
可以看到,isDependent方法返回结果为true时,就会抛出异常。如果bean配置的依赖都通过了检查,接着会调用registerDependentBean方法:
可以看到方法registerDependentBean中,会将bean的名称以及依赖的那些bean名称,都注册到相应的缓存中。而且因为dependsOn是当前bean依赖的那些bean,所以在实例化当前bean之前,Spring会提前调用getBean方法来实例化依赖的这些bean。
我们继续往后看:
首先会判断BeanDefinition中的bean类型是否为单例,在前面我们已经知道了默认就是单例的bean,接下来就会调用方法getSingleton来实例化bean。
我们梳理一下我们今天的流程图: