Spring创建bean之实例化

上一篇文章分析了创建bean的整个过程时候,下面继续分步骤的进行分析Spring是如何创建bean的.
首先我们分析一下Spring是如何实例化bean的:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// 解析bean的class
        Class<?> beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
        // 如果没有可以使用的构造器则抛异常
        // 没有可以使用的是指:没有public的构造器,
        // 并且non-public的构造器又不允许获取
        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());
        } else {
        	// 获取instanceSupplier属性,
        	// 该属性使用了java8的lambda表达式指定了创建bean的方法
        	// 所以如果instanceSupplier不为空,直接调用该方法即可
        	// 就会用到工厂的反射或者寻找构造器再进行反射,提升了性能
            Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
            if (instanceSupplier != null) {
                return this.obtainFromSupplier(instanceSupplier, beanName);
            } else if (mbd.getFactoryMethodName() != null) {
            	// 如果工厂方法不为空,则使用工厂方法进行实例化.
            	// 即在rootBeanDefinition中存在factoryMethodName属性或者在配置文件中配置了factory-method
                return this.instantiateUsingFactoryMethod(beanName, mbd, args);
            } else {
                boolean resolved = false;
                boolean autowireNecessary = false;
                if (args == null) {
                    synchronized(mbd.constructorArgumentLock) {
                    	// 一个类中可以有多个构造函数,每个构造函数都有不同的参数
            			// 所以调用前需要先根据参数锁定构造函数或对应的工厂
                        if (mbd.resolvedConstructorOrFactoryMethod != null) {
                        	// 使用了缓存,因为在寻找构造器的时候,需要根据参数和类型去判断最终会使用哪个构造函数进行实例化,这个过程是比较消耗性能的
                        	// 如果已经解析过则直接从RootBeanDefinition中的属性resolvedConstructorOrFactoryMethod缓存的值去取,
                        	// 否则需要解析,并将解析的结果存放的resolvedConstructorOrFactoryMethod中.
                            resolved = true;
                            autowireNecessary = mbd.constructorArgumentsResolved;
                        }
                    }
                }
				// 如果已经解析过则使用解析好的构造函数方法,
				// 不需要再次锁定
                if (resolved) {
                    return autowireNecessary ? 
                    // 构造函数自动注入
                    this.autowireConstructor(beanName, mbd, (Constructor[])null, (Object[])null) : 
                    // 使用默认的构造函数
                    this.instantiateBean(beanName, mbd);
                } else {
                	// 需要根据参数解析构造函数
                    Constructor<?>[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName);
                    if (ctors == null && mbd.getResolvedAutowireMode() != 3 && !mbd.hasConstructorArgumentValues() && ObjectUtils.isEmpty(args)) {
                        ctors = mbd.getPreferredConstructors();
                        // 如果ctors != null不为空,则使用锁定的构造函数
                		// 否则使用默认构造器
                        return ctors != null ? this.autowireConstructor(beanName, mbd, ctors, (Object[])null) : this.instantiateBean(beanName, mbd);
                    } else {
                    	// 如果ctors不为空则使用锁定的构造函数
                        return this.autowireConstructor(beanName, mbd, ctors, args);
                    }
                }
            }
        }
    }

Spring把实例化分成了两种情况,一种是通用的实例化,另一种是带有参数的实例化.带有参数的实例化过程相当复杂,在判断对应参数上做了大量工作.

带有参数的实例化——autowireConstructor

