Spring容器 —— 深入 bean 的加载(一、加载前的准备工作)

之前谈了有关bean 加载的大致过程。现在要仔细研究一下其中使用到的各个部分的内部原理。

FactoryBean

通常来说,Spring 通过反射机制利用 bean 的 class 属性实现类的加载实例化 bean。但在某些情况下,bean 的实例化比较复杂,需要更为灵活的配置方式,通过自定义编码会更好一些,FactoryBean 就是这样一个工厂类接口,用户可以通过实现 org.springframework.beans.factory.FactoryBean 接口定制实例化 bean 的逻辑。接口的源码如下。

public interface FactoryBean<T> {
	T getObject() throws Exception;
	Class<?> getObjectType();
	default boolean isSingleton() {
		return true;
	}
}
  • T getObject():返回由工厂创建的 bean 实例,如果是单例,则该实例会放到 Spring 容器中但是你缓存池中。
  • boolean isSingleton():返回工厂创建的实例是单例还是原型。
  • Class<?> getObjectType():返回 FactoryBean 创建的 bean 类型。

若在 bean 标签配置的 class 属性是 FactoryBean,那么最后 Spring 会调用 getObjectType() 方法返回最终结果。

缓存中获取单例 bean

首先我们看看源码。

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 直接检查在缓存中是否存在实例
		// Quick check for existing instance without full singleton lock
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			// 缓存中没有,但正在创建,就从早期缓存中寻找
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
				// 还是没有找到,锁定缓存空间,开始创建
				synchronized (this.singletonObjects) {
					// Consistent creation of early reference within full singleton lock
					// 再次检查缓存
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						// 再次检查早期缓存
						singletonObject = this.earlySingletonObjects.get(beanName);
						if (singletonObject == null) {
							// 看看工厂缓存中有没有
							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
							if (singletonFactory != null) {
								// 有工厂缓存,用工厂实例化
								singletonObject = singletonFactory.getObject();
								this.earlySingletonObjects.put(beanName, singletonObject);
								// earlySingletonObjects 和 singletonFactories互斥
								// 早期缓存中有工厂就需要被销毁了
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}

总结一下,缓存获取就是按顺序在三个缓存里寻找需要的 bean,顺序为 singletonObjectsearlySingletonObjectssingletonFactories,如果最终没有找到,那就直接返回 null。三个缓存的作用解释如下:

  • singletonObjects: 用于保存 BeanName 和创建 bean 实例之间的关系,即 bean namebean instance 的映射。
  • singletonFactories:用于保存 BeanName 和创建 bean 的工厂之间的关系,即 bean nameObjectFactory 的映射。
  • earlySingletonObjects: 也是保存 BeanName 和创建 bean 实例之间的关系,与 singletonObjects 的区别是当单例还在创建的时候,就可以放入当前缓存了,目的是为了检测循环应用。

从 bean 实例中获取对象

获取的 bean 实例可能是真正的实例也可能是 FactoryBean,如果是实例则直接返回,否则工厂创建。下面是具体源码。

protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
		
		// 如果是指定要 FactoryBean,但是实例不是 FactoryBean 则抛出异常
		// Don't let calling code try to dereference the factory if the bean isn't a factory.
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			// 若是空 bean,则直接返回
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
			}
		}

		// 如果是 FactoryBean,且 beanName 有 & 前缀,那么直接返回
		// 如果不是 FactoryBean,直接返回
		// Now we have the bean instance, which may be a normal bean or a FactoryBean.
		// If it's a FactoryBean, we use it to create a bean instance, unless the
		// caller actually wants a reference to the factory.
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}

		// 通过工厂创建 bean
		Object object = null;
		if (mbd == null) {
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			// Return bean instance from factory.
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// Caches object obtained from FactoryBean if it is a singleton.
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

总结一下流程:

  1. FactoryBean 的验证
  2. 对非 FactoryBean 不作处理
  3. 对 bean 进行转换
  4. 将从 Factory 中解析 bean 的工作委托给 getObjFromFactoryBean,也就是调用 getObject() 方法。

获取单例

通过以下源码获取单例。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(...);
				}
				...
				// 记录加载状态
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				...
				try {
					// 调用工厂实例化 bean
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					...
				}
				catch (BeanCreationException ex) {
					...
				}
				finally {
					...
					// 清除状态
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

总结一下,上述源码大致可以分为如下几步:

  1. 检查缓存是否已经加载过;
  2. 若没有加载,则记录 beanName 正在加载的状态;
  3. 加载单例前记录加载状态;
    将当前正要创建的 bean 记录到缓存中,这样便可以对循环依赖进行检测。
  4. 通过调用参数中的 ObjectFactory 实例化 bean;
  5. 加载单例后的处理方法调用;
    移出缓存中当前 bean 的正在加载状态。
  6. 将结果记录到缓存并删除加载 bean 过程中所记录的各种状态;
protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			this.singletonObjects.put(beanName, singletonObject);
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}
  1. 返回处理结果

准备创建 bean

首先看一下源码

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		...
		RootBeanDefinition mbdToUse = mbd;

		// 确保 class 解析完成
		// Make sure bean class is actually resolved at this point, and
		// clone the bean definition in case of a dynamically resolved Class
		// which cannot be stored in the shared merged bean definition.
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		...

		// Prepare method overrides.
		try {
			// 处理 override 属性
			mbdToUse.prepareMethodOverrides();
		}
		...

		try {
			// 应用初始化前的处理器,解析指定 bean 是否存在初始化前的短路操作
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		...

		try {
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			...
			return beanInstance;
		}
		...
	}

总结一下步骤:

  1. 根据设置的 class 属性或者根据 className 来解析 Class;
  2. 对 override 属性进行标记及验证;
  3. 应用初始化前的处理器,解析指定 bean 是否存在初始化前的短路操作;
  4. 创建 bean。

处理 override 属性

源码如下

protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
		// 获取对应类中方法名的个数
		int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
		if (count == 0) {
			throw new BeanDefinitionValidationException(
					"Invalid method override: no method with name '" + mo.getMethodName() +
					"' on class [" + getBeanClassName() + "]");
		}
		else if (count == 1) {
			// Mark override as not overloaded, to avoid the overhead of arg type checking.
			mo.setOverloaded(false);
		}
	}

这里并没有做什么更多的操作,只是判断了有多少个 override 属性,即多少个 lookup-method 和 replace-method 配置。
值得注意的是,对于方法的匹配来说,如果一个类中存在若干个重载方法,那么就需要在调用的时候进行参数匹配。这里 Spring 提前做了匹配。

实例化的前置处理

主要是调用 applyBeanPostProcessorsBeforeInstantiation()applyBeanPostProcessorsAfterInitialization()。其中实例化前的后处理器是为了给子类一个修改 BeanDefinition 的机会。实例化后的后处理器调用主要是因为 bean 可能在实例化前的后置处理器中已经初始化了,之后就不会再进入上层函数的实例化后的后置处理器,这里需要提前调用一次。

这里提到了后置处理器,这个主要是 Spring 为了给用户提供扩展的。

至此,bean 创建的准备工作才算做完了,我们可以继续看看创建 bean 的实际内容了。bean 创建.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值