序言

前面几篇文章介绍了Spring中几种方式下Bean对象的实例化的过程,那如果之前的几种都不满足,按照Spring中正常Bean的实例化步骤,该如何创建这个Bean对象呢?

测试类

我们先创建几个debug中用到的栗子。

Person
以一个平平无奇的Person对象的创建为切入点。

public class Person {
	// 省略了get set和构造方法,但是debug过程中构造方法很重要。
	private String name;
	private int age;
}	

person.xml
xml中bean标签配置了person对象信息,并且设置了scope = prototype以及<constructor-arg>。注释掉的<property>标签其实加载逻辑和<constructor-arg>是一样的,我们这里拿<constructor-arg>为例。

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

	<bean id="person" class="org.springframework.factoryMethod.Person" scope="prototype">
		<bean id="person" class="org.springframework.factoryMethod.Person" scope="prototype">
<!--		<property name="age" value="22"/>-->
<!--		<property name="name" value="李四"/>-->
		<constructor-arg name="age" value="18"/>
		<constructor-arg name="name" value="张三"/>
	</bean>
	</bean>
</beans>

main

public class ConstructorTest {
	public static void main(String[] args) {
		ApplicationContext ac = new ClassPathXmlApplicationContext("person.xml");
		Person p1 = (Person)ac.getBean("person");
		Person p2 = (Person)ac.getBean("person");
	}
}

所以根据我们在xml中的配置,在Person(p1)对象实例化中的流程大体如下:

  1. 获取构造器方法列表(因为类中可能定义很多的构造器方法)
  2. 遍历构造器,获取当前构造器方法的参数名称(name,age)
  3. 获取xml中配置的我们配置的具体属性值(18,张三)
  4. 将获取到的参数名称、值与构造器方法做匹配
  5. 计算构造器权重,确认最终使用的构造器
  6. 缓存当前所使用的的构造器方法,实例化Bean对象。

而当我们p2对象进行实例化时,就可以直接从缓存中进行获取。无需再重新遍历。

主流程方法

接下来我们回到doCreateBean的主流程方法中的createBeanInstance方法中,接着往下看。

doCreateBean

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

		// Instantiate the bean.
		//这个beanWrapper是用来持有创建出来的bean对象的
		BeanWrapper instanceWrapper = null;

		//如果是单例对象,从factoryBeanInstanceCache缓存中移除该信息
		if (mbd.isSingleton()) {
			// 如果是单例对象,从factoryBean实例缓存中移除当前bean定义信息
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		// 没有就创建实例
		if (instanceWrapper == null) {
			// 根据执行bean使用对应的策略创建新的实例,如,工厂方法,构造函数主动注入、简单初始化
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		//省略部分代码
		return exposedObject;
	}

createBeanInstance
debug时省略了之前提到的SupplierFactoryMethod创建方法的步骤,我们直接从boolean resolved = false;开始看。

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
		// 锁定class,根据设置的class属性或者根据className来解析class
		Class<?> beanClass = resolveBeanClass(mbd, beanName);
		// 如果beanClass != null
		// 并且,访问修饰符不是public修饰, 抛异常
		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
			throw new BeanCreationException;
		}
		// 获取Supplier
		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		// 如果不为null,
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}
		//如果工厂方法不为null,则采用工厂方法来实例化
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
		//标记下,防止重复创建一个Bean
		boolean resolved = false;
		//是否需要自动装配
		boolean autowireNecessary = false;
		//如果args为null,则进行同步锁,获取构造方法
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				//如果已经解析了构造方法或工厂方法
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		//如果已经解析了构造方法或工厂方法
		if (resolved) {
			//构造器有参数
			if (autowireNecessary) {
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				//使用默认的无参构造
				return instantiateBean(beanName, mbd);
			}
		}

		// Candidate constructors for autowiring?
		//从SmartInstantiationAwareBeanPostProcessor中确认我们的构造器
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// Preferred constructors for default construction?
		//获取首选的构造器,方法return null 自己自定义扩展
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
			return autowireConstructor(beanName, mbd, ctors, null);
		}

		// No special handling: simply use no-arg constructor.
		// 如果没有特殊处理,则采用无参构造器来实例化对象
		return instantiateBean(beanName, mbd);
	}

