十、Spring 源码解析之 bean 的加载流程五: 准备创建bean

  我们不可能指望在一个函数中完成一个复杂的逻辑,而且我们或多或少发现一些规律:一个真正干活的函数其实是以 do 开头的,比如 FactoryBeanRegistrySupport#doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName);而给我们错觉的函数,比如 FactoryBeanRegistrySupport#getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) 其实只是从全局角度去做一些统筹的工作。这个规则对 九、Spring 源码解析之 bean 的加载流程四: 从缓存中获取不到单例 bean时,获取单例处理 文章最后提到的 createBean() 方法也不例外。 createBean() 方法是一个抽象方法,真正实现是 AbstractAutowireCapableBeanFactory#createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args),让我们看看 createBean() 方法做了哪些准备工作。

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

		if (logger.isTraceEnabled()) {
			logger.trace("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;

		//锁定 class,根据设置的 class 属性或者根据 className 来解析 class
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		// Prepare method overrides.
		try {
			/*
			 * 对 override 属性进行标记及验证
			 *     在 Spring 中确实没有 `override-method` 这样的配置,但是在 Spring 配置中是存在 `lookup-method` 和
			 * `replace-method` 的,而这两个配置的加载其实就是将配置统一存放在 `BeanDefinition` 中的 `methodOverrides`
			 * 属性里,而这个函数的操作其实也就是针对于这两个配置的。
			 */
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
			//给 BeanPostProcessors 一个机会来返回代理来替代真正的实例
			//应用初始化前的后处理器,解析指定 bean 是否存在初始化前的短路操作
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
			//创建 bean
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			// A previously detected exception with proper bean creation context already,
			// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

该方法的具体步骤及功能:

  1. 根据设置的 class 属性或者根据 className 来解析 Class
  2. 对 override 属性进行标记及验证
      在 Spring 中确实没有 override-method 这样的配置,但是在 Spring 配置中是存在 lookup-methodreplace-method 的,而这两个配置的加载其实就是将配置统一存放在 BeanDefinition 中的 methodOverrides 属性里,而这个函数的操作其实也就是针对于这两个配置的。
  3. 应用初始化前的后处理器,解析指定 bean 是否存在初始化前的短路操作
  4. 创建 bean。
      我们首先来看下对 override 属性标记及验证的逻辑实现。

一、处理 override 属性

  查看源码中 AbstractBeanDefinition#prepareMethodOverrides() 方法:

	public void prepareMethodOverrides() throws BeanDefinitionValidationException {
		// Check that lookup methods exists.
		if (hasMethodOverrides()) {
			Set<MethodOverride> overrides = getMethodOverrides().getOverrides();
			synchronized (overrides) {
				for (MethodOverride mo : overrides) {
					prepareMethodOverride(mo);
				}
			}
		}
	}

	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.
			//标记 MethodOverride 暂未被覆盖,避免参数类型检查的开销
			mo.setOverloaded(false);
		}
	}

  之前提到过,在 Spring 配置中存在 lookup-methodreplace-method 两个配置功能,而这两个配置的加载其实就是将配置统一存放在 BeanDefinition 中的 methodOverrides 属性里,这两个功能实现原理其实是在 bean 实例化的时候如果检测到存在 methodOverrides 属性,会动态为当前 bean 生成代理并使用对应的拦截器为 bean 做增强处理,相关逻辑实现在 bean 的实例化部分详细介绍。
  但是,这里提到的是,对于方法的匹配来讲,如果一个类中存在若干个重载的方法,name,在函数调用及增强的时候还需要根据参数类型进行匹配,来最终确认当前调用的到底是哪个函数。但是,Spring 将一部分匹配工作在这里完成了,如果当前类中的方法只有一个,那么久设置重载该方法没有被重载,这样在后续调用的时候便可以直接使用找到的方法,而不需要进行方法的参数匹配验证了,而且还可以提前对方法存在性进行验证

二、实例化的前置处理

  在真正调用 doCreate() 方法创建 bean 的实例前使用了这样一个方法 resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd)BeanDefinition 中的属性做些前置处理。当然,无论其中是否有相应的逻辑实现我们都可以理解,因为真正逻辑实现前后留有处理函数也是可扩展的一种体现,但是这不是最重要的,在函数中还提供了一个短路判断,这才是最为关键的部分。

			if (bean != null) {
				return bean;
			}

  当经过前置处理后返回的结果如果不为空,那么会直接略过后续的 bean 的创建而直接返回结果。这一特性虽然很容易被忽略,但是却起着至关重要的作用,我们熟知的 AOP 功能就是基于这里的判断的。

	@Nullable
	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		//如果尚未被解析
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

  此方法中最吸引我们的无疑是两个方法 applyBeanPostProcessorsBeforeInstantiation()applyBeanPostProcessorsAfterInitialization() 。这两个方法实现的非常简单,无非是对后处理器中的所有 InstantiationAwareBeanPostProcessor 类型的后处理器进行 postProcessBeforeInstantiation() 处理和所有 BeanPostProcessor 类型的后处理器进行 postProcessAfterInitialization() 处理。

1.实例化前的后处理器应用

	@Nullable
	protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
				if (result != null) {
					return result;
				}
			}
		}
		return null;
	}

  bean 的实例化前调用,也就是将 AbstractBeanDefinition 转换为 BeanWrapper 前的处理。给子类一个修改 BeanDefinition 的机会,也就是说当程序经过这个方法后,bean 可能已经不是我们认为的 bean 了,而是或许成为一个经过处理的代理 bean,也可能是通过 cglib 生成的,也可能是通过其他技术生成的。在这里我们只需要知道,在 bean 的实例化前后调用后处理器的方法进行处理。

2.实例化后的后处理器应用

  在讲解从缓存中获取单例 bean 的时候就提到过,Spring 中的规则是在 bean 的初始化后尽可能保证将注册的后处理器的 postProcessAfterInitialization() 方法应用到该 bean 中,因为如果返回得到 bean 不为空,那么便不会再次经历普通 bean 的创建过程,所以只能在这里应用后处理器的 postProcessAfterInitialization() 方法。

	@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}
发布了444 篇原创文章 · 获赞 113 · 访问量 40万+

猜你喜欢

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