Spring - 推断构造方法【1】

287 阅读2分钟

这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战

前言

推断构造方法,其实之前我们也经过了:

  • 在创建bean的时候,我们不可避免地需要通过构造方法来创建bean实例。

    • 在循环依赖、依赖注入中,针对构造方法,我们也有说到对应的相关处理。

    这里有一些工作中的小tips:

    • 如果在类中声明了多个构造方法并且没有无参的,并且没有用@Autowired标注的构造方法,那么就会报错。
    • 如果通过getBean以及@Lazy的方式,或者自己写入BD且指定了构造方法,或者指定AutowireMode=CONSTRUCTOR,也可以绕过这一校验。

这里就看看这里是如何进行推断的,以及具体是如何工作的。

根据Bean的生命周期,我们也容易得知:代码入口在:

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

   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;
   if (mbd.isSingleton()) {
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }
   if (instanceWrapper == null) {
       //就是这里
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
//...
}

方法代码在下面:

	protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
        //args:getBean时使用的参数
		// 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);
		}

        //与@Bean有关
		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) {
                //在这里会用缓存来生成【1】
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				return instantiateBean(beanName, mbd);
			}
		}

		// Candidate constructors for autowiring?
        //根据上面的逻辑:这里就是来查找构造方法了【3】
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
            //看这里的方法和【1】是相同的,就代表后面两个参数缺省时会去查找缓存
			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);
	}