此时来到了p1对象的创建,设置resolved等标志位后,因为此时缓存中resolvedConstructorOrFactoryMethod == null,所以并不会进到下面的判断。
在这里插入图片描述

此时resolvedConstructorOrFactoryMethod == null,并不会修改resolved的值,等到下面的 if 判断,因为在xml中设置了构造器参数,所以此时mbd.hasConstructorArgumentValues()返回true,能够进到判断中,接下来我们看autowireConstructor方法。
在这里插入图片描述
而我们的atowireMode共有5种,我们这里没有配置,所以no。
在这里插入图片描述

autowireConstructor

protected BeanWrapper autowireConstructor(
			String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {

		return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
	}

创建Bean实例的整体流程。

public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
			@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {

		//创建BeanWrapperImpl对象
		BeanWrapperImpl bw = new BeanWrapperImpl();
		//初始化bw (设置ConversionService和工厂中所有的PropertyEditor) 用来属性转换
		this.beanFactory.initBeanWrapper(bw);


		Constructor<?> constructorToUse = null;
		ArgumentsHolder argsHolderToUse = null;
		Object[] argsToUse = null;
		//如果有传入的参数,则直接使用
		if (explicitArgs != null) {
			argsToUse = explicitArgs;
		}
		else {
			//声明一个要解析的args数组,默认为null
			Object[] argsToResolve = null;
			synchronized (mbd.constructorArgumentLock) {
				//将beanDefinition中解析完的构造函数和参数
				constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
				//BeanDefinition中存在解析过的构造函数和参数 && 存在构造函数参数
				if (constructorToUse != null && mbd.constructorArgumentsResolved) {
					// Found a cached constructor...
					//从缓存中找到了构造器,继续从缓存中找准备好的构造器参数
					argsToUse = mbd.resolvedConstructorArguments;
					if (argsToUse == null) {
						argsToResolve = mbd.preparedConstructorArguments;
					}
				}
			}
			// 如果缓存中存在解析好的参数,解析配置的参数
			if (argsToResolve != null) {
				argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
			}
		}
		//如果缓存中没有解析好的构造器函数 || 参数构造器参数为空
		if (constructorToUse == null || argsToUse == null) {
			// Take specified constructors, if any.
			// 如果传入的chosenCtors不为null,则使用chosenCtors,否则通过反射获取类中定义的构造器函数
			Constructor<?>[] candidates = chosenCtors;
			if (candidates == null) {
				Class<?> beanClass = mbd.getBeanClass();
				try {
					candidates = (mbd.isNonPublicAccessAllowed() ?
							beanClass.getDeclaredConstructors() : beanClass.getConstructors());
				}
				catch (Throwable ex) {
					throw new BeanCreationException;
				}
			}
			//如果只有1个候选的构造器函数 && 传入参数explicitArgs = null && mbd中也没有构造器函数参数值
			if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
				//获取当前构造器函数
				Constructor<?> uniqueCandidate = candidates[0];
				//如果唯一的构造器函数的参数个数为0,则直接使用
				if (uniqueCandidate.getParameterCount() == 0) {
					synchronized (mbd.constructorArgumentLock) {
						//mbd中缓存解析好的构造器函数或工厂方法
						mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
						//mbd中标记构造器参数已解析
						mbd.constructorArgumentsResolved = true;
						//mbd中缓存解析好的构造器参数为EMPTY_ARGS
						mbd.resolvedConstructorArguments = EMPTY_ARGS;
					}
					//通过反射进行bean的实例化并返回
					bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
					return bw;
				}
			}

			// Need to resolve the constructor.
			// 1.如果传入的chosenCtors参数不为null
			// 2.autowireMode 选择的是构造器注入的方式(AUTOWIRE_CONSTRUCTOR)
			// 有以上两种情况之一:说明需要自动装配,设置autowiring为true
			boolean autowiring = (chosenCtors != null ||
					mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
			ConstructorArgumentValues resolvedValues = null;

			//构造器的最小参数个数
			int minNrOfArgs;
			//如果传入的explicitArgs不为null,则minNrOfArgs = explicitArgs.length
			if (explicitArgs != null) {
				minNrOfArgs = explicitArgs.length;
			}
			else {
				//获取配置文件中配置的构造器参数
				ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
				//创建ConstructorArgumentValues对象,
				resolvedValues = new ConstructorArgumentValues();
				//解析参数个数
				minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
			}
			//将符合条件的构造器方法进行排序
			AutowireUtils.sortConstructors(candidates);
			// 定义一个差异变量,变量的大小决定着构造函数是否能够被使用
			int minTypeDiffWeight = Integer.MAX_VALUE;
			// 不明确的构造函数集合,正常情况下差异值不可能相同
			Set<Constructor<?>> ambiguousConstructors = null;
			//定义一个用于UnsatisfiedDependencyException的列表
			LinkedList<UnsatisfiedDependencyException> causes = null;

			//遍历获取到的构造方法
			for (Constructor<?> candidate : candidates) {
				//获取每个构造方法的参数个数
				int parameterCount = candidate.getParameterCount();
				// 1. 已经找到选用的构造函数
				// 2. 需要的参数个数小于当前的构造函数参数个数则终止,前面已经经过了排序操作
				if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) {
					// Already found greedy constructor that can be satisfied ->
					// do not look any further, there are only less greedy constructors left.
					break;
				}
				// 当前构造器函数所需参数数量 < 要求的参数数量,跳过,遍历下一个
				if (parameterCount < minNrOfArgs) {
					continue;
				}

				ArgumentsHolder argsHolder;
				//获取构造器所需参数类型数组
				Class<?>[] paramTypes = candidate.getParameterTypes();
				if (resolvedValues != null) {
					try {
						// 获取构造函数上的ConstructorProperties注解中的参数
						String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
						//如果没有上面注解,则获取构造器方法参数列表中的属性名称
						if (paramNames == null) {
							ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
							if (pnd != null) {
								//获取指定的构造器参数名称
								paramNames = pnd.getParameterNames(candidate);
							}
						}
						// 根据名称和数据类型创建argsHolder对象
						argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
								getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
					}
					catch (UnsatisfiedDependencyException ex) {
						// Swallow and try next constructor.
						if (causes == null) {
							causes = new LinkedList<>();
						}
						causes.add(ex);
						continue;
					}
				}
				//不存在构造函数参数列表需要解析的参数
				else {
					// Explicit arguments given -> arguments length must match exactly.
					// 如果参数列表的数量与传入进来的参数数量不相等,继续遍历,否则构造参数列表封装对象
					if (parameterCount != explicitArgs.length) {
						continue;
					}
					// 构造函数没有参数的情况
					argsHolder = new ArgumentsHolder(explicitArgs);
				}

				// 计算差异量,根据要参与构造函数的参数列表和本构造函数的参数列表进行计算
				// 省略这部分代码

			// 存在两种情况
			// 1. 没有确定使用的构造器函数
			// 2、存在模糊的构造函数并且不允许存在模糊的构造函数
			if (constructorToUse == null) {
				if (causes != null) {
					UnsatisfiedDependencyException ex = causes.removeLast();
					for (Exception cause : causes) {
						this.beanFactory.onSuppressedException(cause);
					}
					throw ex;
				}
				throw new BeanCreationException;
			}
			else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
				throw new BeanCreationException;
			}
			/**
			 * 没有传入参与构造函数参数列表的参数时,对构造函数缓存到BeanDefinition中
			 * 	1、缓存BeanDefinition进行实例化时使用的构造函数
			 * 	2、缓存BeanDefinition代表的Bean的构造函数已解析完标识
			 * 	3、缓存参与构造函数参数列表值的参数列表
			 */
			if (explicitArgs == null && argsHolderToUse != null) {
				argsHolderToUse.storeCache(mbd, constructorToUse);
			}
		}
		bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
		return bw;
	}

