六、Spring 源码解析之 bean 的加载过程介绍

一、案例解析

	public static void main(String[] args) {
		DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
		XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
		reader.loadBeanDefinitions(new ClassPathResource("spring-dev.xml"));
		User user = (User) factory.getBean("testbean");
		System.out.println(user);
	}

bean 的加载主要由 User user = (User) factory.getBean("testbean") 这段代码完成,跟着这段代码进入源码。

二、调用流程

这里的核心就是doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly)方法,这里简要介绍下加载过程中所涉及的步骤:

1.转换对应 beanName
问题:为什么转换对应的 beanName ,传入的参数 name 不就是 beanName 吗?
回答:其实不是,这里传入的参数可能是别名,也可能是 FactoryBean,所以需要进行一系列的解析,解析内容如下:
1.去除 FactoryBean 的修饰符,也就是如果 name="&aa",name首先去除 & 而使 name=“aa”
2.取指定 alias 所表示的最终 beanName,例如别名 A 指向名称为 B 的 bean 则返回 B;若别名 A 指向别名 B,
别名 B 又指向名称为 C 的 bean 则返回 C

2.尝试从缓存中加载单例
单例在Spring的同一个容器内只会被创建一次,后续再获取 bean,就直接从单例缓存中获取了。当然这里也只是尝试加载,首先尝试从缓存中加载,如果加载不成功则再次尝试从 singletonFactories 中加载。因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,在Spring 中创建 bean 的原则是不等 bean 创建完成就会创建 bean 的 ObjectFactory 提早曝光加入到缓存中,一旦下一个 bean 创建时候需要依赖上一个 bean 则直接使用 ObjectFactory。

3.bean 的实例化
如果从缓存中得到了 bean 的原始窗台,则需要对 bean 进行实例化。这里有必要强调一下,缓存中记录的只是最原始的 bean 状态,并不一定是我们最终想要的 bean。举个例子,假如我们需要对工厂 bean 进行处理,那么这里得到的其实是工厂 bean 的初始状态,但是我们真正需要的是工厂 bean 中定义的 factory-method 方法中返回的 bean,而 getObjectForBeanInstance() 就是完成这个工作的。

4.原型模式的依赖检查
只有在单例情况下才会尝试解决循环,原型模式情况下,如果存在 A 中有 B 属性,B 中有 A 属性,那么当依赖注入的时候,就会产生当 A 还未创建完的时候因为 对于 B 的创建再次返回创建 A,造成循环依赖,也就是下面的情况:isPrototypeCurrentlyInCreation(beanName) 返回 true

5.检测 parentBeanFactory
代码中,若缓存中没有数据的话直接转到父类工厂去加载,这是为什么?
根据判断条件:parentBeanFactory != null && !containsBeanDefinition(beanName),若 parentBeanFactory 为 null,则无需再进行处理,这个没什么说的,但是 !containsBeanDefinition(beanName) 就比较重要了,它是在检测如果当前加载的 XML 配置文件中不包含 beanName 对应的配置,就只能到 parentBeanFactory 去尝试下了,然后再去递归的调用的 getBean() 方法。

6.将存储 XML 配置文件的 GenericBeanDefinition 转换成 RootBeanDefinition
因为 XML 配置文件中读取到的 bean 信息是存储在 GenericBeanDefinition 中的,但是所有的 bean 后续处理都是针对于 RootBeanDefinition 的,所以这里需要进行一个转换,转换的同时,如果父类 bean 不为空的话,则会一并合并父类的属性。

7.寻找依赖
因为 bean 初始化过程中很可能会用到某些属性,而某些属性很可能是动态配置的,并且配置成依赖于其他的 bean,那么这个时候就有必要先加载依赖的 bean,所以,在 Spring 的加载顺序中,在初始化某一个 bean 的时候首先会初始化这个 bean 所对应的依赖。

8.针对不同的 scope 进行 bean 的创建
我们都知道,在 Spring 中存在着不同的 scope,其中默认的是 singleton,但是还有些其它的配置诸如prototype、request 之类的。在这个步骤中,Spring 会根据不同的配置进行不同的初始化策略。

9.类型转换
程序到这里返回 bean 后已经基本结束了,通常对该方法的调用参数 requiredType 是为空的,但是很可能会存在这样的情况,返回的 bean 其实是个 String,但是 requiredType 却传入 Integer 类型,那么这时候本步骤就会起作用了,它的功能是将返回的 bean 转换为 requiredType 所指定的类型。当然 String 转换为 Integer 是做简单的一种转换,在 Spring 中提供了各种各样的转换器,用户也可以自己扩展转换器来满足需求。

扫描二维码关注公众号,回复: 8804364 查看本文章

