测试类
一个简单的测试类
public class Test_2 {
public static void main(String[] args) {
/* 初始化启动 spring ioc 容器 */
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-spring.xml");
/* 从 spring ioc 容器中获取一个 bean */
ProductInfoService productInfoService = (ProductInfoService) applicationContext.getBean("productInfoServiceImpl");
System.out.println("拿到的Bean为:" + productInfoService);
}
}
对于 ApplicationContext
和 ClassPathXmlApplicationContext
类图如下:
getBean
源码解读
使用开发工具进入 DEBUG
模式,进入 getBean
方法,来到 AbstractApplicationContext
抽象类中
查看AbstractApplicationContext
中的 getBean
方法
@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
然后我们看这里的这个 getBean
方法,实际上是调用了抽象类 AbstractBeanFactory
的 doGetBean
方法
查看AbstractBeanFactory
的 doGetBean
方法
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
/**
* 通过 name 获取 beanName。这里不使用 name 直接作为 beanName 有两个原因
* 1、name 可能会以 & 字符开头,表明调用者想获取 FactoryBean 本身,而非 FactoryBean
* 实现类所创建的 bean。在 BeanFactory 中,FactoryBean 的实现类和其他的 bean 存储
* 方式是一致的,即 <beanName, bean>,beanName 中是没有 & 这个字符的。所以我们需要
* 将 name 的首字符 & 移除,这样才能从缓存里取到 FactoryBean 实例。
* 2、还是别名的问题,转换需要 &beanName
*/
final String beanName = transformedBeanName(name);
Object bean;
// 先从缓存中获取,因为在容器初始化的时候或者其他地方调用过getBean,已经完成了初始化
Object sharedInstance = getSingleton(beanName);
// 如果已经初始化过,直接从缓存中获取
if (sharedInstance != null && args == null) {
// 如果beanName的实例存在于缓存中
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
/**
* 如果 sharedInstance 是普通的单例 bean,下面的方法会直接返回。但如果
* sharedInstance 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的
* bean 实例。如果用户想获取 FactoryBean 本身,这里也不会做特别的处理,直接返回
* 即可。毕竟 FactoryBean 的实现类本身也是一种 bean,只不过具有一点特殊的功能而已。
*/
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 如果是原型不应该在初始化的时候创建,在这里直接抛出异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 获取parentBeanFactory
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 将别名解析成真正的beanName
String nameToLookup = originalBeanName(name);
// 如果parentBeanFactory存在,并且beanName在当前BeanFactory不存在Bean定义,则尝试从parentBeanFactory中获取bean实例
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
// 尝试在parentBeanFactory中获取bean对象实例
else if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
// 添加到alreadyCreated set集合当中,表示他已经创建过一次,做标记
markBeanAsCreated(beanName);
}
try {
// 根据beanName重新获取MergedBeanDefinition(步骤6将MergedBeanDefinition删除了,这边获取一个新的)
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 检查MergedBeanDefinition
checkMergedBeanDefinition(mbd, beanName, args);
// 拿到当前bean依赖的bean名称集合,在实例化自己之前,需要先实例化自己依赖的bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
// 遍历当前bean依赖的bean名称集合
for (String dep : dependsOn) {
// 检查dep是否依赖于beanName,即检查是否存在循环依赖
if (isDependent(beanName, dep)) {
// 如果是循环依赖则抛异常
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 将dep和beanName的依赖关系注册到缓存中
registerDependentBean(dep, beanName);
try {
// 获取dep对应的bean实例,如果dep还没有创建bean实例,则创建dep的bean实例
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// bean 的实例化
if (mbd.isSingleton()) {
// scope为 singleton 的bean创建(新建了一个ObjectFactory,并且重写了getObject方法)
sharedInstance = getSingleton(beanName, () -> {
try {
// 创建Bean实例
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
// 返回beanName对应的实例对象
// 这里主要处理实现了FactoryBean的情况,需要调用重写的getObject()方法来获取实际的Bean实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// scope为 prototype 的bean创建
Object prototypeInstance = null;
try {
// 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)
beforePrototypeCreation(beanName);
// 创建Bean实例
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
// 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)
afterPrototypeCreation(beanName);
}
// 返回beanName对应的实例对象
// 这里主要处理实现了FactoryBean的情况,需要调用重写的getObject()方法来获取实际的Bean实例
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
// 既不是单例也不是原型的 bean创建,可能是 request之类的
// 根据scopeName,从缓存拿到scope实例
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 {
// 既不是单例也不是原型的bean创建(新建了一个ObjectFactory,并且重写了getObject方法)
Object scopedInstance = scope.get(beanName, () -> {
// 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)
beforePrototypeCreation(beanName);
try {
// 创建bean实例
return createBean(beanName, mbd, args);
}
finally {
// 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)
afterPrototypeCreation(beanName);
}
});
// 返回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);
}
}
}
catch (BeansException ex) {
// 如果创建bean实例过程中出现异常,则将beanName从alreadyCreated缓存中移除
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// 检查所需类型是否与实际的bean对象的类型匹配
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
// 类型不对,则尝试转换bean类型
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
看doGetBean
方法的流程图
分析doGetBean
方法的主要流程
1.转换对应 beanName
2.(重点)首先尝试从缓存中获取单例 bean
:尝试从缓存中或者 singletonFactories
中的 ObjectFactory
中获取,这么做的主要目的就是为了解决单例模式下的循环依赖

3.如果缓存中没有单例 bean
时,
3.1. 原型模式下如果有循环依赖,直接抛出异常
3.2. 获取parentBeanFactory
,如果parentBeanFactory
存在但并未包含当前bean
的 定义,递归调用父工厂中的getBean
方法得到实例
3.3typeCheckOnly==false
,做记录
3.4 得到RootBeanDefinition
,校验RootBeanDefinition
。将配置文件中GenericBeanDefinition
转换为RootBeanDefinition
,如果beanName
是子bean
的话,会合并父类的属性
3.5 处理依赖,先实例化该bean
依赖的bean
,并且注册依赖
3.6 得到bean
的实例
3.7 (重点)如果是单例,按照单例的策略初始化bean
,调用getSingleton
方法,传入一个类似回调函数的类ObjectFactory
,实现该类的getObject
回调方法,在该回调方法中调AbstractAutowireCapableBeanFactory
的createBean
,实际上是调用它的doCreateBean
在做Bean
实例化的逻辑
3.8 (重点)如果是原型,按照原型的策略创建一个实例,先调beforePrototypeCreation
方法,再调createBean
方法,再调afterPrototypeCreation
方法
3.9 (重点)如果既不是单例也不是原型,按照另一套策略来创建一个实例,调用scope
的get
方法,传入一个类似回调函数的类ObjectFactory
,实现该类的getObject
回调方法,在该回调方法beforePrototypeCreation
中调用AbstractAutowireCapableBeanFactory
的createBean
方法,再调用afterPrototypeCreation
方法
4.检测需要的类型是否符合Bean
的实际类型
查看 getSingleton(beanName)
方法(重点)
可以看到从 IOC
容器中获取 bean
的时候,首先去缓存中获取,就是doGetBean
方法中的 getSingleton(beanName)
,源码如下:
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 先从一级缓存中获取已经实例化,属性填充完成的 bean
Object singletonObject = this.singletonObjects.get(beanName);
// 判断当前单例bean是否正在创建中,也就是没有初始化完成(比如A的构造器依赖了B对象所以得先去创建B对象,
// 或则在A的populateBean过程中依赖了B对象,得先去创建B对象,这时的A就是处于创建中的状态
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 从二级缓存中查询,获取 bean 的早期引用,实例化完成但属性填充未完成的 bean
singletonObject = this.earlySingletonObjects.get(beanName);
// 是否允许从singletonFactories中通过getObject拿到对象
if (singletonObject == null && allowEarlyReference) {
// 从三级缓存中查询,实例化完成,属性未填充的 bean
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 放入 earlySingletonObjects 二级缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
// 从 singletonFactories 三级缓存中移除
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
分析 getSingleton()
的整个过程:
spring
首先从一级缓存singletonObjects
中获取- 如果获取不到,并且对象正在创建中,就再从二级缓存
earlySingletonObjects
(实例化完成但属性填充未完成的bean
)
中获取 - 如果还是获取不到且允许
singletonFactories
通过getObject()
获取,就从三级缓存singletonFactory.getObject()
中获取,如果获取到了则:从singletonFactories
中移除,并放入earlySingletonObjects
(实例化完成但属性填充未完成的
bean
) 中。其实也就是从三级缓存移动到了二级缓存
getSingleton(beanName)
的主要作用就是为了解决单例模式下的 bean
循环依赖问题。spring 单例模式 bean 的循环依赖问题查看
疑惑问题
经使用上面的测试类进行几次调试发现,productInfoServiceImpl
这个 bean
总是从下面的
Object sharedInstance = getSingleton(beanName);
单例缓存池中拿到了,仔细想想问题所在,productInfoServiceImpl
这个 bean
肯定是在下面的
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-spring.xml");
IOC
容器启动时,已经初始化完成,并在某个时候添加进了单例缓存池中。那么这个 bean
是在什么时候初始化的,又在什么时候添加进了单例缓存池中呢?带着问题写博客,请看下片博客
有关 spring
的 getBean
方法的详细解读:https://blog.csdn.net/mamamalululu00000000/article/details/106790079