debug

具体流程
方法开始会创建BeanWrapper对象并初始化,初始化时会设置conversionService和注册BeanFactory中所有的Editors,目的是将值进行转换,因为我们在xml中配置的具体value都是字符串,比如说 age,而我们在具体类中对应的是Integer,在这里初始化后等到赋值时可以直接用。

protected void initBeanWrapper(BeanWrapper bw) {
		bw.setConversionService(getConversionService());
		registerCustomEditors(bw);
	}

声明构造器变量以及参数变量,因为我们此时对象还没有加载,所以缓存中constructorArgumentsResolvedargsToResolve等变量目前都为null,所以这些判断都进不去。
在这里插入图片描述


缓存中没有,所以我们需要获取当前实例中的所有构造器,并挑选一个符合条件的作为我们Bean的实例的容器。当前Person对象中我定义了一个无参构造器和一个包含name和age的构造器方法,所以这里candidates长度为2.
在这里插入图片描述


如果只获取到了一个构造器方法 && 没有构造器函数的参数值(mbd.hasConstructorArgumentValues()) && 也没有传入显示指定的参数(explicitArgs == null
则直接使用instantiate进行Bean的实例化,并设置缓存resolvedConstructorOrFactoryMethodconstructorArgumentsResolvedresolvedConstructorArguments
我们这里有两个构造器参数,所以进不来。
在这里插入图片描述


看是否需要进行自动装配
chosenCtors是方法的传参,这里是null,并且我们也没有在xml中配置 autowiring 属性,所以这里也进不来。
在这里插入图片描述


上面所有的条件都不满足,接下来就要根据我们获得的构造器方法列表和xml中配置的定义属性来挑选一个符合条件的构造器,作为对象实例化加载的容器。

获取到xml中配置的构造器参数。
在这里插入图片描述
解析参数个数,赋值给resolevedValues变量中。并将获取到的构造器进行排序操作。

排序:排序操作很重要,因为如果类中属性特别多,那么对应的生成的构造函数也可能会特别多,排序后再遍历会将不符合条件的直接continue,效率会大大提升。
在这里插入图片描述


遍历我们获取到的构造方法,因为做了排序,所以此时来到的是 name,age的构造方法。
如果已经在缓存中找到了构造函数 && 当前构造函数的参数个数(parameterCount) < 具体实例化时要用到的参数个数(argsToUse)。
说明没有再继续遍历的必要了,直接break。
如果当前构造方法的参数个数(parameterCount) < 我们需要实例化最小的参数个数 (minNrOfArgs),跳过这次循环 continue(当我们第二次循环condidates集合时,来到了无参构造,就会直接continue)
在这里插入图片描述


获取构造方法中的参数名称。
在这里插入图片描述


根据我们解析到xml中的值和当前构造方法的paramNames,创建并封装成argsHolder对象。
在这里插入图片描述


Spring中会计算每个构造器的权重,并通过逻辑选出最适合当前的构造器参数。
在这里插入图片描述


此时,将最终确认的构造器以及参数进行缓存。并调用instantiate方法进行bean的实例化创建并返回。
在这里插入图片描述

public void storeCache(RootBeanDefinition mbd, Executable constructorOrFactoryMethod) {
			synchronized (mbd.constructorArgumentLock) {
				mbd.resolvedConstructorOrFactoryMethod = constructorOrFactoryMethod;
				mbd.constructorArgumentsResolved = true;
				if (this.resolveNecessary) {
					mbd.preparedConstructorArguments = this.preparedArguments;
				}
				else {
					mbd.resolvedConstructorArguments = this.arguments;
				}
			}
		}

此时!我们的p1对象已经创建完成,当我们p2对象再次进行创建时。
缓存中不为null,设置我们的resolved 和 autowireNecessary变量为true。
在这里插入图片描述


再次调用autowireConstructor方法时。缓存不为null直接从缓存中找。找到后直接调用instantiate方法进行bean的实例化。(只有xml中配置 scope=“prototype” 才可以看到效果,不然创建完p1后直接放入 singletonObjects 缓存, 等到p2创建直接从singletonObjects中获取了)

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部