spring 源码之 getBean 方法解读

测试类

一个简单的测试类

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);
    }
}

对于 ApplicationContextClassPathXmlApplicationContext 类图如下:

在这里插入图片描述

getBean 源码解读

使用开发工具进入 DEBUG 模式,进入 getBean 方法,来到 AbstractApplicationContext 抽象类中

查看AbstractApplicationContext 中的 getBean方法

@Override
	public Object getBean(String name) throws BeansException {
    
    
		assertBeanFactoryActive();
		return getBeanFactory().getBean(name);
	}

然后我们看这里的这个 getBean方法,实际上是调用了抽象类 AbstractBeanFactorydoGetBean 方法

查看AbstractBeanFactorydoGetBean 方法

@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回调方法,在该回调方法中调AbstractAutowireCapableBeanFactorycreateBean,实际上是调用它的doCreateBean在做Bean实例化的逻辑

3.8 (重点)如果是原型,按照原型的策略创建一个实例,先调beforePrototypeCreation方法,再调createBean方法,再调afterPrototypeCreation方法

3.9 (重点)如果既不是单例也不是原型,按照另一套策略来创建一个实例,调用scopeget方法,传入一个类似回调函数的类ObjectFactory,实现该类的getObject回调方法,在该回调方法beforePrototypeCreation中调用AbstractAutowireCapableBeanFactorycreateBean方法,再调用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() 的整个过程:

  1. spring 首先从一级缓存 singletonObjects 中获取
  2. 如果获取不到,并且对象正在创建中,就再从二级缓存 earlySingletonObjects(实例化完成但属性填充未完成的 bean
    中获取
  3. 如果还是获取不到且允许 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 是在什么时候初始化的,又在什么时候添加进了单例缓存池中呢?带着问题写博客,请看下片博客

有关 springgetBean 方法的详细解读:https://blog.csdn.net/mamamalululu00000000/article/details/106790079

猜你喜欢

转载自blog.csdn.net/weixin_38192427/article/details/113409386