spring选择bean初始化构造器的简单分析(源码层面)——存在问题

因为要通过源码分析,这里就要追踪到createBeanInstance方法

带注释的源码如下,如果想要了解如何执行到这里的,请看下面的流程解析

bean初始化(实例化)详解

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
	// Make sure bean class is actually resolved at this point.
	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());
	}

	Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
	if (instanceSupplier != null) {
		return obtainFromSupplier(instanceSupplier, beanName);
	}

	// 如果有FactoryMethod就会用FactoryMethod来创建bean对象
	// 可以在xml中配置factory-method属性
	if (mbd.getFactoryMethodName() != null) {
		return instantiateUsingFactoryMethod(beanName, mbd, args);
	}


	// Shortcut when re-creating the same bean...
	boolean resolved = false;
	boolean autowireNecessary = false;
	if (args == null) {
		synchronized (mbd.constructorArgumentLock) {
			// 判断是不是存在FactoryMethod,存在就进入if
			if (mbd.resolvedConstructorOrFactoryMethod != null) {
				resolved = true;
				autowireNecessary = mbd.constructorArgumentsResolved;
			}
		}
	}
	// 只有存在FactoryMethod才会进入
	if (resolved) {
		if (autowireNecessary) {
			return autowireConstructor(beanName, mbd, null, null);
		}
		else {
			return instantiateBean(beanName, mbd);
		}
	}

	//这里通过后置处理器得到bean的构造方法
	// 总的来说除非只有一个构造器(非默认构造器)的情况下,都会返回null
	// 如果存在一个非默认构造器,而且默认构造器是非显示的,那么非返回这个构造器
	// Candidate constructors for autowiring?
	Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
	if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
			mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {

		//使用有参的构造方法来初始化bean
	return autowireConstructor(beanName, mbd, ctors, args);

	}

	// No special handling: simply use no-arg constructor.
	//执行默认构造方法创建bean
	return instantiateBean(beanName, mbd);
}

构造器的选择是通过determineConstructorsFromBeanPostProcessorsfang方法是实现的。

走进这个方法,方法里面又是通过determineCandidateConstructors方法得到的构造器,这是一个接口方法,真正调用的是AutowiredAnnotationBeanPostProcessor中的determineCandidateConstructors方法,这个方法中代码很多但是我们可以只关心最后几行代码,对于spring是怎么拿到构造器的我们不关心,主要是spring是如何选择使用哪一个构造器的。
在这里插入图片描述
rawCandidates里存储的构造器会有几种情况,这个数组中存储着对象的所有构造器,但是对于默认构造器是否存储在这个数组中会有几种不同情况:

  1. 只有默认构造器,这种情况下不论显不显示地写出默认构造器rawCandidates中都会有默认构造器
  2. 存在非默认构造器
    a.显示地写出默认构造器,那么rawCandidates就会有默认构造器
    b.不显示地写出默认构造器,那么rawCandidates就不会有默认构造器
			/**
			 * 上面关于构造器如何得到和一些处理不做分析
			 * 这里得到rawCandidates和nonSyntheticConstructors
			 * rawCandidates里面装着所有的构造器(一般情况下)
			 * 至于rawCandidates都有哪些构造器这里会有几种情况
			 *
			 * 1.只有默认构造器,这种情况下不论显不显示地写出默认构造器rawCandidates中都会有默认构造器
			 *
			 * 2.存在非默认构造器
			 * 	a.显示地写出默认构造器,那么rawCandidates就会有默认构造器
			 * 	b.不显示地写出默认构造器,那么rawCandidates就不会有默认构造器
			 *
			 * 这里的primaryConstructor目前并不清楚如何设置
			 * 默认是没有设置的,就是null
			 *
			 * 排除这个primaryConstructor
			 * 总的来说除非只有一个构造器(非默认构造器)的情况下,都会使用默认构造器
			 * 而且这个默认构造器是非显示的
			 */
			// 如果只有一个构造器就会返回这个构造器(非默认构造器)
			else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
				candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
			}
			// 如果有两个构造器(含默认构造器)且存在primary设置的构造器就返回此构造器
			else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
					defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
				candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
			}
			// 如果有一个构造器且存在primary设置的构造器就返回此构造器
			else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
				candidateConstructors = new Constructor<?>[] {primaryConstructor};
			}
			else {
				// 如果进入此语句代表最终将返回null
				// 也就是使用默认构造器初始化bean
				candidateConstructors = new Constructor<?>[0];
			}
			this.candidateConstructorsCache.put(beanClass, candidateConstructors);
		}
	}
}
return (candidateConstructors.length > 0 ? candidateConstructors : null);

因为还不知道primaryConstructor是如何设置的,而且默认是null。

总的来说排除这个primaryConstructor,除非只有一个构造器(非默认构造器)的情况下,都会使用默认构造器,而且这个默认构造器是非显示的。

如果在上面选择构造器的时候真的找到了初始化时使用的会默认构造方法的话会执行下面的方法初始化bean
在这里插入图片描述
在上面就分析过了,如果无法设置主要构造器的话,除了返回null之外只会返回一个构造器,自然就是通过这个构造器实例化的bean,当然如果返回了多个构造器spring也会在这个方法中进行选择一个匹配度最高的构造器来初始化bean。

我们可以通过spring的扩展点设置需要注入的属性的类型,如下所示,mybatis也正是通过这种方法是实现实例化mapper接口。
在这里插入图片描述
下面是spring内部拿到我们注入的属性
在这里插入图片描述
然后spring会通过这些需要注入的属性来选择构造器,这个是属于spring内部的算法选择,具体是如何选择的就不具体分析了,类似于编辑距离算法。

下面是通过选择的构造方法初始化bean的方法
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值