spring bean的实例化是在bean的沈明周期中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的构造方法们的**
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)》