1. 本文概览
目标: 理解BeanFactory#getBean()内部bean加载过程
完整上面的过程需要2个部分:
- 容器初始化阶段:
- firstly,加载Configuration Metedata(通过Resource,ResourceLoader)
- secondly,解析Configuration Metedata,创建BeanDefinition
- thrid,将生成的BeanDefinition注册进BeanFactory中
2.加载Bean阶段:触发时机: 当我们显示或者隐身调用
BeanFactory#getBean()
,就会触发Bean的加载阶段。 - first,获取BeanName
- second,从单例Bean缓存获取Bean
- third,原型模式依赖检测
- four,从parentBeanFactory中获取Bean
- fifth,标记Bean为已创建或即将创建
- sixth,获取BeanDefinition
- seventh,依赖Bean处理
- enghth,不同作用域的Bean的实例化
- nine,类型转换
2. getBean()源码流程
看的源码是AbstractBeanFactory#getBean()
的源码,getBean()源码流程即为加载Bean阶段。
AbstractBeanFactory#getBean()源码
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
AbstractBeanFactory下有其他getBean的重载方法,但是最终都是调用doGetBean,只是传递的参数不同。doGetBean源码很长,就不贴了,网上博客基本上都将其分为了9个部分,本文也是按照这个流程对源码进行说明。
2.1 获取BeanName
/**
* 1. 过滤 beanName
* 1. 断言 beanName 不为 null
* 2. 若 beanName 以 factoryBean 前缀('&')开头,去掉前缀
* 3. 将别名转换为规范名
*/
final String beanName = transformedBeanName(name);
我这不再跟进transformedBeanName源码了,有兴趣的可以自己看看。感觉注释也说的很清楚了。这个地方就在说明一个问题:
FactoryBean与普通Bean区别?
其实两者都是Spring Bean,FactoryBean是一个接口,实现该接口的Bean在Spring容器中会被当作一个FactoryBean,其实和设计模式中的工厂相同,用来生产普通Bean的。这里说的区别就是在使用getBean(String name)
方法的不同。
比如我们有一个OrderFactoryBean,专门用来生产OrderBean的。
那么getBean('orderFactoryBean') 返回的是OrderFactoryBean这个工厂本身还是这个工厂创建的Bean呢。答案是:创建Bean。获取工厂本身需要加上一个前缀'&',像酱紫getBean('&orderFactoryBean')。
2.2 从单例Bean缓存获取Bean
// Eagerly check singleton cache for manually registered singletons.
/**
* 2. 立即检测单例缓存中手动注册的单例对象是否含有目标bean ()
* 1. 尝试从 单例对象map 中获取bean
* 2. 若1中没有,并且目标bean正在被创建,则尝试从 早期单例对象map 中获取bean
* 3. 若2中没有,并且允许早期引用,则尝试从 工厂对象map 中获取工厂,然后通过工厂生成bean,
* 此时创建的bean 被添加到 早期单例map 中
* 4. 若3没有,返回 null
*
* 3个map缓存:
* 1. 单例对象缓存(singletonObjects)
* 2. 早期单例对象缓存(earlySingletonObjects)
* 3. 工厂对象缓存(singletonFactories)
*
*/
Object sharedInstance = getSingleton(beanName);
这个过程的代码其实只有一行,所以我在把getSingleton(beanName)
源码贴出来
// 尝试从 singletionObjects map 中获取注册的单例
Object singletonObject = this.singletonObjects.get(beanName);
// 若 singletonObject 为 null 并且当前查找 beanName 正在被实例化
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// map中找不到单例,isSingletonCurrentlyInCreation(beanName)=true表示目标单例bean正在被创建
synchronized (this.singletonObjects) {
// 加锁
// 尝试从早期单例 map 中获取bean (早期单例对象 就是没有完全初始化完成的单例对象,比如对象的属性值还没有赋值)
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 早期单例map与单例map中均没有目标bean,此时若设置 允许早期引用
// 则尝试从工厂创建目标bean
// 尝试获取单例工厂
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 若获取到单例工厂,则使用工厂产生bean对象,这种方式产生的 bean 添加到 早期单例map 种
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
这个过程是从单例缓存中获取Bean,那么我们就必须直到有哪些单例缓存
源码位置在DefaultSingletonBeanRegistry
类中,涉及到的单例缓存有3种:
- 单例缓存
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
这个map存储的是已经完成初始化的单例对象。
- 正在创建的单例缓存
/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
看名字就知道了,当前正在创建的单例。就是当一个bean正在被创建,就把它的beanName加入到这个set中。
- 早期单例对象缓存
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
其实一开始我也是不理解这个东西有毛线用?后来才知道存放的是没有完全初始化完成的单例对象,这种对象就类似于单例设计模式中“Double Check”因指令重排序产生的单例对象,它没有初始化完成,不能够正常的使用。
- 工厂Bean单例缓存
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
通过名字就知道存放的是FactoryBean对象。这个地方也是FatoryBean于普通Bean不一样的地方。
丛单例缓存中获取Bean,得不到就返回null,那么得到了呢?看下面代码:
if (sharedInstance != null && args == null) {
// 若从单例缓存中获取到了 bean,并且没有传递 bean 的参数
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 + "'");
}
}
// 3. sharedInstance可能是factoryBean获取普通bean
// 1. 若是factoryBean,并且 name 有 '&'前缀,返回工厂本身
// 2. 若是factoryBean,name无'&'前缀,通过工厂产生对象返回
// 3. 普通bean,直接返回
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
从缓冲中得到 sharedInstance 后,再通过getObjectForBeanInstance(sharedInstance, name, beanName, null);
就得到了最终生成bean对象。这个方法作用在上面注释已经标出了。
2.3 原型模式依赖检测
// 因为 Spring 只解决单例模式下得循环依赖,在原型模式下如果存在循环依赖则会抛出异常。
// 对于单例( Singleton )模式, Spring 在创建 Bean 的时候并不是等 Bean 完全创建完成后才会将 Bean 添加至缓存中,
// 而是不等 Bean 创建完成就会将创建 Bean 的 ObjectFactory 提早加入到缓存中,这样一旦下一个 Bean 创建的时候需要
// 依赖 bean 时则直接使用 ObjectFactroy 。
// 但是原型( Prototype )模式,我们知道是没法使用缓存的,所以 Spring 对原型模式的循环依赖处理策略则是不处理。
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
2.4 从parentBeanFactory中获取Bean
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory(); // 获取父factory
// containsBeanDefinition(beanName) -> 判断该beanName的BeanDefinition是否在该factory中
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 有父factory存在并且当前factory不包含该beanName,则尝试从父factory中加载bean
// Not found -> check parent.
String nameToLookup = originalBeanName(name); // 若有多个'&'值保留一个
if (parentBeanFactory instanceof AbstractBeanFactory) {
// 递归调用父类 doGetBean 方法
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// // 用明确的 args 从 parentBeanFactory 中,获取 Bean 对象
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// 用明确的 requiredType 从 parentBeanFactory 中,获取 Bean 对象
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
// 直接使用 nameToLookup 从 parentBeanFactory 获取 Bean 对象
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
在自己的fatory中到不到bean就尝试从父fatroy中找,父找不到就到父父上面找,一直递归下去。
2.5 标记Bean为已创建或即将创建
// 如果不是仅做类型检查,而是创建bean,则需要标记该beanName为已经创建或者为即将被创建
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
2.6 获取BeanDefinition
try {
// 从容器中获取 beanName 相应的 GenericBeanDefinition 对象,并将其转换为 RootBeanDefinition 对象
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 检查给定的合并的 BeanDefinition
checkMergedBeanDefinition(mbd, beanName, args);
RootBeanDefinition
我是真的不知道这个是什么东西,但是从这个对象我们可以获得到bean对应BeanDefinition,我目前只能看出这一个作用。
2.7 依赖Bean处理
// 处理所依赖的 bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
// 若给定的依赖 bean 已经注册为依赖给定的 bean
// 上面的话很拗口,其实就是bean出现了循环依赖
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 设置 beanName 的依赖bean
registerDependentBean(dep, beanName);
try {
// 递归获取依赖bean
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
处理bean创建的依赖问题,先创建目标bean,如果目标bean依赖另一个bean,则递归调用getBean()先把依赖对象创建。
2.8 不同作用于的Bean实例化
// Create bean instance.
if (mbd.isSingleton()) {
// beanName 是单例对象,从单例缓存中获取
// 1. 若缓存中有,直接返回
// 2. 若缓存中没有,通过 beanName 对应的 Beandefinition 创建 bean返回
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.
// beanName 可能已经存在了
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// beanName 是 prototype,创建一个新的bean
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
// 其他类型的scope,如 session等
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
在使用注解配置Bean的时候我们通过scope参数指定我们的socpe,不同的scope走不同路线。
2.9 类型转换
// 检查beanName类型是否符合需要的类型,若不符合,尝试进行转换
if (requiredType != null && !requiredType.isInstance(bean)) {
// 传递了 requiredType参数,并且bean的类型不是需要的类型
try {
// 尝试进行转换
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
// 转换失败,抛出异常
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;