protected BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
        return (new ConstructorResolver(this)).autowireConstructor(beanName, mbd, ctors, explicitArgs);
    }
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
			@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {

		BeanWrapperImpl bw = new BeanWrapperImpl();
		this.beanFactory.initBeanWrapper(bw);

		Constructor<?> constructorToUse = null;
		ArgumentsHolder argsHolderToUse = null;
		Object[] argsToUse = null;
		// explicitArgs:通过getBean方法传入的参数
		if (explicitArgs != null) {
			// 如果getBean方法调用的时候直接指定方法参数,那么直接使用即可
			argsToUse = explicitArgs;
		}
		else {
			// 如果没有传的话,则尝试从配置文件中解析
			Object[] argsToResolve = null;
			synchronized (mbd.constructorArgumentLock) {
				// 尝试从缓存中获取
				constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
				if (constructorToUse != null && mbd.constructorArgumentsResolved) {
					// 从缓存中获取参数
					argsToUse = mbd.resolvedConstructorArguments;
					if (argsToUse == null) {
						// 配置文件的构造函数参数
						argsToResolve = mbd.preparedConstructorArguments;
					}
				}
			}
			// 如果缓存中存在
			if (argsToResolve != null) {
				// 解析参数类型,因为缓存中的值可能是原始值也可能是最终值
				// 所以进行类型转换
				// 比如A(int,int)的构造函数,通过此方法后,就会把配置文件中的("1","1")转换为(1,1)了.
				argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
			}
		}
		// 缓存中没有
		if (constructorToUse == null || argsToUse == null) {
			// 把指定的构造函数设置为候选
			Constructor<?>[] candidates = chosenCtors;
			if (candidates == null) {
				// 如果没有指定构造函数,则获取类的所有构造函数
				Class<?> beanClass = mbd.getBeanClass();
				try {
					candidates = (mbd.isNonPublicAccessAllowed() ?
							beanClass.getDeclaredConstructors() : beanClass.getConstructors());
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Resolution of declared constructors on bean Class [" + beanClass.getName() +
							"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
				}
			}
			// 如果候选的构造器只有一个,并且参数为空,并且md中的构造函数参数为空
			// 则能够确定构造函数为当前候选的构造函数
			if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
				Constructor<?> uniqueCandidate = candidates[0];
				if (uniqueCandidate.getParameterCount() == 0) {
					synchronized (mbd.constructorArgumentLock) {
						mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
						mbd.constructorArgumentsResolved = true;
						mbd.resolvedConstructorArguments = EMPTY_ARGS;
					}
					// 使用当前构造函数进行实例化,
					// 并把得到的对象放入的bw中
					bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
					return bw;
				}
			}

			// 判断构造方法是否为空,判断是否根据构造方法自动注入
			boolean autowiring = (chosenCtors != null ||
					mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
			ConstructorArgumentValues resolvedValues = null;
			// 用来存储确定的构造函数的参数最小个数
			int minNrOfArgs;
			if (explicitArgs != null) {
				// 如果调用getBean的时候传入的参数explicitArgs不为空
				// 则 minNrOfArgs的值就等于传入的参数个数
				minNrOfArgs = explicitArgs.length;
			}
			else {
				// 否则获取mbd上解析配置文件得到的构造函数的参数信息
				ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
				resolvedValues = new ConstructorArgumentValues();
				// 获取解析的构造函数参数的个数
				minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
			}
			// 按照public构造函数参数数量降序排序,
			// 再把非public构造函数按照参数数量降序排序
			AutowireUtils.sortConstructors(candidates);
			int minTypeDiffWeight = Integer.MAX_VALUE;
			Set<Constructor<?>> ambiguousConstructors = null;
			LinkedList<UnsatisfiedDependencyException> causes = null;

			for (Constructor<?> candidate : candidates) {
				// 当前构造函数的参数个数
				int parameterCount = candidate.getParameterCount();

				if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) {
					// 1、如果已经找到选用的构造函数
					// 2、或者需要的参数个数大于当前的构造函数参数个数终止
					// 因为已经按照参数数量降序排序了
					break;
				}
				if (parameterCount < minNrOfArgs) {
					// 如果当前的构造函数的参数小于mbd解析出来的构造函数参数的数量
					// 则继续寻找下一个
					// 为什么这里不是直接break
					// 注意上面的排序,先按照public进行排序的,当前小于可能仅仅是public类型的构造函数,非public的构造函数还没有遍历
					continue;
				}

				ArgumentsHolder argsHolder;
				// 获取当前构造函数的参数类型
				Class<?>[] paramTypes = candidate.getParameterTypes();
				// 如果参数不为空
				if (resolvedValues != null) {
					try {
						// 从注解上获取参数名称
						String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
						// 如果没有注解,则尝试使用参数名称探索器来获取
						if (paramNames == null) {
							// 获取参数名称探索器
							ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
							if (pnd != null) {
								// 使用参数名称探索器进行获取参数名称
								paramNames = pnd.getParameterNames(candidate);
							}
						}
						// 根据名称和数据类型创建参数持有者
						argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
								getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
					}
					catch (UnsatisfiedDependencyException ex) {
						if (logger.isTraceEnabled()) {
							logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
						}
						// Swallow and try next constructor.
						if (causes == null) {
							causes = new LinkedList<>();
						}
						causes.add(ex);
						continue;
					}
				}
				else {
					// 如果getBean传入了参数,则传入的个数必须和构造函数的参数个数相等
					if (parameterCount != explicitArgs.length) {
						continue;
					}
					argsHolder = new ArgumentsHolder(explicitArgs);
				}
				// 探索是否有不确定的构造函数存在,例如不同构造函数的参数为父子关系
				int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
						argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
				// 如果它代表着当前最接近的匹配则选择作为构造函数
				if (typeDiffWeight < minTypeDiffWeight) {
					constructorToUse = candidate;
					argsHolderToUse = argsHolder;
					argsToUse = argsHolder.arguments;
					minTypeDiffWeight = typeDiffWeight;
					ambiguousConstructors = null;
				}
				else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
					// 否则将当前构造函数放到集合ambiguousConstructors中
					// 作为判断是够抛异常的依据之一
					if (ambiguousConstructors == null) {
						ambiguousConstructors = new LinkedHashSet<>();
						ambiguousConstructors.add(constructorToUse);
					}
					ambiguousConstructors.add(candidate);
				}
			}

			if (constructorToUse == null) {
				if (causes != null) {
					UnsatisfiedDependencyException ex = causes.removeLast();
					for (Exception cause : causes) {
						this.beanFactory.onSuppressedException(cause);
					}
					throw ex;
				}
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"Could not resolve matching constructor " +
						"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
			}
			else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"Ambiguous constructor matches found in bean '" + beanName + "' " +
						"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
						ambiguousConstructors);
			}

			if (explicitArgs == null && argsHolderToUse != null) {
				// 如果换入的函数为空,并且argsHolderToUse不为空,则进行缓存
				argsHolderToUse.storeCache(mbd, constructorToUse);
			}
		}

		Assert.state(argsToUse != null, "Unresolved constructor arguments");
		//用解析到的构造函数进行实例化
		bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
		return bw;
	}

