spring-推断构造方法

问题

当我在创建一个Bean的时候,肯定是需要调用构造方法,如果有默认的就直接默认的,如果没有默认的,而且只有一个,就会调用这个构造方法,如果有两个,但是都不是默认的,自己也没有指定,就会抛异常,如果指定了,就用指定的

如果自己指定了,那个优先级就是最高的

源码解析

主要就是bean的实例化

spring-推断构造方法_第1张图片

  • 这个方法比较长,分段分析
    • 缓存(主要是 为了 原型bean 多次创建时,更快)
    • 		// 一个原型BeanDefinition,会多次来创建Bean,那么就可以把该BeanDefinition所要使用的构造方法缓存起来,避免每次都进行构造方法推断
      		boolean resolved = false;
      		boolean autowireNecessary = false;
      		if (args == null) {
      			synchronized (mbd.constructorArgumentLock) {
      				if (mbd.resolvedConstructorOrFactoryMethod != null) {
      					resolved = true;
      					// autowireNecessary表示有没有必要要进行注入,比如当前BeanDefinition用的是无参构造方法,那么autowireNecessary为false,否则为true,表示需要给构造方法参数注入值
      					autowireNecessary = mbd.constructorArgumentsResolved;
      				}
      			}
      		}
      • 这个 args 是==》 getBean中传的args,这个其实是指定构造方法的参数中,如果自己指定了,那就没必要再去管缓存了,直接根据参数,找到那个构造方法,直接调用即可
      • BD的resolvedConstructorOrFactoryMethod(类型是Executable 是 Method的父类),其实就是缓存的构造方法
      • 如果有缓存的构造方法,就将有缓存的打开(resolved = true;)
      • autowireNecessary = mbd.constructorArgumentsResolved;

      • 这行代码是为了确定这个缓存的构造方法的参数情况,如果是无参的,就直接false,不需要注入,如果是有参数,那就需要去找到参数并且注入,这个就为true

      • 	if (resolved) {
        			// 如果确定了当前BeanDefinition的构造方法,那么看是否需要进行对构造方法进行参数的依赖注入(构造方法注入)
        			if (autowireNecessary) {
        				// 方法内会拿到缓存好的构造方法的入参
        				return autowireConstructor(beanName, mbd, null, null);
        			}
        			else {
        				// 构造方法已经找到了,但是没有参数,那就表示是无参,直接进行实例化
        				return instantiateBean(beanName, mbd);
        			}
        		}
        • 如果有缓存,就判断是不是需要参数,不需要就直接实例化,需要再去找

    • 如果没有缓存,就开始了推断构造方法(找构造方法)

      • 		// 提供一个扩展点,可以利用SmartInstantiationAwareBeanPostProcessor来控制用beanClass中的哪些构造方法
        		// 比如AutowiredAnnotationBeanPostProcessor会把加了@Autowired注解的构造方法找出来,具体看代码实现会更复杂一点
        		Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        
        		// 如果推断出来了构造方法,则需要给构造方法赋值,也就是给构造方法参数赋值,也就是构造方法注入
        		// 如果没有推断出来构造方法,但是autowiremode为AUTOWIRE_CONSTRUCTOR,则也可能需要给构造方法赋值,因为不确定是用无参的还是有参的构造方法
        		// 如果通过BeanDefinition指定了构造方法参数值,那肯定就是要进行构造方法注入了
        		// 如果调用getBean的时候传入了构造方法参数值,那肯定就是要进行构造方法注入了
        		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);
        •  determineConstructorsFromBeanPostProcessors(beanClass, beanName);

        • 这个就是最后调的AutowiredAnnotationBeanPostProcessor类(非常熟悉)的determineCandidateConstructors方法

          • 这个方法的逻辑有一点点绕(但是慢慢看,是可以看懂的)

          • 大概就是

          • 获取到所有的构造方法,并遍历

          • 判断这个构造方法是否加了@Autowired的注解

            • 加了

            • 会获得这个注解的required的值

            • 就是 所有加了这个注解的构造方法,如果其中出现一个为true,就会报错

            • 但是只有一个构造方法加了这个注解,true不会报错

            • 多个,要么都是false,出现true就会报错

            • 一个 ,无论true或者false都不会报错

          • 会将这些加了注解的构造方法放到candidates这个集合

          • 如果有无参的构造方法(并且没有加注解),就会将这个方法打个标记

          • 遍历就结束了

          • 开始筛选

          • 如果candidates这个集合不为空,

            • 还没找到一个required为true的,但是找到了一个,无参的构造方法,就会将无参的加到这个集合中

            • 如果找到了一个required为true的,那就只有这一个是有效的,candidates转为数组(就和默认的构造方法没有关系了)

          • 如果candidates为空(就是没有一个构造方法加注解)

            • 但是这个类的所有构造方法只有一个,还必须有参数,才会列为有效的构造方法

            • 以上都不满足,就会返回null(代表,一个有效的都没有)

        • spring-推断构造方法_第2张图片

      • 得到了ctros,如果是null,其实就会去找无参构造方法去创建对象,没找到就会抛异常(这个是兜底的)就是这个方法instantiateBean

      • 		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
        				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
        			return autowireConstructor(beanName, mbd, ctors, args);
        		}
      • 如果这四个条件满足其一就会开始找了

      • 如果推断出来了构造方法,则需要给构造方法赋值,也就是给构造方法参数赋值,也就是构造方法注入
         如果没有推断出来构造方法,但是autowiremode为AUTOWIRE_CONSTRUCTOR,则也可能需要给构造方法赋值,因为不确定是用无参的还是有参的构造方法
        如果通过BeanDefinition指定了构造方法参数值,那肯定就是要进行构造方法注入了
         如果调用getBean的时候传入了构造方法参数值,那肯定就是要进行构造方法注入了

        • 开始注入

        • autowireConstructor

 autowireConstructor

上面分析:ctros 要么是 null 只有一个 要么有多个

一个和多个 就会进入autowireConstructor 方法,其他的三个条件,大部分情况下都不符合

autowireConstructor这个方法也是超级无敌长

你可能感兴趣的:(java,开发语言)