Spring Ioc源码分析系列--容器实例化Bean的四种方法

Spring源码之bean的实例化createBeanInstance方法解读 目录前言 前言 这篇文章是 IOC 容器初始化启动时,抽象类 AbstractAutowireCapableBeanFactory 的 doCreateBean() 方法里面的 createBeanInstance() 方法,顾名思义是 bean 的实例化方法。 阅读本篇文章,同时可以参考阅读 spring源码之getBean(获取 bean)方法解读(二) 和 spring aop代理对象的产生(一) 这两篇文章的 doCreateBean() 方法 ... 阅读详情

🚀 优质资源分享 🚀

学习路线指引(点击解锁)知识定位人群定位
🧡 Python实战微信订餐小程序 🧡进阶级本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
💛Python量化交易实战💛入门级手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

Spring Ioc源码分析系列–实例化Bean的几种方法

前言

前面的文章Spring Ioc源码分析系列–Bean实例化过程(二)在讲解到bean真正通过那些方式实例化出来的时候,并没有继续分析了,而是留到了这里去分析,主要是因为获取获取构造函数,推断构造函数也是一个比较复杂的操作,就想另起一篇文章再说,但是总的来说,应该不会比前面的逻辑绕,因为这里很清晰,就是实例化对象的几种方法,那么实例化对象有哪几种选择呢?没印象,那说明前面的文章没留下影响,回去翻翻。所以废话少说,跟着上面文章的口子,我们来分析实例化bean的过程。

源码分析

首先,这里回忆一下之前说到什么。

本篇文章的核心逻辑入口是在AbstractAutowireCapableBeanFactory#createBeanInstance()方法里。
跟进createBeanInstance(beanName, mbd, args)方法。这个方法干了哪几件事?

  • 首先尝试调用obtainFromSupplier()实例化bean
  • 尝试调用instantiateUsingFactoryMethod()实例化bean
  • 根据给定参数推断构造函数实例化bean
  • 以上均无,则使用默认构造函数实例化bean

先贴一下代码,然后逐个分析。

	/**
 * Create a new instance for the specified bean, using an appropriate instantiation strategy:
 * factory method, constructor autowiring, or simple instantiation.
 *
 * 使用适当的实例化策略为指定的 bean 创建一个新实例:工厂方法、构造函数自动装配或简单实例化。
 *
 * @param beanName the name of the bean
 * @param mbd the bean definition for the bean
 * @param args explicit arguments to use for constructor or factory method invocation
 * @return a BeanWrapper for the new instance
 * @see #obtainFromSupplier
 * @see #instantiateUsingFactoryMethod
 * @see #autowireConstructor
 * @see #instantiateBean
 */
	protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
		// 确保此时实际解析了 bean 类。
		Class beanClass = resolveBeanClass(mbd, beanName);

		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}
		// 通过bd中提供的instanceSupplier来获取一个对象
		// 正常bd中都不会有这个instanceSupplier属性,这里也是Spring提供的一个扩展点,但实际上不常用
		Supplier instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}

		//如果工厂方法不为null,则使用工厂方法初始化策略
		// bd中提供了factoryMethodName属性,那么要使用工厂方法的方式来创建对象,
		// 工厂方法又会区分静态工厂方法跟实例工厂方法
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
		// 在原型模式下,如果已经创建过一次这个Bean了,那么就不需要再次推断构造函数了
		// 是否推断过构造函数
		boolean resolved = false;
		// 构造函数是否需要进行注入
		boolean autowireNecessary = false;
		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?
		//需要根据参数解析构造函数
		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?
		// 默认构造的首选构造函数?
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
			return autowireConstructor(beanName, mbd, ctors, null);
		}

		// No special handling: simply use no-arg constructor.
		//使用默认构造函数
		return instantiateBean(beanName, mbd);
	}


使用Supplier实例化bean

这一块的逻辑对应如下

		// 通过bd中提供的instanceSupplier来获取一个对象
		// 正常bd中都不会有这个instanceSupplier属性,这里也是Spring提供的一个扩展点,但实际上不常用
		Supplier instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}

Supplier在Spring里面的使用是相对比较新的,看了一个代码的commit记录,这一块的代码是在2016年12月19号加上的,相对来说还是比较新的。

Supplier就是一个Java 8提供的函数式编程接口,里面提供一个get()方法,可以通过这个方法实例化bean对象。

@FunctionalInterface
public interface Supplier {

 /**
 * Gets a result.
 *
 * @return a result
 */
 T get();
}

跟进obtainFromSupplier()方法,可以看到逻辑是比较简单的,通过一个NamedThreadLocal设置依赖关系beanName,然后调用instanceSupplier.get()获取对象,随后包装成一个BeanWrapper返回。

	/**
 * Obtain a bean instance from the given supplier.
 *
 * 从给定的 supplier 处获取一个 bean 实例。
 *
 * @param instanceSupplier the configured supplier
 * @param beanName the corresponding bean name
 * @return a BeanWrapper for the new instance
 * @since 5.0
 * @see #getObjectForBeanInstance
 */
	protected BeanWrapper obtainFromSupplier(Supplier instanceSupplier, String beanName) {
		Object instance;

		// 这里是处理 Supplier 创建的 bean 的内外部名称依赖关系
		String outerBean = this.currentlyCreatedBean.get();
		this.currentlyCreatedBean.set(beanName);
		try {
			// 调用 get() 方法获取对象
			instance = instanceSupplier.get();
		}
		finally {
			if (outerBean != null) {
				this.currentlyCreatedBean.set(outerBean);
			}
			else {
				this.currentlyCreatedBean.remove();
			}
		}

		if (instance == null) {
			instance = new NullBean();
		}
		BeanWrapper bw = new BeanWrapperImpl(instance);
		initBeanWrapper(bw);
		return bw;
	}

使用工厂方法实例化bean

简介

这一块的代码逻辑对应如下

		//如果工厂方法不为null,则使用工厂方法初始化策略
		// bd中提供了factoryMethodName属性,那么要使用工厂方法的方式来创建对象,
		// 工厂方法又会区分静态工厂方法跟实例工厂方法
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