对应的流程图(版本不一致,可能局部不同)
在这里插入图片描述

  • AbstractBeanFactory#getBean(String name)
	@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}
  • AbstractBeanFactory#doGetBean(final String name, @Nullable final Class requiredType,@Nullable final Object[] args, boolean typeCheckOnly)
  1. 转换对应 beanName
  2. 尝试从缓存中加载单例
  3. bean 的实例化
  4. 原型模式的依赖检查
  5. 检测 parentBeanFactory
  6. 将存储 XML 配置文件的 GenericBeanDefinition 转换成 RootBeanDefinition
  7. 寻找依赖
  8. 针对不同的 scope 进行 bean 的创建
  9. 类型转换
	/**
	* bean的加载
	*/
	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
		//提取对应的 beanName
		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		/*
		 * 检查缓存中或者实例工厂中是否有对应的实例
		 * 为什么首先会使用这段代码呢?
		 * 因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖。
		 * Spring 创建 bean 的原则是不等 bean 创建完成就会将创建 bean 的 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 + "'");
				}
			}
			// 返回对应的实例,有时候存在诸如 BeanFactory 的情况并不是直接返回实例本身,而是返回“指定方法”返回的实例
			bean = 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(beanName) 返回 true
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// Check if bean definition exists in this factory.
			//若缓存中没有数据的话直接转到父类工厂去加载
			BeanFactory parentBeanFactory = getParentBeanFactory();
			/*
			 * 如果 beanDefinitionMap 中也就是在所有已经加载的类中不包括 beanName 则尝试从 parentBeanFactory 中检测
			 * !containsBeanDefinition(beanName):如果当前加载的 XML 配置文件中不包含 `beanName` 对应的配置
			 */
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				// 递归到 BeanFactory 中寻找
				else if (args != null) {
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}
			// 如果不是仅仅做类型检查则是创建bean,这里需要进行记录
			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}

			try {
				/*
				 * 将存储 XML 配置文件的 GenericBeanDefinition 转换成  RootBeanDefinition,如果指定
				 * BeanName 是子 Bean 的话同时会合并父类的相关属性
				 */
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				// Guarantee initialization of beans that the current bean depends on.
				String[] dependsOn = mbd.getDependsOn();
				// 若存在依赖则需要递归实例化依赖的 bean
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						// 缓存依赖调用
						registerDependentBean(dep, beanName);
						try {
							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()) {
					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;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				} else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					// prototype 模式的创建(new)
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				} else {
					//指定的 scope 上实例化 bean
					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);
					}
				}
			}
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}

		// Check if required type matches the type of the actual bean instance.
		// 检查需要的类型是否符合 bean 的实际类型,不符合则转换
		if (requiredType != null && !requiredType.isInstance(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;
	}
  • AbstractBeanFactory#transformedBeanName(String name)
	/**
	 * 问题:为什么转换对应的 beanName ,传入的参数 name 不就是 beanName 吗?
	 * 回答:其实不是,这里传入的参数可能是别名,也可能是 FactoryBean,所以需要进行一系列的解析,解析内容如下:
	 * 1、去除 FactoryBean 的修饰符,也就是如果 name="&aa",name首先去除 & 而使 name="aa"
	 * 2、取指定 alias 所表示的最终 beanName,例如别名 A 指向名称为 B 的 bean 则返回 B;若别名 A 指向别名 B,
	 *    别名 B 又指向名称为 C 的 bean 则返回 C
	 */
	protected String transformedBeanName(String name) {
		return canonicalName(BeanFactoryUtils.transformedBeanName(name));
	}

	/**
	 * BeanFactoryUtils类
	 * 去除 FactoryBean 的修饰符,也就是如果 name="&aa",name首先去除 & 而使 name="aa"
	 */
	public static String transformedBeanName(String name) {
		Assert.notNull(name, "'name' must not be null");
		if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
			return name;
		}
		return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
			do {
				beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
			}
			while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
			return beanName;
		});
	}	

	/**
	 * AbstractBeanFactory类
	 *     取指定 alias 所表示的最终 beanName,例如别名 A 指向名称为 B 的 bean 则返回 B;若别名 A 指向别名 B,
	 * 别名 B 又指向名称为 C 的 bean 则返回 C
	 */
	public String canonicalName(String name) {
		String canonicalName = name;
		// Handle aliasing...
		String resolvedName;
		do {
			resolvedName = this.aliasMap.get(canonicalName);
			if (resolvedName != null) {
				canonicalName = resolvedName;
			}
		}
		while (resolvedName != null);
		return canonicalName;
	}
发布了444 篇原创文章 · 获赞 113 · 访问量 40万+

猜你喜欢

转载自blog.csdn.net/panchang199266/article/details/100996418