spring源码12: spring创建Bean

创建bean前准备

如果使用调试模式,跟进来下面代码倒不会有什么疑问,但是这一步代码的跳转确十分奇特,值得去探究一番。
在上一节讲到,首先spring在AbstractBeanFactory类中创建了ObjectFactory的对象,并重写了getObject()方法,然后将他传给DefaultSingletonBeanRegistry。此时DefaultSingletonBeanRegistry调用了singletonFactory.getObject()getObject()又调用了creatBean(),因此实际调用的是AbstractBeanFactory类的creatBean()。而AbstractBeanFactory类又被AbstractAutowireCapableBeanFactory所继承,并且重写了其creatBean(),因此最后调用的就是以下代码

// AbstractAutowireCapableBeanFactory.java
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;

		// 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.
		// 1. 锁定class,确保能根据class,className属性正确获取到对应class
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			// 设置上一步获取到的Class
			mbdToUse.setBeanClass(resolvedClass);
		}

		// Prepare method overrides.
		try {
			// 2. 校验和准备覆盖的方法(指:lookup-method, replace-method)
			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.
			/**
			 * 3. 实例化前的后置处理器
			 * 给BeanPostProcessors一个机会返回代理替换调真实的实例,主要是来执行实现了InstantiationAwareBeanPostProcessor接口的BeanPostProcessor
			 * AOP核心方法,具体内容到AOP再解答
			 */
			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 {
			// 4. 核心逻辑
			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,首先得告诉spring你要创建的bean是哪个类,这个类存不存在,能不能解析

  1. 检验及准备lookup-methodreplace-method方法
	public void prepareMethodOverrides() throws BeanDefinitionValidationException {
		// Check that lookup methods exist and determine their overloaded status.
		if (hasMethodOverrides()) {
			// 循环检查override方法是否存在,有无重载
			getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
		}
	}
	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() + "]");
		}
		// 有且仅有1个,则说明没有重载,后续可以直接用。如果有重载后续还得进行解析,看看哪个重载方法最适合
		else if (count == 1) {
			// Mark override as not overloaded, to avoid the overhead of arg type checking.
			mo.setOverloaded(false);
		}
	}

  1. 实例化前置处理,这是目前接触到的第一个后置处理器(墙裂推荐看一下后置处理器的使用:spring BeanPostProcessor 生命周期),目前还未开始实例化bean,但是在下一段代码doCreateBean(),将马上开始bean的实例化,因此在这里调用实例化前的before后置处理器是合适的。大家到这里只要知道一下后置处理器是怎么用的就行,一般来说这里都是返回null。(需要了解一下AOP的targetSource代理就是在这里完成的,一旦被AOP接手,将通过cglib会生成一个完全不同bean,并且是已经实例化、填充、初始化过的,因此一旦bean不为空则需要应用初始化的after后置处理,然后直接返回代理bean,不再继续往下创建。)
	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		// 确认bean在初始化阶段之前
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				// 确认当前beanName所要返回的最终类型
				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;
	}
	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;
	}

上方代码频繁出现InstantiationAwareBeanPostProcessors,该类是一个后置处理器接口。如下,总的有4个方法,1、2两个是用在实例化前后,3、4则是用在属性填充步骤的。也就是说只要有类实现了该接口,且重写了相关方法,则后续所有bean的创建都将被重写的方法所修改。所以后置处理器并不复杂,只是一个调用的过程,难的是有多少子类继承了它,这些子类又进行了哪些处理的操作?比如@AutowiredAOP等等,子类太多肯定无法每个都吃透,后续我们会单独挑出@Autowired详解,看看@Autowired是如何通过重写这些方法达到自动注入的目的spring源码16: @Autowired实现原理

InstantiationAwareBeanPostProcessors.png


  1. 看到do了吗,之前说过do才是真正干活的方法!这才是真真真真真核心逻辑。