跟进instantiateUsingFactoryMethod()方法,可以看到这里先new了一个ConstructorResolver,这个ConstructorResolver非常重要,它会去推断合适的构造函数。实例化bean另起这篇文章来写,很大程度就是因为这个ConstructorResolver,我想写清楚一点。

	/**
 * Instantiate the bean using a named factory method. The method may be static, if the
 * mbd parameter specifies a class, rather than a factoryBean, or an instance variable
 * on a factory object itself configured using Dependency Injection.
 *
 * 使用命名工厂方法实例化 bean。
 * 如果 mbd 参数指定一个类,而不是 factoryBean,或者使用依赖注入配置的工厂对象本身的实例变量,则该方法可能是静态的。
 *
 * @param beanName the name of the bean
 * @param mbd the bean definition for the bean
 * @param explicitArgs argument values passed in programmatically via the getBean method,
 * or {@code null} if none (-> use constructor argument values from bean definition)
 * @return a BeanWrapper for the new instance
 * @see #getBean(String, Object[])
 */
	protected BeanWrapper instantiateUsingFactoryMethod(
 String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

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

首先来看一下ConstructorResolver类上的定义,翻译一下就是:用于解析构造函数和工厂方法的委托,通过参数匹配执行构造函数解析。

Delegate for resolving constructors and factory methods.Performs constructor resolution through argument matching.

这个类的作用非常强大,可以解析实例化对象的所需的构造器,如果有多个,会根据构造器的参数类型和给定的参数类型通过计算权重的方式去匹配一个最佳的构造器。

跟进方法instantiateUsingFactoryMethod()代码,这个方法整整三百行,可以说非常离谱。

这里先贴个图,看下基本的逻辑。其实逻辑也跟我们写业务差不多,先做些基础准备,这里就是初始化个BeanWrapperImpl,给工厂bean属性赋赋值等,然后就去缓存去工厂方法和参数,取不到就去解析获取方法和参数,然后利用工厂方法和参数,实例化一个对象返回,逻辑清晰。

下面分段来看一下代码吧。

基础属性赋值

这一块代码比较简单,就是初始化一个BeanWrapperImpl,然后给一些属性赋值。

		// 创建并初始化一个 BeanWrapperImpl
		BeanWrapperImpl bw = new BeanWrapperImpl();
		this.beanFactory.initBeanWrapper(bw);

		// 实例化这个Bean的工厂Bean
		Object factoryBean;
		// 工厂Bean的Class
		Class factoryClass;
		// 静态工厂方法或者是实例化工厂方法
		boolean isStatic;

		/*下面这段代码就是为上面申明的这三个属性赋值*/
		String factoryBeanName = mbd.getFactoryBeanName();
		if (factoryBeanName != null) {
			// 如果创建这个Bean的工厂就是这个Bean本身的话,那么直接抛出异常
			if (factoryBeanName.equals(beanName)) {
				throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
						"factory-bean reference points back to the same bean definition");
			}
			// 得到创建这个Bean的工厂Bean
			factoryBean = this.beanFactory.getBean(factoryBeanName);
			if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
				throw new ImplicitlyAppearedSingletonException();
			}
			factoryClass = factoryBean.getClass();
			isStatic = false;
		}
		else {
			// It's a static factory method on the bean class.
			// factoryBeanName为null,说明是通过静态工厂方法来实例化Bean的
			// 静态工厂进行实例化Bean,beanClass属性必须要是工厂的class,如果为空,直接报错
			if (!mbd.hasBeanClass()) {
				throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
						"bean definition declares neither a bean class nor a factory-bean reference");
			}
			factoryBean = null;
			factoryClass = mbd.getBeanClass();
			isStatic = true;
		}

从缓存获取参数

完成准备后,接下来是从缓存中获取工厂方法和参数,这里也比较简单,跟着注释看看。这里需要注意resolvedConstructorArguments和preparedConstructorArguments这两个参数缓存,resolvedConstructorArguments 用于缓存完全解析的构造函数参数的包可见字段,preparedConstructorArguments 用于缓存部分准备好的构造函数参数的包可见字段。其中如果是preparedConstructorArguments 中存在参数的话,需要调用resolvePreparedArguments()方法再次进行解析。

		// 到这里已经得到了一个BeanWrapper,明确了实例化当前这个Bean到底是静态工厂还是实例工厂
		// 并且已经确定了工厂Bean
		//================//
		// 最终确定的要用来创建对象的方法
		Method factoryMethodToUse = null;
		ArgumentsHolder argsHolderToUse = null;
		Object[] argsToUse = null;

		// 从缓存中解析获取参数
		// 参数分析时已经说过,explicitArgs就是null
		if (explicitArgs != null) {
			argsToUse = explicitArgs;
		}
		else {
			// 下面这段代码是什么意思呢?
			// 在原型模式下,我们会多次创建一个Bean,所以Spring对参数以及所使用的方法做了缓存
			// 在第二次创建原型对象的时候会进入这段缓存的逻辑
			// 但是这里有个问题,为什么Spring对参数有两个缓存呢?
			// 一:resolvedConstructorArguments 用于缓存完全解析的构造函数参数的包可见字段
			// 二:preparedConstructorArguments 用于缓存部分准备好的构造函数参数的包可见字段
			Object[] argsToResolve = null;
			synchronized (mbd.constructorArgumentLock) {
				factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
				// 缓存已经解析过的工厂方法或者构造方法
				if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
					// Found a cached factory method...
					// 找到一个缓存的工厂方法...resolvedConstructorArguments 跟 preparedConstructorArguments都是对参数的缓存
					argsToUse = mbd.resolvedConstructorArguments;
					if (argsToUse == null) {
						argsToResolve = mbd.preparedConstructorArguments;
					}
				}
			}
			if (argsToResolve != null) {
				// preparedConstructorArguments需要再次进行解析,其中主要完成了获取依赖以及类型转换等工作
				argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
			}
		}

跟进resolvePreparedArguments()方法,简单来说就是根据参数的类型去解析获取出需要的参数,同时这里也会完成类型转换。

	/**
 * Resolve the prepared arguments stored in the given bean definition.
 *
 * 解析存储在给定 bean 定义中的准备好的参数。
 *
 */
	private Object[] resolvePreparedArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
			Executable executable, Object[] argsToResolve, boolean fallback) {

		// 获取类型转换器
		TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
		TypeConverter converter = (customConverter != null ? customConverter : bw);
		// 获取占位符解析器
		BeanDefinitionValueResolver valueResolver =
				new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
		Class[] paramTypes = executable.getParameterTypes();

		Object[] resolvedArgs = new Object[argsToResolve.length];
		// 逐个遍历参数
		for (int argIndex = 0; argIndex < argsToResolve.length; argIndex++) {
			Object argValue = argsToResolve[argIndex];
			MethodParameter methodParam = MethodParameter.forExecutable(executable, argIndex);
			// 如果是自动装配标志,则进行依赖解析
			if (argValue == autowiredArgumentMarker) {
				argValue = resolveAutowiredArgument(methodParam, beanName, null, converter, fallback);
			}
			// 如果是 BeanMetadataElement 类型,则进行各种BeanDefinition的解析,因为 BeanMetadataElement 的实现基本上是各种BeanMetadataElement
			else if (argValue instanceof BeanMetadataElement) {
				argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue);
			}
			// String 类型
			else if (argValue instanceof String) {
				argValue = this.beanFactory.evaluateBeanDefinitionString((String) argValue, mbd);
			}
			Class paramType = paramTypes[argIndex];
			try {
				// 进行类型转换
				resolvedArgs[argIndex] = converter.convertIfNecessary(argValue, paramType, methodParam);
			}
			catch (TypeMismatchException ex) {
				throw new UnsatisfiedDependencyException(
						mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
						"Could not convert argument value of type [" + ObjectUtils.nullSafeClassName(argValue) +
						"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
			}
		}
		return resolvedArgs;
	}

解析获取工厂方法和参数

解析一下这段逻辑,这里会先去获取该工厂bean的所有方法作为候选方法,然后按照先前赋值的属性进行简单筛选。如果非常巧合,只找到了一个,同时参数又为空,这时候就可以利用这个唯一的方法去实例化对象,省略了后面参数解析的复杂逻辑。如果不巧,那就只好老老实实去解析参数匹配。

  • 首先这里会对所有方法进行排序,这里会对给定的工厂方法进行排序,优先选择公共方法和具有最多参数的“贪婪”方法。结果将首先包含公共方法,参数数量减少,然后是非公共方法,参数数量再次减少。
  • 然后会调用resolveConstructorArguments()去获取可执行方法的最少参数个数minNrOfArgs。
  • 随后遍历所有的候选方法,方法的参数个数必须满足大于或等于可执行方法的最少参数个数minNrOfArgs,尝试通过方法参数名称,方法参数类型和给定的resolvedValues属性里面去查找或者通过自动注入获取到参数值,然后封装成ArgumentsHolder对象。
  • 如果存在多个,通过权重计算获取最合适的工厂方法。如果最后没有找到工厂方法和参数,直接报错。如果最合适的有多个,那么也直接报错。
  • 最后对工厂方法和参数进行缓存,然后调用instantiate()方法,使用前面解析出来的工厂方法和参数进行对象创建。