上面的代码真的很长很长,需要我们再做个总结
1、构造函数参数的确定

  • 根据explicitArgs参数判断
    如果传入的explicitArgs不为空,可以直接确定参数.即调用了getBean(string name,Object… args) throws BeanException;
    在获取bean的时候,用户不仅能够指定bean的名称,还可以指定bean所对应类的构造函数或者工厂方法的方法参数,主要用于静态工厂方法的调用,并且参数是完全匹配的参数,所以,可以进行判断.
  • 缓存中获取
    注意从缓存获取的参数可能是最终类型,也有可能是参数的初始类型,所以还需要经过类型转换器的过滤以确保参数类型与对应的构造函数参数类型完全对应.
  • 配置文件获取
    其实就是获取mbd中constructArgumentValues存储的构造函数的信息,然后获取对应的参数值信息,获取参数值的信息包括直接指定值.

2、构造函数的确定
确定了构造函数的参数之后,接下来就是根据参数在所有的构造函数中找到对应的构造函数.而寻找的方法就是根据参数个数匹配,所以在匹配之前对构造函数按照了public构造函数优先参数数量降序、非public构造函数参数数量降序排序.这样就能在遍历的时候快速判断排在后面的构造函数个数是否符合条件.
另外在配置文件中并不是唯一限制使用参数位置索引的方式去创建,同样还支持指定参数名称进行设定参数值的情况,< construct-arg name=“name” >,那么这种情况就需要首先确定构造函数中的参数名称.
函数参数名称的获取有两种方式:

  • 通过注解的方式获取
  • 使用Spring中提供的工具类ParameterNameDiscover来获取.

构造函数、参数名称、参数类型、参数值都确定后就可以锁定构造函数以及转换对应的参数类型了.

3、根据确定的构造函数转换对应的参数类型
4、构造函数的不确定性的验证
5、根据实例化测了以及得到的构造函数及函数参数实例化bean.

通用实例化——instantiateBean

protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
        try {
            Object beanInstance;
            if (System.getSecurityManager() != null) {
                beanInstance = AccessController.doPrivileged(() -> {
                    return thisx.getInstantiationStrategy().instantiate(mbd, beanName, this);
                }, this.getAccessControlContext());
            } else {
                beanInstance = this.getInstantiationStrategy().instantiate(mbd, beanName, this);
            }

            BeanWrapper bw = new BeanWrapperImpl(beanInstance);
            this.initBeanWrapper(bw);
            return bw;
        } catch (Throwable var6) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", var6);
        }
    }

从上面的代码可以看到,直接进行了实例化操作,这是因为带参数的构造函数,把大量的工作用来进行构造函数的锁定上了,如果没有参数的话,是非常简单的.

实例化策略
不管哪种方式进行实例化,都用到了实例化策略.Spring并没有直接根据信息直接使用反射进行实例化.


public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// 如果有需要覆盖或者动态替换的方法则当然需要使用cglib进行动态代理
		// 因为可以在创建代理的同时将动态方法织入到类中
		// 但如果没有需要动态改变的方法,为了方便直接反射就可以了
        if (!bd.hasMethodOverrides()) {
            Constructor constructorToUse;
            synchronized(bd.constructorArgumentLock) {
                constructorToUse = (Constructor)bd.resolvedConstructorOrFactoryMethod;
                if (constructorToUse == null) {
                    Class<?> clazz = bd.getBeanClass();
                    if (clazz.isInterface()) {
                        throw new BeanInstantiationException(clazz, "Specified class is an interface");
                    }

                    try {
                        if (System.getSecurityManager() != null) {
                            clazz.getClass();
                            constructorToUse = (Constructor)AccessController.doPrivileged(() -> {
                                return clazz.getDeclaredConstructor();
                            });
                        } else {
                            constructorToUse = clazz.getDeclaredConstructor();
                        }

                        bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                    } catch (Throwable var9) {
                        throw new BeanInstantiationException(clazz, "No default constructor found", var9);
                    }
                }
            }

            return BeanUtils.instantiateClass(constructorToUse, new Object[0]);
        } else {
        	// 否则使用动态代理
            return this.instantiateWithMethodInjection(bd, beanName, owner);
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值