创建bean

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

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			// 是单例的情况下清空缓存
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			/**
			 * 1. 实例化bean,这一阶段是调用构造器生产实例的阶段
			 * 
			 * 如果有使用@Autowired构造器注入,则在该阶段完成属性的注入。
			 * (注意这里是Autowired构造器,而不是我们正常使用的注解在属性上)
			 * @Autowired
			 * public Outer(Inner inner) {
			 * 	this.inner = inner;
			 * }
			 */
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Allow post-processors to modify the merged bean definition.
		/**
		 * 	2. beanDefinition合并后的后置处理
		 * 	比如@Autowired在属性上,就是在这里解析的,但是仅仅只是单纯的解析,还没有实现注入
		 */
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		// 当mbd是单例,且允许循环引用,且正在被创建,则提前曝光该对象
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			// 3. 将该bean提前曝光,具体做法是创建一个ObjectFactory对象,再将对象加入到singletonFactories缓存中
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			//
			/**
			 * 4. 填充属性
			 * 如果@Autowired注解属性,则在上方完成解析后,在这里完成注入
			 *
			 * @Autowired
			 * private Inner inner;
			 */
			populateBean(beanName, mbd, instanceWrapper);
			// 5. 初始化
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		// 6. 被依赖检测
		/**
		 * 假设  B, C, D均依赖A,当前正在创建A
		 * dependentBeanMap的key = A, value = B, C, D
		 * 要检测的是B, C, D是否正确注入了A,而不是要检测A,所以叫被依赖检测
		 */
		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				// exposedObject跟bean一样,说明初始化操作没用应用Initialization后置处理器改变exposedObject
				// 注意一下这里用的 == 号,说明是引用是否相等的判断
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				// 引用都不相等了,也就是现在的bean已经不是当时提前曝光的bean了
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					// dependentBeans也就是B, C, D
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					// 循环 B, C, D
					for (String dependentBean : dependentBeans) {
						/**
						 * 如果B, C, D已经创建完了,那么他们拿到的肯定是A提前曝光的引用
						 *
						 * 但是这个判断又说明了现在的bean已经不是提前曝光的那个bean了,那这样B, C, D注入的A就是有问题的,抛出异常
						 * 这里有非的条件,里层也个非,需要留心这个逻辑
 						 */
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}

					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			// 7. 根据scope注册bean
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}
  1. instance(实例化),也就是调用构造函数,new出对应Class对象的过程。其中根据参数类型还分为有参构造函数跟无参构造函数,又根据是否有override函数分为JDK代代理和cglib代理。后面做详解
  2. 又是一个后置处理器(再强调一下后置处理器不会用的先看spring BeanPostProcessor 生命周期),跟之前说的一样,只不过是调用子类重写的方法,后面我们详细看一下@Autowired如何通过后置处理器注入属性spring源码16: @Autowired实现原理
  3. 循环依赖提前曝光。在单例模式下,如果允许循环引用,则曝光当前实例。该做法就是当bean只是刚实例化完,还没进行属性填充以及初始化,spring就先将当前实例曝光出去,这样其他bean就可以在当前bean尚未创建完成就获取到当前bean的引用。下一节单独详解
  4. populateBean(属性填充),将所有属性填充到bean实例中
  5. initializeBean(初始化)
  6. 被依赖检测(这点了解即可,要看懂不容易,可以考虑学完IOC以后再去深究)。很明显这里多加了一个"被"字!假设B, C, D依赖A,现在正常创建A。如果说B, C, D已经完成了创建,则B, C, D必然已经注入了A,但是被注入的A是提前曝光的版本,现在A经过初始化后变成了新的对象A2(这一步一般是不会发生的),因此B, C, D引用的A是错误的,正确应该引用A2,所以抛出异常。
    做一个测试,让A注入B,B注入A,同时在A初始化时生成一个全新的A,结果就会抛出该异常
// 省略getter、setter
public class A {
	@Autowired
	private B b;
}

public class B {
	@Autowired
	private A a;
}

public class ABeanPostProcessor implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if (bean instanceof A) {
			A a = new A();
			a.setB(((A) bean).getB());
			bean = a;
		}
		return bean;
	}
}

// XML
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<bean id="a" class="A"/>
	<bean id="b" class="B"/>

	<bean id="myBeanPostProcessor" class="ABeanPostProcessor"/>
	<context:component-scan base-package="autowire"/>
</beans>

// 报错信息
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Bean with name 'a' has been injected into other beans [b] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.

  1. 根据不同的scope注册bean,其中destroy-method销毁方法也是在这里注册的

完成创建并返回,接下去会详细介绍上面的步骤,包括循环依赖、实例化、属性填充、初始化、以及@Autowired的注入

发布了30 篇原创文章 · 获赞 9 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/chaitoudaren/article/details/104833567