具体实现如下,可以跟着注释查看。这里就不全部再去解析,下面就简单分析一下确定方法执行所需的最小参数和封装ArgumentsHolder对象的逻辑。

		// 缓存中找不到方法获取参数,执行到这段代码说明是第一次实例化这个对象
		if (factoryMethodToUse == null || argsToUse == null) {
			// Need to determine the factory method...
			// Try all methods with this name to see if they match the given arguments.
			// 需要确定工厂方法...尝试所有具有此名称的方法,看看它们是否与给定的参数匹配。
			// 如果被cglib代理的话,获取父类的class
			factoryClass = ClassUtils.getUserClass(factoryClass);

			// 获取到工厂类中的所有方法
			List candidateList = null;
 if (mbd.isFactoryMethodUnique) {
 if (factoryMethodToUse == null) {
 factoryMethodToUse = mbd.getResolvedFactoryMethod();
 }
 if (factoryMethodToUse != null) {
 candidateList = Collections.singletonList(factoryMethodToUse);
 }
 }
 if (candidateList == null) {
 candidateList = new ArrayList<>();
 // 获取到工厂类中的所有方法,接下来要一步步从这些方法中筛选出来符合要求的方法
 Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
 // 第一步筛选:之前 在第二段代码中已经推断了方法是静态或者非静态的
 // 所以这里第一个要求就是要满足静态/非静态这个条件
 // 第二个要求就是必须符合bd中定义的factoryMethodName的名称
 // 其中第二个要求请注意,如果bd是一个configurationClassBeanDefinition,
 // 也就是说是通过扫描@Bean注解产生的,那么在判断时还会添加是否标注了@Bean注解
 for (Method candidate : rawCandidates) {
 if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
 candidateList.add(candidate);
 }
 }
 }

 // 如果只有一个,则没有重载方法,不需要查找,这里就会省略后续复杂的推断了,可以直接确定方法
 if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
 Method uniqueCandidate = candidateList.get(0);
 // 如果没有参数
 if (uniqueCandidate.getParameterCount() == 0) {
 mbd.factoryMethodToIntrospect = uniqueCandidate;
 synchronized (mbd.constructorArgumentLock) {
 mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
 mbd.constructorArgumentsResolved = true;
 mbd.resolvedConstructorArguments = EMPTY\_ARGS;
 }
 bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY\_ARGS));
 return bw;
 }
 }

 // 将之前得到的方法集合转换成数组
 // 到这一步得到的其实就是某一个方法的所有重载方法
 // 比如 codegitz(),codegitz(String name),codegitz(String name,int age)
 Method[] candidates = candidateList.toArray(new Method[0]);
 // 排序,public跟参数多的优先级越高
 AutowireUtils.sortFactoryMethods(candidates);

 // 用来保存从配置文件中解析出来的参数
 ConstructorArgumentValues resolvedValues = null;
 // 是否使用了自动注入,本段代码中没有使用到这个属性,但是在后面用到了
 boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE\_CONSTRUCTOR);
 int minTypeDiffWeight = Integer.MAX\_VALUE;
 // 可能出现多个符合要求的方法,用这个集合保存,实际上如果这个集合有值,就会抛出异常了
 Set ambiguousFactoryMethods = null;

 int minNrOfArgs;
 // 必定为null,不考虑了
 if (explicitArgs != null) {
 minNrOfArgs = explicitArgs.length;
 }
 else {
 // We don't have arguments passed in programmatically, so we need to resolve the
 // arguments specified in the constructor arguments held in the bean definition.
 // 就是说配置文件中指定了要使用的参数,那么需要对其进行解析,解析后的值就存储在resolvedValues这个集合中
 if (mbd.hasConstructorArgumentValues()) {
 // 通过解析constructor-arg标签,将参数封装成了ConstructorArgumentValues
 // ConstructorArgumentValues这个类在下文我们专门分析
 ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
 resolvedValues = new ConstructorArgumentValues();
 // 解析标签中的属性,类似进行类型转换,后文进行详细分析
 minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
 }
 else {
 // 配置文件中没有指定要使用的参数,所以执行方法的最小参数个数就是0
 minNrOfArgs = 0;
 }
 }

 LinkedList causes = null;

 for (Method candidate : candidates) {
 Class[] paramTypes = candidate.getParameterTypes();

 if (paramTypes.length >= minNrOfArgs) {
 ArgumentsHolder argsHolder;

 if (explicitArgs != null) {
 // Explicit arguments given -> arguments length must match exactly.
 // 给定的显式参数 -> 参数长度必须完全匹配。
 if (paramTypes.length != explicitArgs.length) {
 continue;
 }
 argsHolder = new ArgumentsHolder(explicitArgs);
 }
 else {
 // Resolved constructor arguments: type conversion and/or autowiring necessary.
 // 已解决的构造函数参数:需要类型转换和自动装配。
 try {
 String[] paramNames = null;
 ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
 if (pnd != null) {
 paramNames = pnd.getParameterNames(candidate);
 }
 // 给定解析的构造函数参数值,创建一个参数数组以调用构造函数或工厂方法
 argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
 paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
 }
 catch (UnsatisfiedDependencyException ex) {
 if (logger.isTraceEnabled()) {
 logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
 }
 // Swallow and try next overloaded factory method.
 if (causes == null) {
 causes = new LinkedList<>();
 }
 causes.add(ex);
 continue;
 }
 }

 // 计算给定参数和方法定义参数的权重,选择一个最合适的方法
 int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
 argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
 // Choose this factory method if it represents the closest match.
 // 如果它代表最接近的匹配,则选择此工厂方法。
 if (typeDiffWeight < minTypeDiffWeight) {
 factoryMethodToUse = candidate;
 argsHolderToUse = argsHolder;
 argsToUse = argsHolder.arguments;
 minTypeDiffWeight = typeDiffWeight;
 ambiguousFactoryMethods = null;
 }
 // Find out about ambiguity: In case of the same type difference weight
 // for methods with the same number of parameters, collect such candidates
 // and eventually raise an ambiguity exception.
 // However, only perform that check in non-lenient constructor resolution mode,
 // and explicitly ignore overridden methods (with the same parameter signature).
 // 找出歧义:如果具有相同数量的参数的方法的类型差异权重相同,则收集此类候选并最终引发歧义异常。
 // 但是,仅在非宽松构造函数解析模式下执行该检查,并显式忽略重写的方法(具有相同的参数签名)
 // 可以理解为,这里就是收集参数类型和数量一样,方法名一样,如果存在这种情况,最终会抛出异常
 // 为啥会出现这种情况,我理解可能是同名方法参数的顺序不一样导致的,例如 sayHi(String name,String age) 和 sayHi(String age,String name)
 else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
 !mbd.isLenientConstructorResolution() &&
 paramTypes.length == factoryMethodToUse.getParameterCount() &&
 !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
 if (ambiguousFactoryMethods == null) {
 ambiguousFactoryMethods = new LinkedHashSet<>();
 ambiguousFactoryMethods.add(factoryMethodToUse);
 }
 ambiguousFactoryMethods.add(candidate);
 }
 }
 }

 // 最终没有找到可用的工厂方法或者参数,或者有多个符合要求的方法等情况,进行异常处理
 if (factoryMethodToUse == null || argsToUse == null) {
 // 省略一些异常处理...
 }

 // 缓存参数
 if (explicitArgs == null && argsHolderToUse != null) {
 mbd.factoryMethodToIntrospect = factoryMethodToUse;
 argsHolderToUse.storeCache(mbd, factoryMethodToUse);
 }
 }

