springBean的实例化过程详解---createBeanInstance(1)

概述

spring bean的实例化是在bean的沈明周期中createBeanInstance实现的

createBeanInstance

		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());
		}

即然是实例化一个类,那么不可避免的需要直到这个bean的class类型,在获取到class类型后,还会判断这个class的修饰符,如果说这个class的修饰符不是public ,spring就会抛出异常

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

这是Spring提供给开发者的扩展点
如果我们要自己来实现创建对象的过程, 那么就可以提供一个Supplier的实现类,
当一个BeanDefinition中存在一个Supplier实现类的时候, Spring就利用这个类的get方法来获取实例,
而不再走Spring创建对象的逻辑

		if (mbd.getFactoryMethodName() != null) {
     
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

在xml里面的配置其实 FactoryMethod 还是比较好理解的,就是去配置 factory-method 这个属性,使用工厂的方式来创建一个 Bean
对于注解配置而言,factory-method这个属性就是@Bean标注的方法,所以@Bean对应生成的BeanDefinition 的FactoryMethod是有值的
然后就会去通过反射执行对应的factory-method方法生成对应的Bean

		boolean resolved = false;
		boolean autowireNecessary = false;
		if (args == null) {
     
			synchronized (mbd.constructorArgumentLock) {
     
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
     
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}

对于一个类而言,java会为其提供一个默认的空参构造方法,但是实际工作中,程序员可能会为这个bean定义好几个构造方法,resolvedConstructorOrFactoryMethod : 记录的就是在实例化的时候需要使用的构造方法 or FactoryMethod
constructorArgumentsResolved :该BeanDefinition是否已经决定了要使用的构造方法参数
boolean resolved : 是否已经知道了要使用的构造方法
boolean autowireNecessary :是否知道了构造的参数值

args又是什么呢?
我们在使用getBean的时候 可以发现这个方法的一个重载方法 public Object getBean(String name, Object… args)
这个args参数 就是这里的 args,也就是说我们在getBean的时候可以尝试传一些参数,这样spring就会有选择性的将这个参数加到构造方法里面去
但是还有一个需要注意的点,这个方式只对原型的bean有用,或者是懒加载的bean,因为如果是非懒加载单例Bean,spring就已经使用自己的getBean进行了实例化

Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
			throws BeansException {
     
		// AutowiredAnnotationBeanPostProcessor
		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;
	}

接下来的这一步就很重要了可以看出来,这一步的目的是返回构造方法,并且是通过后置处理器来实现这个区找构造方法的逻辑

** 来看看spring 是如何找到构造bean的构造方法们的**

determineCandidateConstructors

					Constructor<?>[] rawCandidates;
						// 拿到当前类所有的构造方法,如果没有写任何构造方法,这里会返回一个无参的构造方法
					rawCandidates = beanClass.getDeclaredConstructors();
	
					List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
					// requiredConstructor表示@Autowired标注并且required为true的构造方法, 因为只允许出现一个这样的构造方法, 所以当这个变量存在值后, 又出现了一个相同情况的构造方法的话, Spring就会抛出一个错误
					Constructor<?> requiredConstructor = null;
					// defaultConstructor用来保存默认构造方法
					Constructor<?> defaultConstructor = null;

requiredConstructor :保存required == true
defaultConstructor :保存默认构造
candidates :存储结果

// 遍历所有的构造方法
					for (Constructor<?> candidate : rawCandidates) {
     
						// nonSyntheticConstructors这个变量是和primaryConstructor != null一起使用的,所以也不用管
						if (!candidate.isSynthetic()) {
     
							nonSyntheticConstructors++;
						}
						else if (primaryConstructor != null) {
     
							continue;
						}

						// 查看该构造方法上是否存在@Autowired注解,或者看代理类的父类中对应的构造方法上是否存在@Autowired注解
						MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
						if (ann == null) {
     
							// 如果当前类是cglib生成的代理类,则获取期父类
							Class<?> userClass = ClassUtils.getUserClass(beanClass);
							if (userClass != beanClass) {
     
								try {
     
									Constructor<?> superCtor =
											userClass.getDeclaredConstructor(candidate.getParameterTypes());
									ann = findAutowiredAnnotation(superCtor);
								}
								catch (NoSuchMethodException ex) {
     
									// Simply proceed, no equivalent superclass constructor found...
								}
							}
						}

						// 如果构造方法上存在@Autowired注解
						if (ann != null) {
     
							// requiredConstructor表示程序员手动指明的要使用的哪个构造方法
							// 所以如果有多个构造方法上都写了@Autowired注解就会报错,required位true的情况下
							// 因为作为程序员你如果告诉Spring多个构造方法,那Spring也就不知道到底要使用哪一个了
							if (requiredConstructor != null) {
     
								throw new BeanCreationException(beanName,
										"Invalid autowire-marked constructor: " + candidate +
										". Found constructor with 'required' Autowired annotation already: " +
										requiredConstructor);
							}
							// 查看@Autowired的required属性值,默认位true
							// 这里说明如果使用@Autowired ,那么入宫使用了requred==true,那么第二个required==false也会报错
							// 存在一个required==true,就不能存在其他的@Autowired
							boolean required = determineRequiredStatus(ann);
							if (required) {
     
								if (!candidates.isEmpty()) {
     
									throw new BeanCreationException(beanName,
											"Invalid autowire-marked constructors: " + candidates +
											". Found constructor with 'required' Autowired annotation: " +
											candidate);
								}
								requiredConstructor = candidate;
							}
							// candidates中存的是加了@Autowired注解的构造方法
							candidates.add(candidate);
						}
						// 如果当前构造方法上不存在@Autowired,并且是无参构造方法,则记录一下该无参构造方法
						// 所以我们可以方法,在遍历构造方法时,其实只关心无参构造方法和加了@Autowired注解的构造方法
						else if (candidate.getParameterCount() == 0) {
     
							defaultConstructor = candidate;
						}
					}

拿到所有的构造方法之后就开始遍历

					// 如果存在添加了@Autowired的构造方法
					if (!candidates.isEmpty()) {
     
						// 如果没有指定required为true的构造方法,那么就把构造方法添加到candidates中去,后续一起进行推断
						if (requiredConstructor == null) {
     
							if (defaultConstructor != null) {
     
								// 如果有无参的构造方法,这里会将无参的构造方法加入
								candidates.add(defaultConstructor);
							}
							// 如果没有指定required为true的构造方法,并且也没有无参的构造方法,并且只有一个构造方法
							else if (candidates.size() == 1 && logger.isInfoEnabled()) {
     
							...//省略
							}
						}

						// candidateConstructors就是当前方法的返回值
						// 把candidates方法,两种情况,要么只有一个@Autowired(required=true)的构造方法,要么多个@Autowired(required=false)+一个无参构造方法
						candidateConstructors = candidates.toArray(new Constructor<?>[0]);
					}
					// 如果candidates为空,表示没有构造方法上添加了@Autowired注解,并且只有一个构造方法,并且该构造方法的参数个数大于0
					// 那么表示只有一个构造方法可用,并且有参数 直接返回
					else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
     
						candidateConstructors = new Constructor<?>[] {
     rawCandidates[0]};
					}
					else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
							defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
     
						candidateConstructors = new Constructor<?>[] {
     primaryConstructor, defaultConstructor};
					}
					else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
     
						candidateConstructors = new Constructor<?>[] {
     primaryConstructor};
					}
					// 如果没有构造方法上添加了@Autowired注解,并且有多个构造方法,并且没有primaryConstructor
					else {
     
						//如果只有一个无参的构造 会返回空数组
						// 返回一个空的Constructor数组,表示没有推断出来构造方法
						candidateConstructors = new Constructor<?>[0];
					}

