Spring的Bean的加载

     先把上一片博客的图整过来:

上边的这张简易流程图是getBean的过程,在这里进行拆分,本篇博文主要是将前两步的源码,即getBean和doGetBean。

1、getBean

查看getBean的源码,发现有几个实现,但是每个实现都很简单,都是调用了doGetBean的防范,如下:

	@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}

	@Override
	public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
		return doGetBean(name, requiredType, null, false);
	}

	@Override
	public Object getBean(String name, Object... args) throws BeansException {
		return doGetBean(name, null, args, false);
	}


	public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
			throws BeansException {

		return doGetBean(name, requiredType, args, false);
	}

下面我们还是重点查看doGetBean的方法。

2、doGetBean

doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly)

  • name:bean的名字
  • requiredType:需要转换的类型
  • args:参数
  • typeCheckOnly:是否仅仅是类型检查

源码如下:

	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		//提取对应的bean
		final String beanName = transformedBeanName(name);
		Object bean;

		/**
		 * 检查缓存中或者实例中是否存在对应的实例
		 * 为什么要写这段代码呢 ——> 因为在创建单例的bean的时候会存在依赖注入的场景,而在创建依赖的时候为了避免循环依赖,Spring
		 * 容器在创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提前曝光,即将ObjectFactory加入缓存中,一旦下个bean
		 * 创建的时候依赖上个bean则直接使用ObjectFactory
		 *
		 */
		//先获取一次,若不为null,则会走缓存
		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 {
			//只有单例但setter注入可以解决循环依赖,原型模式但情况下,是不能解决循环依赖但问题,因为原型模式spring是不存入缓存的
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			BeanFactory parentBeanFactory = getParentBeanFactory();
			//若beanDefinitionMap中也就是在所有已经加载的类中不包括beanName,则会尝试从parentBeanFactory中检测
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {  //递归到BeanFactory中查找
					// 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) {
				//标记beanName,已创建
				markBeanAsCreated(beanName);
			}

			try {
				//将存储在XML配置文件的GernericBeanDefinition转换为RootBeanDefinition,
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				//若指定beanName是子Bean的时候同时会合并父类的相关属性
				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);
						}
					}
				}
				//实例化依赖的bean后可以实例化mbd(RootBeanDefinition)本身了
				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()) {
					//原型模式下创建一个新的实例
					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;
			}
		}

		//检查需要的类型是否符合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;
	}

看上去比较长,bean的加载经历一个相当长的复杂的过程,中间的各种场景的考虑。在加载的过程中所涉及到的几点:

1)beanName的转换

就是说转换成对应的beanName,有时候传进来的beanName是别名,也有可能是FactoryBean,因此需要进行转换。

	protected String transformedBeanName(String name) {
		return canonicalName(BeanFactoryUtils.transformedBeanName(name));
	}
BeanFactoryUtils.transformedBeanName(name)的定义如下:
	public static String transformedBeanName(String name) {
		Assert.notNull(name, "'name' must not be null");
		/**
		 * 去除BeanFactory的修饰符,即以 & 开头,例如若name="&TestBean",则首先去除 &
		 * 从而使得name="TestBean".
		 */
		//不以 & 开头
		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;
		});
	}
	public String canonicalName(String name) {
		//如果存在alias即别名,则会使用该别名最终所代表的bean的name
		String canonicalName = name;
		// Handle aliasing...
		String resolvedName;
		do {
			resolvedName = this.aliasMap.get(canonicalName);
			if (resolvedName != null) {
				canonicalName = resolvedName;
			}
		}
		while (resolvedName != null);
		return canonicalName;
	}

2)尝试从缓存中加载单例

Spring容器内的bean默认会被创建一次,之后在使用bean的时候直接从单例缓存中获取。这里只是尝试,如果加载不成功则再次尝试从singletonFactories中加载。在创建单例的时候可能会存在循环依赖的问题,这个问题可以看一下我上一篇博文的介绍:Spring循环依赖

3)bean的实例化

若是从缓存中得到的bean的原始状态,则还需要对其进行实例化。

bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);

注意:bean在缓存中记录的只是最原始的bean的状态,并不一定是我们最终想要的bean。

4)原型模式的依赖检查

       原型模式的情况是无法解决循环依赖的问题,因为在该模式下spring不对bean缓存,因而无法解决循环依赖。另外在说一点,构造器造成的循环依赖Spring也是无法解决的,因为在通过查看单例模式下setter注入解决循环依赖的前提条件是,对bean的提前曝光,提前曝光是通过bean的空参构造器来实现的。

5)检测parentBeanFactory

        判断条件:parentBeanFactory != null && !containsBeanDefinition(beanName)

        !containsBeanDefinition(beanName)  是在检测若当前加载的xml配置文件中不包含beanName所有的配置,就只能到parentBeanFactory去尝试了,然后在递归调用getBean.

6)将XML文件的GernericBeanDefinition转换为RootBeanDefinition。

7)寻找依赖

8)针对不同的scope创建bean。

9)类型转换

         在本文最初的getBean的几个方法中就可以看出,当需要做类型转换的时候会传入requiredType。如返回的bean其实是个String,但是requiredType传入的却是Integer类型,这个时候该步骤就起到作用了。

 

至此,bean的加载就算完成了。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值