简单的逻辑就不做过多解释了,这里重点来看下是怎么确定方法最小使用参数个数的。跟进代码resolveConstructorArguments(),该方法会先获取constructor-arg标签指定的参数个数,然后去获取参数的下标值,如果下标值更大,那么最小的参数个数就取下标值加一。

	/**
 * Resolve the constructor arguments for this bean into the resolvedValues object.
 * This may involve looking up other beans.
 * This method is also used for handling invocations of static factory methods.
 *
 * 将此 bean 的构造函数参数解析为 resolvedValues 对象。这可能涉及查找其他 bean。
 * 此方法也用于处理静态工厂方法的调用。
 *
 * 方法目的:解析配置文件中指定的方法参数
 * beanName:bean名称
 * mbd:beanName对应的beanDefinition
 * bw:通过它进行类型转换
 * ConstructorArgumentValues cargs:解析标签得到的属性,还没有经过解析(类型转换)
 * ConstructorArgumentValues resolvedValues:已经经过解析的参数
 * 返回值:返回方法需要的最小参数个数
 *
 */




	private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
 ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) {

		// 是否有定制的类型转换器,没有的话直接使用BeanWrapper进行类型转换
		TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
		TypeConverter converter = (customConverter != null ? customConverter : bw);
		// 构造一个BeanDefinitionValueResolver,专门用于解析constructor-arg中的value属性,实际上还包括ref属性,内嵌bean标签等等
		BeanDefinitionValueResolver valueResolver =
				new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);

		// minNrOfArgs 记录执行方法要求的最小参数个数,一般情况下就是等于constructor-arg标签指定的参数数量
		int minNrOfArgs = cargs.getArgumentCount();

		for (Map.Entry entry : cargs.getIndexedArgumentValues().entrySet()) {
 int index = entry.getKey();
 if (index < 0) {
 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 "Invalid constructor argument index: " + index);
 }
 // 这是啥意思呢?
 // 暂且你先这样理解
 // 假设A方法直接在配置文件中指定了index=3上要使用的参数,那么这个时候A方法至少需要4个参数
 // 但是其余的3个参数可能不是通过constructor-arg标签指定的,而是直接自动注入进来的,那么在配置文件中我们就只配置了index=3上的参数,也就是说 int minNrOfArgs = cargs.getArgumentCount()=1,这个时候 index=3,minNrOfArgs=1, 所以 minNrOfArgs = 3+1
 if (index > minNrOfArgs) {
 minNrOfArgs = index + 1;
 }
 ConstructorArgumentValues.ValueHolder valueHolder = entry.getValue();
 if (valueHolder.isConverted()) {
 // 如果已经转换过了,直接添加到resolvedValues集合中
 resolvedValues.addIndexedArgumentValue(index, valueHolder);
 }
 else {
 // 解析value/ref/内嵌bean标签等
 Object resolvedValue =
 valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
 // 将解析后的resolvedValue封装成一个新的ValueHolder,
 // 并将其source设置为解析constructor-arg得到的那个ValueHolder,
 // 后期会用到这个属性进行判断
 ConstructorArgumentValues.ValueHolder resolvedValueHolder =
 new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName());
 resolvedValueHolder.setSource(valueHolder);
 resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder);
 }
 }
 // 对getGenericArgumentValues进行解析,代码基本一样,不再赘述
 for (ConstructorArgumentValues.ValueHolder valueHolder : cargs.getGenericArgumentValues()) {
 if (valueHolder.isConverted()) {
 resolvedValues.addGenericArgumentValue(valueHolder);
 }
 else {
 Object resolvedValue =
 valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
 ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder(
 resolvedValue, valueHolder.getType(), valueHolder.getName());
 resolvedValueHolder.setSource(valueHolder);
 resolvedValues.addGenericArgumentValue(resolvedValueHolder);
 }
 }

 return minNrOfArgs;
 }


看完怎么确定最小方法参数个数的逻辑,接下来需要按照给定解析的构造函数参数值,创建一个参数数组以调用构造函数或工厂方法,就看一下封装ArgumentsHolder对象的过程,跟进代码createArgumentArray()方法查看。

这方法也没啥好说,就是逐个去获取,如果给定的参数没有,那就从容器中获取,这部分即为自动注入的参数。


	/**
 * Create an array of arguments to invoke a constructor or factory method,
 * given the resolved constructor argument values.
 *
 * 给定解析的构造函数参数值,创建一个参数数组以调用构造函数或工厂方法。
 */
	private ArgumentsHolder createArgumentArray(
 String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,
 BeanWrapper bw, Class[] paramTypes, @Nullable String[] paramNames, Executable executable,
 boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {

		TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
		TypeConverter converter = (customConverter != null ? customConverter : bw);

		ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
		Set usedValueHolders = new HashSet<>(paramTypes.length);
 Set autowiredBeanNames = new LinkedHashSet<>(4);

 for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
 Class paramType = paramTypes[paramIndex];
 String paramName = (paramNames != null ? paramNames[paramIndex] : "");
 // Try to find matching constructor argument value, either indexed or generic.
 // 尝试找到匹配的构造函数参数值,无论是索引的还是泛型的。
 ConstructorArgumentValues.ValueHolder valueHolder = null;
 if (resolvedValues != null) {
 valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders);
 // If we couldn't find a direct match and are not supposed to autowire,
 // let's try the next generic, untyped argument value as fallback:
 // it could match after type conversion (for example, String -> int).
 // 如果我们找不到直接匹配并且不应该自动装配,让我们尝试下一个通用的、无类型的参数值作为后备:它可以在类型转换后匹配(例如,String -> int)。
 if (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) {
 valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);
 }
 }
 if (valueHolder != null) {
 // We found a potential match - let's give it a try.
 // Do not consider the same value definition multiple times!
 // 我们找到了一个潜在的匹配 - 让我们试一试。不要多次考虑相同的值定义!
 usedValueHolders.add(valueHolder);
 Object originalValue = valueHolder.getValue();
 Object convertedValue;
 if (valueHolder.isConverted()) {
 convertedValue = valueHolder.getConvertedValue();
 args.preparedArguments[paramIndex] = convertedValue;
 }
 else {
 MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
 try {
 convertedValue = converter.convertIfNecessary(originalValue, paramType, methodParam);
 }
 catch (TypeMismatchException ex) {
 throw new UnsatisfiedDependencyException(
 mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
 "Could not convert argument value of type [" +
 ObjectUtils.nullSafeClassName(valueHolder.getValue()) +
 "] to required type [" + paramType.getName() + "]: " + ex.getMessage());
 }
 Object sourceHolder = valueHolder.getSource();
 if (sourceHolder instanceof ConstructorArgumentValues.ValueHolder) {
 Object sourceValue = ((ConstructorArgumentValues.ValueHolder) sourceHolder).getValue();
 args.resolveNecessary = true;
 args.preparedArguments[paramIndex] = sourceValue;
 }
 }
 args.arguments[paramIndex] = convertedValue;
 args.rawArguments[paramIndex] = originalValue;
 }
 else {
 // 这部分就是超出了参数定义,需要自动注入参数的处理
 MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
 // No explicit match found: we're either supposed to autowire or
 // have to fail creating an argument array for the given constructor.
 if (!autowiring) {
 throw new UnsatisfiedDependencyException(
 mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
 "Ambiguous argument values for parameter of type [" + paramType.getName() +
 "] - did you specify the correct bean references as arguments?");
 }
 try {
 Object autowiredArgument = resolveAutowiredArgument(
 methodParam, beanName, autowiredBeanNames, converter, fallback);
 args.rawArguments[paramIndex] = autowiredArgument;
 args.arguments[paramIndex] = autowiredArgument;
 args.preparedArguments[paramIndex] = autowiredArgumentMarker;
 args.resolveNecessary = true;
 }
 catch (BeansException ex) {
 throw new UnsatisfiedDependencyException(
 mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);
 }
 }
 }

 for (String autowiredBeanName : autowiredBeanNames) {
 this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
 if (logger.isDebugEnabled()) {
 logger.debug("Autowiring by type from bean name '" + beanName +
 "' via " + (executable instanceof Constructor ? "constructor" : "factory method") +
 " to bean named '" + autowiredBeanName + "'");
 }
 }

 return args;
 }