遍历完 之后就需要判断哪些构造方法需要进行返回
总结:
1. 只能有一个@Autowired(required=true)的构造方法,有多个会报错,如果是这种情况,那么就应该这个构造方法来实例化对象
2. 可以有多个@Autowired(required=false)的构造方法,如果是这种情况,那么还不确定到底应该用哪个构造方法来实例化对象,
所以,如果是这种情况,我们还需要把无参构造方法加到candidateConstructors集合中,一起作为候选构造方法
3. 如果没有@Autowired的构造方法,但是如果本来只有一个有参构造方法,则也表明了只有这个构造方法可用
4. 如果没有@Autowired的构造方法,并且有多个构造方法,则返回空
5. 如果只有一个唯一的构造方法会返回这个构造方法

	 这个方法做一件事情,就是去找到,到底哪些构造方法是可用的
	 6. 程序员通过@Autowired注解指定的构造方法
	 7. 在没有指定时,如果这个类只有一个构造方法,那么就应该用这个构造方法I(只有一个无参的构造,返回的是空数组)
	 8. 否则,当前方法也不知道应该用哪个构造方法

其实忙活了大半天,现在还没有正真的确定一定会用那个方法,只会把可能会用到的选择了出来,要确定具体要用哪一个构造方法,还需要进行构造方法的推断,将在笔者下篇博客讲解A《springBean的实例化过程详解—createBeanInstance(2)》

你可能感兴趣的:(java,spring)