实例化bean

工厂方法和参数都已经获取完成了,到最后就是调用instantiate()方法去实例化一个bean对象,跟进instantiate()方法查看代码。可以看到这里就是确定一个构造策略,然后调用其instantiate()方法。

	private Object instantiate(String beanName, RootBeanDefinition mbd,
 @Nullable Object factoryBean, Method factoryMethod, Object[] args) {

		try {
			if (System.getSecurityManager() != null) {
				return AccessController.doPrivileged((PrivilegedAction) () ->
 this.beanFactory.getInstantiationStrategy().instantiate(
 mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args),
 this.beanFactory.getAccessControlContext());
 }
 else {
 // 确定实例化策略,调用其 instantiate() 方法,
 // 该方法有两种实现,
 // 一种是普通的实现 SimpleInstantiationStrategy,
 // 一种是需要使用到代理的 CglibSubclassingInstantiationStrategy 实现
 return this.beanFactory.getInstantiationStrategy().instantiate(
 mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args);
 }
 }
 catch (Throwable ex) {
 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 "Bean instantiation via factory method failed", ex);
 }
 }

我们看一下普通的实现SimpleInstantiationStrategy#instantiate(),跟进代码查看。可以看到逻辑还是比较简单的,就是完成一些基础设置,然后直接调用方法获取对象返回。至此,使用工厂方法实例化bean的分析已经完成了。

	@Override
	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
 @Nullable Object factoryBean, final Method factoryMethod, Object... args) {

		try {
			// 权限相关,暂时忽略...
			if (System.getSecurityManager() != null) {
				AccessController.doPrivileged((PrivilegedAction) () -> {
 ReflectionUtils.makeAccessible(factoryMethod);
 return null;
 });
 }
 else {
 // 设置访问标识
 ReflectionUtils.makeAccessible(factoryMethod);
 }

 // 记录上一个调用的工厂方法
 Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
 try {
 // 设置当前调用的工厂方法
 currentlyInvokedFactoryMethod.set(factoryMethod);
 // 直接调用工厂方法获取对象
 Object result = factoryMethod.invoke(factoryBean, args);
 if (result == null) {
 result = new NullBean();
 }
 // 返回对象
 return result;
 }
 finally {
 // 后续状态的设置
 if (priorInvokedFactoryMethod != null) {
 currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
 }
 else {
 currentlyInvokedFactoryMethod.remove();
 }
 }
 }
 catch (IllegalArgumentException ex) {
 // 省略部分异常处理...
 }
 }

使用有参构造函数实例化bean

还是回到AbstractAutowireCapableBeanFactory#createBeanInstance()方法里,如果经过了前面两种处理都没有获得一个实例化的对象的话,那么接下来就要使用构造函数去实例化对象了。

构造函数分为有参构造函数和无参构造函数。在这里会先匹配有参构造函数,然后再去使用默认的无参构造函数。

这里先讨论使用有参构造函数的情况,啥时候使用有参构造函数呢?在这里看来无非是两种:

  • 指定了一个构造函数,spring提供了一个determineConstructorsFromBeanPostProcessors()方法来提供一个扩展口返回一个构造函数。
  • 传入的参数不为空,这里会进入到autowireConstructor()方法里进行推断构造函数,这里的推断过程跟上面工厂方法推断过程非常类似,可以参考着看看。

先来看看指定一个构造函数是怎么处理,跟进determineConstructorsFromBeanPostProcessors()方法,这里可以看到就是调用了SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors()方法,没啥特别的。

	/**
 * Determine candidate constructors to use for the given bean, checking all registered
 * {@link SmartInstantiationAwareBeanPostProcessor SmartInstantiationAwareBeanPostProcessors}.
 *
 * 确定用于给定 bean 的候选构造函数,检查所有已注册的 {@link SmartInstantiationAwareBeanPostProcessor SmartInstantiationAwareBeanPostProcessors}。
 *
 * @param beanClass the raw class of the bean
 * @param beanName the name of the bean
 * @return the candidate constructors, or {@code null} if none specified
 * @throws org.springframework.beans.BeansException in case of errors
 * @see org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
 */
	@Nullable
	protected Constructor[] determineConstructorsFromBeanPostProcessors(@Nullable Class beanClass, String beanName)
			throws BeansException {

		if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					Constructor[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
					if (ctors != null) {
						return ctors;
					}
				}
			}
		}
		return null;
	}

接下来看重点autowireConstructor()方法,这里的实现逻辑也是委派给了ConstructorResolver去实现。

	/**
 * "autowire constructor" (with constructor arguments by type) behavior.
 * Also applied if explicit constructor argument values are specified,
 * matching all remaining arguments with beans from the bean factory.
 * This corresponds to constructor injection: In this mode, a Spring
 * bean factory is able to host components that expect constructor-based
 * dependency resolution.
 *
 * “自动装配构造函数”(按类型使用构造函数参数)行为。
 * 如果指定了显式构造函数参数值,也适用,将所有剩余参数与 bean 工厂中的 bean 匹配。
 * 这对应于构造函数注入:在这种模式下,Spring bean 工厂能够托管期望基于构造函数的依赖解析的组件。
 *
 * @param beanName the name of the bean
 * @param mbd the bean definition for the bean
 * @param ctors the chosen candidate constructors
 * @param explicitArgs argument values passed in programmatically via the getBean method,
 * or {@code null} if none (-> use constructor argument values from bean definition)
 * @return a BeanWrapper for the new instance
 */




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

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

跟进autowireConstructor()方法,可以看到这里的逻辑跟工厂方法的解析是非常类似的,根据参数去推断合适的方法,然后获取参数的依赖,最后利用获取到的构造方法和参数实例化对象,详细可见上一节,这里不再赘述。

	/**
 * "autowire constructor" (with constructor arguments by type) behavior.
 * Also applied if explicit constructor argument values are specified,
 * matching all remaining arguments with beans from the bean factory.
 * This corresponds to constructor injection: In this mode, a Spring
 * bean factory is able to host components that expect constructor-based
 * dependency resolution.
 *
 * “自动装配构造函数”(按类型使用构造函数参数)行为。
 * 如果指定了显式构造函数参数值,也适用,将所有剩余参数与 bean 工厂中的 bean 匹配。
 * 这对应于构造函数注入:在这种模式下,Spring bean 工厂能够托管期望基于构造函数的依赖解析的组件。
 *
 * @param beanName the name of the bean
 * @param mbd the merged bean definition for the bean
 * @param chosenCtors chosen candidate constructors (or {@code null} if none)
 * @param explicitArgs argument values passed in programmatically via the getBean method,
 * or {@code null} if none (-> use constructor argument values from bean definition)
 * 通过 getBean 方法以编程方式传入的参数值,如果没有则 {@code null}(-> 使用 bean 定义中的构造函数参数值)
 * @return a BeanWrapper for the new instance
 */




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

		BeanWrapperImpl bw = new BeanWrapperImpl();
		this.beanFactory.initBeanWrapper(bw);

		Constructor constructorToUse = null;
		ArgumentsHolder argsHolderToUse = null;
		Object[] argsToUse = null;

		if (explicitArgs != null) {
			argsToUse = explicitArgs;
		}
		else {
			Object[] argsToResolve = null;
			// 先到缓存中尝试获取构造器和参数
			synchronized (mbd.constructorArgumentLock) {
				constructorToUse = (Constructor) mbd.resolvedConstructorOrFactoryMethod;
				if (constructorToUse != null && mbd.constructorArgumentsResolved) {
					// Found a cached constructor...
					// 如果已经解析过了构造器,则直接使用缓存的构造器
					argsToUse = mbd.resolvedConstructorArguments;
					if (argsToUse == null) {
						argsToResolve = mbd.preparedConstructorArguments;
					}
				}
			}
			// 如果 mbd 存在待解析的参数,直接进行解析
			if (argsToResolve != null) {
				argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
			}
		}

		// 缓存中没有同时存在构造器和参数,老老实实去创建获取
		if (constructorToUse == null || argsToUse == null) {
			// Take specified constructors, if any.
			// 采用指定的构造函数,如果有的话。
			Constructor[] candidates = chosenCtors;
			if (candidates == null) {
				Class beanClass = mbd.getBeanClass();
				try {
					// 获取所有的构造器
					candidates = (mbd.isNonPublicAccessAllowed() ?
							beanClass.getDeclaredConstructors() : beanClass.getConstructors());
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Resolution of declared constructors on bean Class [" + beanClass.getName() +
							"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
				}
			}

			// 如果只有一个构造器,且无指定的参数并且没有已解析的参数,直接使用该构造函数实例化对象返回
			if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
				Constructor uniqueCandidate = candidates[0];
				// 如果这个唯一的构造函数是无参构造函数,设置 mbd 属性,实例化后返回
				if (uniqueCandidate.getParameterCount() == 0) {
					synchronized (mbd.constructorArgumentLock) {
						mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
						mbd.constructorArgumentsResolved = true;
						mbd.resolvedConstructorArguments = EMPTY_ARGS;
					}
					// 实例化返回
					bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
					return bw;
				}
			}

			// Need to resolve the constructor.
			// 不是无参构造函数,需要解析构造函数。
			boolean autowiring = (chosenCtors != null ||
					mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
			ConstructorArgumentValues resolvedValues = null;

			int minNrOfArgs;
			// 确定最少参数的个数
			if (explicitArgs != null) {
				minNrOfArgs = explicitArgs.length;
			}
			else {
				ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
				resolvedValues = new ConstructorArgumentValues();
				minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
			}

			AutowireUtils.sortConstructors(candidates);
			int minTypeDiffWeight = Integer.MAX_VALUE;
			Set> ambiguousConstructors = null;
 LinkedList causes = null;

 for (Constructor candidate : candidates) {
 Class[] paramTypes = candidate.getParameterTypes();

 if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) {
 // Already found greedy constructor that can be satisfied ->
 // do not look any further, there are only less greedy constructors left.
 // 已经找到可以满足的贪心构造器了——>别再看了,贪心构造器就少了。
 break;
 }
 if (paramTypes.length < minNrOfArgs) {
 continue;
 }

 ArgumentsHolder argsHolder;
 if (resolvedValues != null) {
 try {
 String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
 if (paramNames == null) {
 ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
 if (pnd != null) {
 paramNames = pnd.getParameterNames(candidate);
 }
 }
 argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
 getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
 }
 catch (UnsatisfiedDependencyException ex) {
 if (logger.isTraceEnabled()) {
 logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + 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 (paramTypes.length != explicitArgs.length) {
 continue;
 }
 argsHolder = new ArgumentsHolder(explicitArgs);
 }

 // 获取构造函数和给定参数间的类型权重
 int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
 argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
 // Choose this constructor if it represents the closest match.
 // 如果它代表最接近的匹配,则选择此构造函数。
 if (typeDiffWeight < minTypeDiffWeight) {
 constructorToUse = candidate;
 argsHolderToUse = argsHolder;
 argsToUse = argsHolder.arguments;
 minTypeDiffWeight = typeDiffWeight;
 ambiguousConstructors = null;
 }
 else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
 if (ambiguousConstructors == null) {
 ambiguousConstructors = new LinkedHashSet<>();
 ambiguousConstructors.add(constructorToUse);
 }
 ambiguousConstructors.add(candidate);
 }
 }

 if (constructorToUse == null) {
 if (causes != null) {
 UnsatisfiedDependencyException ex = causes.removeLast();
 for (Exception cause : causes) {
 this.beanFactory.onSuppressedException(cause);
 }
 throw ex;
 }
 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 "Could not resolve matching constructor " +
 "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
 }
 else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 "Ambiguous constructor matches found in bean '" + beanName + "' " +
 "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
 ambiguousConstructors);
 }

 if (explicitArgs == null && argsHolderToUse != null) {
 argsHolderToUse.storeCache(mbd, constructorToUse);
 }
 }

 Assert.state(argsToUse != null, "Unresolved constructor arguments");
 bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
 return bw;
 }


使用默认构造函数实例化bean

如果前面的逻辑都没有获取到一个实例化bean,那么就会走到最后的默认逻辑instantiateBean()里,这里会使用默认的构造函数去实例化一个bean返回。

跟进instantiateBean()方法代码查看。

	/**
 * Instantiate the given bean using its default constructor.
 *
 * 使用其默认构造函数实例化给定的 bean。
 *
 * @param beanName the name of the bean
 * @param mbd the bean definition for the bean
 * @return a BeanWrapper for the new instance
 */
	protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
		try {
			Object beanInstance;
			final BeanFactory parent = this;
			if (System.getSecurityManager() != null) {
				beanInstance = AccessController.doPrivileged((PrivilegedAction) () ->
 getInstantiationStrategy().instantiate(mbd, beanName, parent),
 getAccessControlContext());
 }
 else {
 // 使用默认的实例化策略来实例化对象,默认为 CglibSubclassingInstantiationStrategy 实现,但是instantiate()方法只在SimpleInstantiationStrategy里有实现逻辑
 beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
 }
 BeanWrapper bw = new BeanWrapperImpl(beanInstance);
 initBeanWrapper(bw);
 return bw;
 }
 catch (Throwable ex) {
 throw new BeanCreationException(
 mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
 }
 }

进入SimpleInstantiationStrategy#instantiate()方法,这里获取了默认的构造函数,然后调用BeanUtils.instantiateClass(constructorToUse)实例化对象,注意这里没有传入构造参数。

	@Override
	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// Don't override the class with CGLIB if no overrides.
		/**
 * 如果需要覆盖或者动态替换方法,则使用cglib进行动态代理
 * 因为可以在创建动态代理的同时将动态方法织入类中
 * 如果没有需要改变的方法,为了方便直接反射即可
 */
		if (!bd.hasMethodOverrides()) {
			Constructor constructorToUse;
			synchronized (bd.constructorArgumentLock) {
				constructorToUse = (Constructor) bd.resolvedConstructorOrFactoryMethod;
				if (constructorToUse == null) {
					final Class clazz = bd.getBeanClass();
					if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						if (System.getSecurityManager() != null) {
							constructorToUse = AccessController.doPrivileged(
									(PrivilegedExceptionAction>) clazz::getDeclaredConstructor);
 }
 else {
 constructorToUse = clazz.getDeclaredConstructor();
 }
 bd.resolvedConstructorOrFactoryMethod = constructorToUse;
 }
 catch (Throwable ex) {
 throw new BeanInstantiationException(clazz, "No default constructor found", ex);
 }
 }
 }
 return BeanUtils.instantiateClass(constructorToUse);
 }
 else {
 // Must generate CGLIB subclass.
 return instantiateWithMethodInjection(bd, beanName, owner);
 }
 }

跟进BeanUtils.instantiateClass(constructorToUse)的实现,**这里注意,我们上一步并没有传入参数,这里使用的是无参构造函数。**最后是调用了 ctor.newInstance(argsWithDefaultValues)实例化一个对象返回。至此,所有实例化对象的方法都已经分析完成。

	/**
 * Convenience method to instantiate a class using the given constructor.
 * Note that this method tries to set the constructor accessible if given a
 * non-accessible (that is, non-public) constructor, and supports Kotlin classes
 * with optional parameters and default values.
 *
 * 使用给定构造函数实例化类的便捷方法。
 * 请注意,如果给定一个不可访问(即非公共)构造函数,
 * 此方法会尝试将构造函数设置为可访问,并且支持带有可选参数和默认值的 Kotlin 类。
 *
 * @param ctor the constructor to instantiate
 * @param args the constructor arguments to apply (use {@code null} for an unspecified
 * parameter, Kotlin optional parameters and Java primitive types are supported)
 * @return the new instance
 * @throws BeanInstantiationException if the bean cannot be instantiated
 * @see Constructor#newInstance
 */




	public static  T instantiateClass(Constructor ctor, Object... args) throws BeanInstantiationException {
 Assert.notNull(ctor, "Constructor must not be null");
 try {
 ReflectionUtils.makeAccessible(ctor);
 if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
 return KotlinDelegate.instantiateClass(ctor, args);
 }
 else {
 // 获取构造器的参数
 Class[] parameterTypes = ctor.getParameterTypes();
 Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
 Object[] argsWithDefaultValues = new Object[args.length];
 // 遍历获取传入的 args 参数
 for (int i = 0 ; i < args.length; i++) {
 if (args[i] == null) {
 Class parameterType = parameterTypes[i];
 argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT\_TYPE\_VALUES.get(parameterType) : null);
 }
 else {
 argsWithDefaultValues[i] = args[i];
 }
 }
 return ctor.newInstance(argsWithDefaultValues);
 }
 }
 catch (InstantiationException ex) {
 // 省略部分异常处理...
 }
 }

总结

这篇文章主要是分析了实例化bean的几种方法,有哪几种?纸面上来看是四种,但是从实际来看,后面的三种都是确定一个函数以及函数的参数来实例化一个对象,有异曲同工之妙,可以细细品味。我们实例化对象如果不指定的话,默认用的都是无参构造函数。

总的来说这篇文章比较简单,就讲了实例化对象这一件事情,相比较之前兜兜转转的逻辑来说可能相对层次浅一点。这篇文章的难点在于理解方法和函数之间的匹配,怎么通过类型权重去确定一个最佳方法,这里需要花点时间琢磨一下。

个人水平有限,如有错误,还请指出。

如果有人看到这里,那在这里老话重提。与君共勉,路漫漫其修远兮,吾将上下而求索。

  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角**【[推荐](javascript:void(0)😉】**一下。
CentOS7.9 安装 ImageMagick,图片转换为HEIC图像格式 由于ImageMagick7以下不支持heic等图片格式,所以重新安装了ImageMagick7.1版本支持heic格式,在网上找了很多资料,归纳总结并写此文章记录一下。在Linux(CentOS7.9)上安装ImageMagick7.1.1-38。 阅读详情

相关推荐

保姆级教程:用PROGRAM_FTDI搞定Xilinx FPGA的JTAG调试器(基于FT232/FT2232/FT4232)

本文详细介绍了如何使用FT232/FT2232/FT4232系列芯片通过PROGRAM_FTDI工具配置Xilinx FPGA的JTAG调试器。从芯片选型、驱动安装到固件烧写和Vivado验证,提供了完整的实操指南和避坑要点,帮助开发者低成本实现高效调试。

weixin_29271053的博客 2165

Spring源码系列:依赖注入(三)-属性注入

前面文章中对依赖注入的触发和bean的创建做了学习记录,本文将来记录一下bean的属性注入过程。Bean的属性注入发生在BeanDefinitionValueResolver这个类中,BeanDefinitionValueResolver这类是用于bean工厂实现的Helper类,职责就是将bean定义对象中包含的值解析为应用于目标bean实例的实际值。 BeanDefinitionValueRe...

weixin_34203832的博客 780

MCGS触摸屏数据记录与U盘导出配置全解析

在工业自动化现场,数据记录是设备运行状态分析与故障追溯的基础。HMI触摸屏作为人机交互核心,不仅承担实时监控任务,还负责过程数据的存储与导出。理解数据采集周期、存盘机制与存储介质的匹配原理,能帮助工程师高效配置数据记录功能。合理运用定时存盘、存盘组与U盘导出,可支撑设备趋势分析、报表生成及事故排查。本文以MCGS触摸屏为例,详解数据记录的完整组态流程,并汇总常见配置陷阱与排查思路,为现场调试与长期运维提供可落地的技术参考。

weixin_34253126的博客 462

Spring依赖注入详解

启动容器后看看到底能不能拿到teacherService的值。我们具体来分析怎么注入的。会将set后面的方法去掉set,然后首字母小写放入缓存中,来获取对应的注入值,如果找不到直接报错。如果是这样会报错吗?不会,底层拿到set方法然后进行反射,故set方法和注入的属性一直就不会报错。发现pvs里面有一个我们自己set的值。问题1:如果set方法乱写可以注入吗?不行,会报错,我们看看具体在哪里报错。直接从容器中获取,然后进行属性赋值。

u012222011的博客 852

解决eNSP安装WinPcap版本冲突的完整指南

网络数据包捕获工具WinPcap是网络仿真环境的基础组件,其版本兼容性直接影响eNSP等网络模拟器的正常运行。当系统已安装新版WinPcap时,eNSP内置的旧版安装程序会因版本校验机制触发报错。通过彻底卸载现有驱动、安装特定版本WinPcap 4.1.2,并验证注册表和服务状态,可解决版本冲突问题。对于需要同时使用新版驱动的场景,可采用虚拟机隔离或Npcap兼容模式。该方案适用于Windows 10/11系统环境,涉及驱动签名、虚拟网卡等典型网络工程问题。

weixin_32612263的博客 339

matlab 点云可视化(1)——pcshow()函数可视化单个点云

matlab可视化单个点云常用方法汇总。

点云侠的博客 5359

Spring 5 BeanDefinitionValueResolver 源码注释

/** * Helper class for use in bean factory implementations, * resolving values contained in bean definition objects * into the actual values applied to the target bean instance. * <p>在bean工厂实现中使用Helper类,它将beanDefinition对象中包含的值解析为应用于 * 目标bean实例的实

qq_30321211的博客 687

探索如何利用CST和ADS进行DDR的SIPI联合仿真

本文系统介绍了CST和ADS两款工具进行DDR信号完整性/电源完整性(SI/PI)联合仿真的方法。CST采用工作室协同方式,通过PCB布局导入、材料设置、模型分配等步骤,重点分析了电源阻抗优化和信号波形质量。ADS则利用SIPro、PIPro等专用工具,突出系统级验证和自动化优化功能。两者各有优势:CST擅长3D结构精确建模,ADS更适于快速系统验证。文章建议可根据项目需求混合使用两种工具,并提供了模型简化、频带选择等实用技巧。通过对比分析,为工程师选择仿真工具提供了决策参考。

一只豌豆象的博客 1150

Spring源码剖析-Bean的实例化-属性注入,幸亏有这本623页的微服务框架实战笔记

/存放类型转换过的属性,把Bean的属性解析值新建拷贝,把拷贝的数据注入到对象//类型转换,把属性转换为对应的类型//属性值不需要转else {//属性名//原始属性值,它的类型是一个 如: RuntimeBeanReference 引用类型//转换属性值,将引用转换为 IOC 容器中实例化对象引用 OtherBean!//使用用户自定义的转换器转换//设置转换之后的值到PV ,把依赖的Bean设置给PropertyValue!!else {

2301_76348206的博客 1007

OceanBase数据库:与MySQL和Oracle的函数差异分析

OceanBase数据库兼容性解析:MySQL与Oracle模式深度比较 摘要:OceanBase通过独特的双模式架构,实现了对MySQL和Oracle的高度兼容。文章首先分析了OceanBase的兼容性架构,包括SQL解析层、优化器层和执行引擎层的差异化设计。随后对比了两种模式在数据类型、SQL语法、函数支持等方面的兼容性差异,其中MySQL模式兼容5.7版本大部分功能,Oracle模式则支持155个内置函数和PL/SQL特性。最后提出了模式选择的六大考量因素,包括现有系统基础、功能需求和迁移成本等,为数

本博客聚焦 YOLOv11 全流程落地,涵盖架构优化、数据集处理、训练技巧与多场景部署,兼及国产数据库、Java 开发与 AI 模型应用,内容兼顾理论与工程实践,为开发者提供系统干货,助力高效提升技术能力。 1228

ximalaya 新xm-sign逆向思路

本文主要介绍目标网站新xm-sign值的逆向思路。仅代表个人理解,如有其他建议可在评论区沟通。声明仅仅记录一下自己的学习方法,不作为其他参考、更不作为商业用途。如有侵犯请联系本人删除。

weixin_66580433的博客 2017

深入了解 Spring 篇之 BeanDefinition 结构

BeanDefinition 是定义对 Bean 的接口是 spring 容器中最重要的一个接口,spring 围绕这个接口进行对象的创建以及对象中的属性注入。AbstractBeanDefinition 是整个 BeanDefinition 接口的抽象类,也是具体实现类的基础类,里面的属性内容基本含盖了 spring 的 IOC 的功能特点;RootBeanDefinition 在 spring 初始化 bean 实例过程所使用的复合对象;...

Q54665642ljf的博客 351

第3课:大模型集成与API设计

OpenAIAnthropicGoogle国内厂商:文心一言、通义千问、讯飞星火。

lpfasd123的博客 111

Spring的IoC容器Bean创建过程从理论到源码分析

文章目录 系列文章目录 前言 一、pandas是什么? 二、使用步骤 1.引入库 2.读入数据 总结 前言 我们都知道Spring有以下很多优点: 方便解耦,简化开发。降低了业务对象替换的复杂性,可以让开发人员更关注业务逻辑 方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付 数据库事务问题 ...... 1.那IOC起到了什么作用? IOC容器的主要作用其实就是第一点说的,方便解耦,简化开发。 (1).那它是如何解耦的? 这就.

持续学习,共同进步 1万+

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Spring官网学习(二)IOC和Bean的实例化

本章节主要是学习Spring官网的1.1、1.2和1.3节内容,有兴趣的同学可以跟着官网一起学习。 文章目录1、Spring容器和IOC1.1、Spring容器是什么?1.2、Spring Bean是什么?1.3、IOC是什么?2、Spring容器如何实例化一个Bean2.1、Bean的实例化2.2、构造方法实例化Bean2.2.1、Demo搭建 1、Spring容器和IOC 1.1、Spri...

qq_36526036的博客 1207

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

【Spring源码系列-IOC容器二】

spring获取bean的流程

qq_45592483的博客 1473

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Spring IoC容器初始化源码(7)—createBean实例化Bean的整体流程以及createBeanInstance创建实例并进行构造器自动注入【四万字】

基于最新Spring 5.x,详细介绍了getSingleton方法中的核心createBean方法的全部流程以及该方法内部的createBeanInstance方法的源码——bean的创建以及构造器的自动注入的过程,即bean的“实例化”。

终生学习践行者 5188

Spring IOC容器启动流程与Bean生命周期源码分析

文章目录1、IOC容器启动与Bean生命周期源码分析1、new ClassPathXmlApplicationContext初始化过程1、Super(parent)2、setConfigLocations(configLocations)3、refresh()1、prepareRefresh2、obtainFreshBeanFactory1、加载bean声明的一系列过程2、注册bean声明3、prepareBeanFactory4、postProcessBeanFactory2、 ApplicationCo

学无止境! 2344

Spring-IoC源码分析

IoC源码分析 1、IoC定义 将原本在程序中⼿动创建对象的控制权,交由Spring框架来管理。 IoC 容器是 Spring⽤来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象 将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注⼊。 IoC 容器就像是⼀个⼯⼚⼀样,当我们需要创建⼀个对象的时候,只需要配置好配置⽂件/注解即 可,完全不⽤考虑对象是如何被创建出来的。 IoC 的实现原理就是工厂模式加反射机制 优点: 代

一名蒟蒻的博客 2559

Spring原理与源码分析系列(三)- Spring IoC容器启动过程分析(下)

0 前言 关于Spring容器启动过程的分析,本章节文章分为两篇文章进行叙述,第一篇主要介绍Spring中Bean的相关概念以及IoC容器类型;第二篇开始详细介绍IoC容器的启动过程。 上篇Spring原理与源码分析系列(二)- Spring IoC容器启动过程分析(上)已经介绍了介绍Spring中Bean的相关概念以及IoC容器类型。本篇主要详述IoC容器的启动过程。 四、Spring

noaman_wgs的博客 1914

Spring Ioc源码分析系列--Bean实例化过程(一)

上一篇文章Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理已经完成了对IoC容器启动方法也就是refresh()方法的简单分析。但是之前的分析在对容器实例化Bean的过程的略过了,留到了这后续的文章分析,所以这篇文章会对Bean的实例化过程做一个介绍。关键词是实例化。由于Spring是利用反射实现的实例化,脑子里先简单想一下Java里利用发射实例化一个对象需要哪些步骤和操作。毫无疑问,我们首先要知道对象的class。

qq_32445015的博客 170

Spring IOC 容器源码分析

原文地址:https://javadoop.com/post/spring-ioc 本文干货很多,建议静心阅读 文章目录Spring IOC 容器源码分析引言BeanFactory 简介启动过程分析创建 Bean 容器前的准备工作创建 Bean 容器,加载并注册 BeanBeanDefinition 接口定义customizeBeanFactory加载 Bean: loadBeanDefini...

VicterTian的博客 1573

Spring源码分析(二)-Spring IoC容器的初始化No.2

Spring源码分析(二)-Spring IoC容器的初始化No.2

qq418517226的专栏 2946

Spring原理与源码分析系列(五)- Spring IoC源码分析(下)

0 前言 IoC容器主要分为两个阶段:IoC容器启动和依赖注入。 在上节 Spring原理与源码分析系列(四)- Spring IoC源码分析(上) 我们已经从源码的角度分析了IoC容器的启动过程,本篇将要讲述依赖注入过程的源码分析。 二、IoC容器的依赖注入 在IoC容器的初始化完成后,就已经在容器内建立了BeanDefinition数据映射。 接下来就需要开始依赖注入了

noaman_wgs的博客 1495

头条一面:Spring IOC容器中只存放单例Bean吗?

最近,很多小伙伴出去面试,感觉自己面的不是很理想,回来后,不少小伙伴把面试题做了记录发给我,让我给大家解析下,然后发出来。当我看到这些面试题时,快速在脑海中构建起了整个知识体系,从基础到框...

架构师小秘圈 424
上一篇: 【ASP.NET Core】配置应用程序地址的N多种方法
下一篇: 深度学习与CV教程(12) | 目标检测 (两阶段,R-CNN系列)
pythonxxoo
博客等级 码龄5年 337粉丝 670原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值