日积月累,水滴石穿 😄
前言
上篇讲到程序执行了 resolveBeforeInstantiation
函数之后,如果返回的结果为 null,就需要执行 doCreateBean
函数进行创建 Bean。那本篇就来分析 doCreateBean
的代码逻辑
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
// BeanWrapper是对Bean的包装
BeanWrapper instanceWrapper = null;
//1、如果是单例,移除缓存
if (mbd.isSingleton()) {
// factoryBeanObjectCache:存的是beanName对应的FactoryBean.getObject()所返回的对象
// factoryBeanInstanceCache:存的是beanName对应的FactoryBean实例对象
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
// 2、实例化
if (instanceWrapper == null) {
// 创建bean实例 1、工厂方法 2、构造函数自动注入 3、简单初始化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 包装的实例对象,也就是原始对象
final Object bean = instanceWrapper.getWrappedInstance();
// 包装的实例对象的类型
Class<?> beanType = instanceWrapper.getWrappedClass();
// 如果不是NullBean,则将resolvedTargetType 属性设置为当前的WrappedClass
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
//3、寻找注入点
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// 这里会查找@Autowired、@Value、Resource的注入点(InjectedElement),
// 并把这些注入点添加到mbd的属性externallyManagedConfigMembers中
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
//4、
//如果当前bean是单例并且支持循环依赖,且当前bean正在创建,
//就通过往singletonFactories(三级缓存)添加一个objectFactory,
//这样后期如果有其他bean依赖该bean 可以从singletonFactories获取到bean, 解决循环依赖
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 构造一个 ObjectFactory 添加到singletonFactories中
// getEarlyBeanReference()可以对 返回的bean进行修改,目前除了可能会返回动态代理对象(aop) 其他的都是直接返回bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 5、填充属性,对 bean 进行填充 将各个属性注入
populateBean(beanName, mbd, instanceWrapper);
// 6、执行初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
// 7、检测循环依赖
if (earlySingletonExposure) {
// earlySingletonReference 只有在检测到有循环依赖的情况下才会不为空
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 如果提前暴露的对象(bean)和经过了完整的生命周期后的对象相等(exposedObject)
// 则把缓存中的earlySingletonReference赋值给exposedObject
// 最终会添加到singletonObjects中去
// (初始化之后的bean等于原始的bean,说明不是proxy),
//
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
//检测该bean的dependon的bean是否都已经初始化好了
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
/*
* 因为 bean 创建后;其所依赖的 bean 一定是创建了的。
* actualDependentBeans 不为空表示当 bean 创建后依赖的 bean 没有
* 全部创建完,也就是说存在循环依赖
*/
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
// 8、注册DisposableBean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
}
上述代码分支挺多的,总结一下关键点:
1、如果是单例则需要首先清除缓存
2、实例化 Bean
,有四种方式:工厂方法,Supplier
回调、有参构造函数自动注入、默认构造函数注入
3、MergedBeanDefinitionPostProcessor
的使用
4、单例模式下的依赖处理
5、属性填充,将所有属性填充至 bean 的实例中
6、执行初始化方法
7、循环依赖检查,存在循环依赖则抛出异常
8、注册 DisposableBean
第一点就不再分析了。我们来看第二点实例化Bean createBeanInstance
方法。本文就分析其中两种实例化Bean 的方式。分别是:工厂方法,Supplier 回调。其余两种放到下一篇。
createBeanInstance
进入到createBeanInstance
方法, 该方法位于 AbstractAutowireCapableBeanFactory
类中
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 得到bean的class 使用类加载器根据设置的 class 属性或者根据 className 来解析 Class
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 如果beanclass不是public 且不允许访问非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());
}
// 这是Spring提供给开发者的扩展点
// 当一个BeanDefinition中存在一个Supplier类的时候, Spring就利用这个类的get方法来获取实例,
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 通过factoryMethod实例化这个bean
// factorMethod这个名称在xml中还是比较常见的, 即通过工厂方法来创建bean对象
// 如果一个bean对象是由@Bean注解创建的, 也会走instantiateUsingFactoryMethod方法来创建
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean... 重新创建相同bean时的快捷方式
boolean resolved = false;
boolean autowireNecessary = false;
// 当作用域为原型、多次调用getBean()时,不传入参数,从缓存中获取这段逻辑才会被执行
// 如果是单例,第二次调用 getBean(),直接从单例池获取对象了,根本就不会走到这里
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
// resolvedConstructorOrFactoryMethod 缓存了已解析的构造函数或工厂方法
if (mbd.resolvedConstructorOrFactoryMethod != null) {
// resolved为true,表示当前bean的构造方法已经确定了,也代表该Bean之前被解析过
resolved = true;
// constructorArgumentsResolved:将构造函数参数标记为已解析,true就是标记为了已解析
// 默认为 false。
// 如果autowireNecessary为true说明是采用有参构造函数注入
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
// resolved为true,表示当前bean的构造方法已经确定了,也代表该Bean之前被解析过
// autowireNecessary表示采用有参构造函数注入
if (autowireNecessary) {
// 采用有参构造函数注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 如果构造方法已经确定了,但是没有确定构造方法参数,那就表示没有构造方法参数,用无参的构造方法来实例化bean
return instantiateBean(beanName, mbd);
}
}
// 代码执行到这,说明是第一次创建该bean
// 根据SmartInstantiationAwareBeanPostProcessor获取构造函数,
// 具体实现在:AutowiredAnnotationBeanPostProcessor
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 通过BeanPostProcessor找出了构造方法
// 或者BeanDefinition的autowire属性为AUTOWIRE_CONSTRUCTOR xml中使用了 autowire="constructor"
// 或者BeanDefinition中指定了构造方法参数值 使用了 <constructor-arg>标签
// 或者在getBean()时指定了args
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 进行有参构造方法推断并实例化
return autowireConstructor(beanName, mbd, ctors, args);
}
// 没啥用
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// 用无参的构造方法来实例化bean
return instantiateBean(beanName, mbd);
}
上面代码一大堆,其主要的逻辑为:
1、如果存在 Supplier
回调,则调用 obtainFromSupplier()
进行初始化
2、如果存在工厂方法,则使用 instantiateUsingFactoryMethod()
进行初始化
3、判断 resolvedConstructorOrFactoryMethod
是否不为空,如果不为空,则存在缓存,直接使用已经解析了的。然后根据 autowireNecessary
参数来判断是使用有参构造函数自动注入还是使用默认构造函数注入。
4、如果缓存中没有,则需要明确使用哪个构造函数来完成解析工作,因为一个类可以有多个构造函数,每个构造函数都有不同的构造参数,所以需要根据参数来锁定构造函数并完成初始化。如果存在参数则使用相应的带有参数的构造函数,否则使用默认构造函数。
obtainFromSupplier
Supplier
是 Java8
的一个函数式接口。该接口中就一个 get() 方法。具体介绍不多说,详情请前往 Java8——Lambda表达式
从上述代码可以看到 Spring
是从 mbd
中得到的 Supplier
。既然可以得到那就可以进行设置。instanceSupplier
属性是属于 AbstractBeanDefinition
抽象类的。
- set方法 进行设置
public void setInstanceSupplier(@Nullable Supplier<?> instanceSupplier) {
this.instanceSupplier = instanceSupplier;
}
- 构造方法 进行设置
public <T> RootBeanDefinition(@Nullable Class<T> beanClass, @Nullable Supplier<T> instanceSupplier) {
super();
setBeanClass(beanClass);
setInstanceSupplier(instanceSupplier);
}
- 直接进行注册
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
ctx.registerBean(Person.class, new Supplier<Person>() {
@Override
public Person get() {
return new Person("gongj");
}
});
使用
这里就对使用 set方式
举例。首先创建两个普通类对象,Person
和 User
。
public class Person{
private String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
public class User {
}
测试
public static void main(String[] args) {
// 创建 BeanFactory 容器
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 构建 BeanDefinition
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClass(User.class);
// 构造器引用 这里调用的是无参构造器
rootBeanDefinition.setInstanceSupplier(Person::new);
// 注册BeanDefinition
factory.registerBeanDefinition("user",rootBeanDefinition);
Object user = factory.getBean("user");
// 返回的是 Person 对象
System.out.println("结果:" +user);
}
结果:Person{name='null'}
可以看到我们 setBeanClass
设置的是User
,但结果确是Person
。
如果设置了 instanceSupplier
则调用 obtainFromSupplier()
完成 bean 的初始化,如下:
protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {
Object instance;
String outerBean = this.currentlyCreatedBean.get();
// 设置 beanName到 currentlyCreatedBean 中
this.currentlyCreatedBean.set(beanName);
try {
// 调用 Supplier 的 get(),返回一个 Bean 对象
instance = instanceSupplier.get();
}
finally {
if (outerBean != null) {
this.currentlyCreatedBean.set(outerBean);
}
else {
this.currentlyCreatedBean.remove();
}
}
// get() 未创建 Bean 对象,则创建 NullBean 对象
if (instance == null) {
instance = new NullBean();
}
// 创建bean的包装类
BeanWrapper bw = new BeanWrapperImpl(instance);
// 初始化bean的包装
initBeanWrapper(bw);
return bw;
}
obtainFromSupplier
方法的代码很简单,调用 Supplier
的 get()
方法获得一个实例对象,然后根据该实例对象构造一个 BeanWrapper
对象 bw
,最后初始化该对象。
instantiateUsingFactoryMethod
通过 factory-method
创建对象有两种方式,一种是静态工厂注入(其中的方法必须是静态的),另一种是实例工厂注入。具体使用请移步前往:XML文件的读取-factory-method的使用
该方法位于 AbstractAutowireCapableBeanFactory
类
protected BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}
然后再进入 ConstructorResolver
类的 instantiateUsingFactoryMethod
public BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
// 构造 BeanWrapperImpl 对象
BeanWrapperImpl bw = new BeanWrapperImpl();
// 初始化 BeanWrapperImpl
// 向 BeanWrapper对象中添加 ConversionService 对象和属性编辑器 PropertyEditor 对象
this.beanFactory.initBeanWrapper(bw);
Object factoryBean;
Class<?> factoryClass;
// 当前factoryMethod是不是静态的
boolean isStatic;
//获取 factory-bean 属性的值,如果有值就说明是 实例工厂方式实例对象
String factoryBeanName = mbd.getFactoryBeanName();
if (factoryBeanName != null) {
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
}
// 根据 factoryBeanName 获取工厂实例
// 直接走 getBean 方法
factoryBean = this.beanFactory.getBean(factoryBeanName);
//如果当前Bean是单例并且单例池中存在该beanName的对象 则抛出异常
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
throw new ImplicitlyAppearedSingletonException();
}
factoryClass = factoryBean.getClass();
isStatic = false;
}
// 静态工厂方式
else {
// It's a static factory method on the bean class.
// 静态工厂创建bean,必须要提供工厂的全类名
if (!mbd.hasBeanClass()) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"bean definition declares neither a bean class nor a factory-bean reference");
}
factoryBean = null;
factoryClass = mbd.getBeanClass();
isStatic = true;
}
// 工厂方法
Method factoryMethodToUse = null;
ArgumentsHolder argsHolderToUse = null;
// 参数
Object[] argsToUse = null;
// 开发者在调用 getBean 方法的时候指定了方法参数则直接使用
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
// 没有指定,则尝试从 mbd 中解析参数
Object[] argsToResolve = null;
// 首先尝试从缓存中获取
synchronized (mbd.constructorArgumentLock) {
// 获得已解析的构造函数或工厂方法
// resolvedConstructorOrFactoryMethod:缓存已解析的构造函数或工厂方法
factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
// 找到了mbd中缓存的构造方法
if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached factory method...
// 获得已完全解析的构造函数参数(参数类型已经确定,能够直接进行使用)
// 正常情况下 resolvedConstructorArguments 的值就是 null
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
//获得部分准备好的构造函数参数(该参数的类型是不确定的,需要进行解析)
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
//如果存在构造函数参数,那么则对参数值进行类型转化
//如给定方法的构造函数 Person(int) 则通过此方法后就会把配置中的
// "5“ 转换为 5
//<constructor-arg index="0" value="5"/>
//缓存中的值可能是原始值也可能是最终值
if (argsToResolve != null) {
// 什么时候进入这里? 当作用域为原型时并多次调用 getBean()时没有传递参数
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
}
}
// 如果当前BeanDefinition中没有解析出来具体的factoryMethod对象,或者没有解析出对应的方法参数
// 也就是没有缓存,第一次进行创建
// 那什么时候能解析出来缓存呢?当作用域为原型时、多次调用getBean方法时不传入参数
if (factoryMethodToUse == null || argsToUse == null) {
// 如果当前类是cglib生成的代理类,则获取其父类,否则返回class本身
factoryClass = ClassUtils.getUserClass(factoryClass);
// 方法集合
List<Method> candidates = null;
// 工厂方法是否唯一
if (mbd.isFactoryMethodUnique) {
if (factoryMethodToUse == null) {
factoryMethodToUse = mbd.getResolvedFactoryMethod();
}
if (factoryMethodToUse != null) {
candidates = Collections.singletonList(factoryMethodToUse);
}
}
if (candidates == null) {
candidates = new ArrayList<>();
// 获取工厂类里所有待定方法
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
// 检索所有方法 将符合条件的方法添加到集合中
for (Method candidate : rawCandidates) {
// 当前方法是否包含static修饰符,包含则返回true,否则返回false,然后与 isStatic 比较
// 当前方法名称是否与 配置的factoryMethod方法名称是否相等
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
candidates.add(candidate);
}
}
}
// 找到的方法数量为 1 并且没有传入参数 配置文件也没有使用 constructor-arg 属性
if (candidates.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
Method uniqueCandidate = candidates.get(0);
// 该工厂方法的参数个数为 0
if (uniqueCandidate.getParameterCount() == 0) {
// 缓存唯一的工厂方法
mbd.factoryMethodToIntrospect = uniqueCandidate;
synchronized (mbd.constructorArgumentLock) {
// 缓存已解析的构造函数或工厂方法
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
// 将构造函数参数标记为已解析
mbd.constructorArgumentsResolved = true;
// 缓存完全解析的构造函数参数
mbd.resolvedConstructorArguments = EMPTY_ARGS;
}
// 创建对象
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
return bw;
}
}
// 匹配的方法数量 大于 1,进行方法排序
// 按构造方法的参数个数降序排序,先排序public构造函数,参数降序排列
// 然后排序非public 的构造函数,参数降序排列
if (candidates.size() > 1) {
candidates.sort(AutowireUtils.EXECUTABLE_COMPARATOR);
}
// 记录解析后的构造方法参数值
ConstructorArgumentValues resolvedValues = null;
// autowireMode 是构造方法自动注入,则要自动选择构造方法
boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Method> ambiguousFactoryMethods = null;
// minNrOfArgs:表示所有构造方法中,参数个数最少的构造方法的参数个数是多少
int minNrOfArgs;
// 开发者在调用 getBean 方法的时候指定了方法参数则直接使用方法参数的个数
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}else {
// 如果有为这个bean定义的构造函数参数值,则返回true
if (mbd.hasConstructorArgumentValues()) {
// 构造函数的参数 值来源于 constructor-arg标签
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
// 解析参数个数 值来源于 constructor-arg 标签中的 index属性的值
// 也会将该 bean 的构造函数参数解析为 resolvedValues 对象,其中会涉及到其他 bean
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}else {
// 没有指定参数 也没有 定义constructor-arg标签
minNrOfArgs = 0;
}
}
LinkedList<UnsatisfiedDependencyException> causes = null;
for (Method candidate : candidates) {
// 方法的参数个数
int parameterCount = candidate.getParameterCount();
// 当前方法的参数个数 大于等于 最小的构造方法的参数个数
if (parameterCount >= minNrOfArgs) {
ArgumentsHolder argsHolder;
// 当前方法每个参数的参数类型
Class<?>[] paramTypes = candidate.getParameterTypes();
// 调用getBean()时传递了参数
if (explicitArgs != null) {
//已经显式的给出参数->参数长度必须精确匹配,不匹配则跳过当前方法
if (paramTypes.length != explicitArgs.length) {
continue;
}
// 参数长度已经匹配 根据 genBean()方法传入的参数构建 ArgumentsHolder 对象
argsHolder = new ArgumentsHolder(explicitArgs);
}else {
// 调用getBean()时没有传递参数
try {
String[] paramNames = null;
// ParameterNameDiscoverer用于解析方法、构造函数上的参数名称
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
// 获取指定方法的参数名称
paramNames = pnd.getParameterNames(candidate);
}
// 在获得 解析的构造函数参数值(resolvedValues) 的情况下,创建一个ArgumentsHolder 对象
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
paramTypes, paramNames, candidate, autowiring, candidates.size() == 1);
}
catch (UnsatisfiedDependencyException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
}
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
}
// 根据参数类型和参数值计算权重
// Lenient宽松,默认宽松模式是开启的
// 严格模式:解析函数时,必须所有的都需要匹配,否则抛出异常
// 宽松模式:使用具有"最接近的模式"进行匹配
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// 如果当前方法的权重比较小,则表示当前方法更合适
if (typeDiffWeight < minTypeDiffWeight) {
factoryMethodToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousFactoryMethods = null;
}
// 如果具有相同参数数量的方法具有相同的类型差异权重,则收集此类型选项
// 但是,仅在非宽松构造函数解析模式下执行该检查,并显式忽略重写方法(具有相同的参数签名)
else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
!mbd.isLenientConstructorResolution() &&
paramTypes.length == factoryMethodToUse.getParameterCount() &&
!Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
if (ambiguousFactoryMethods == null) {
ambiguousFactoryMethods = new LinkedHashSet<>();
ambiguousFactoryMethods.add(factoryMethodToUse);
}
ambiguousFactoryMethods.add(candidate);
}
}
}
// 没有可执行的工厂方法,抛出异常
if (factoryMethodToUse == null || argsToUse == null) {
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
List<String> argTypes = new ArrayList<>(minNrOfArgs);
if (explicitArgs != null) {
for (Object arg : explicitArgs) {
argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
}
}
else if (resolvedValues != null) {
Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
valueHolders.addAll(resolvedValues.getGenericArgumentValues());
for (ValueHolder value : valueHolders) {
String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
(value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
argTypes.add(argType);
}
}
String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"No matching factory method found: " +
(mbd.getFactoryBeanName() != null ?
"factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
"factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
"Check that a method with the specified name " +
(minNrOfArgs > 0 ? "and arguments " : "") +
"exists and that it is " +
(isStatic ? "static" : "non-static") + ".");
}
else if (void.class == factoryMethodToUse.getReturnType()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Invalid factory method '" + mbd.getFactoryMethodName() +
"': needs to have a non-void return type!");
}
else if (ambiguousFactoryMethods != null) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous factory method matches found in bean '" + beanName + "' " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousFactoryMethods);
}
if (explicitArgs == null && argsHolderToUse != null) {
mbd.factoryMethodToIntrospect = factoryMethodToUse;
// 将解析的构造函数加入缓存
argsHolderToUse.storeCache(mbd, factoryMethodToUse);
}
}
// 反射调用factoryBean对象中的工厂方法进行实例化得到一个对象
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
return bw;
}
累了累了,这个方法是真的长,而且分支还特别多。各位读者下去需要多 Debug
几次了。
接下来总结一下:
上面那么多代码其实就是在确认:确定工厂对象,然后确认构造函数和构造参数,最后调用 InstantiationStrategy
对象的 instantiate()
来创建实例。
- 1、首先确定
factory-bean
属性的值,如果值不为 null,则代表是实例工厂方式实例对象,调用beanFactory.getBean()
获取工厂对象。若为空,则代表是静态工厂方式,对于静态工厂方法必须提供工厂类的全类名,同时设置factoryBean = null
,isStatic = true
。这里就确定了工厂对象。 - 2、工厂对象确定后,则是确认构造参数。构造参数的确认主要分为三种情况:
explicitArgs
参数、缓存中获取、配置文件中解析。explicitArgs
参数也就是我们在调用getBean
方法时指定的方法参数。如果explicitArgs
不为空,则可以确认方法参数就是它,那也就没必要从缓存中获取了。只需要确定工厂方法就好了。如果explicitArgs
为空,则需要从缓存中确定了,在缓存中可以确定工厂方法和构造参数。如果工厂方法和构造参数都确定好了直接调用InstantiationStrategy
对象的instantiate()
来创建实例。 - 3、如果
explicitArgs
参数为空、在缓存中也没有确定,那就只能从配置文件中获取构造参数信息。如果你阅读了笔者前面的文章就会知道,配置文件中的信息都会转换为BeanDefinition
对象,所以可以通过BeanDefinition
对象进行获取。 -
- 3.1、首先获取到工厂对象里的所有方法,包括工厂对象父类的方法,然后根据条件进行筛选。如果筛选出来的方法数量为 1 并且
explicitArgs
参数为空,配置文件也没有使用constructor-arg
属性,则使用无参工厂方法进行实例对象,调用InstantiationStrategy
对象的instantiate()
来创建实例。顺便进行缓存:
- 3.1、首先获取到工厂对象里的所有方法,包括工厂对象父类的方法,然后根据条件进行筛选。如果筛选出来的方法数量为 1 并且
if (uniqueCandidate.getParameterCount() == 0) {
// 缓存唯一的工厂方法
mbd.factoryMethodToIntrospect = uniqueCandidate;
synchronized (mbd.constructorArgumentLock) {
// 缓存已解析的构造函数或工厂方法
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
// 将构造函数参数标记为已解析
mbd.constructorArgumentsResolved = true;
// 缓存完全解析的构造函数参数
mbd.resolvedConstructorArguments = EMPTY_ARGS;
}
-
- 3.2、如果筛选出来的方法数量大于 1 ,对其进行排序处理,排序规则是:public 构造函数优先,参数数量降序;然后是非 public 构造参数数量降序。如果
explicitArgs
参数为空,则从配置文件获取构造参数信息,确定构造参数。
- 3.2、如果筛选出来的方法数量大于 1 ,对其进行排序处理,排序规则是:public 构造函数优先,参数数量降序;然后是非 public 构造参数数量降序。如果
// 如果有为这个bean定义的构造函数参数值,则返回true
if (mbd.hasConstructorArgumentValues()) {
// 构造函数的参数 值来源于 constructor-arg标签
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
// 解析参数个数,值来源于 constructor-arg 标签中的 index 属性的值 这个值可以随便写
// 也会将 bean 的构造函数参数解析为 resolvedValues 对象
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
-
- 3.3、通过循环的方式,遍历筛选出来的方法。再次进行筛选,当前方法的参数个数需要大于等于最小的构造方法的参数个数(
parameterCount >= minNrOfArgs
)。如果显示提供了参数(explicitArgs != null
),则直接比较两者的参数个数是否相等,如果相等则表示找到了,根据explicitArgs
参数构建ArgumentsHolder
对象。如果没有显示提供参数,则需要获取ParameterNameDiscoverer
对象,主要用于解析方法、构造函数上的参数名称。 根据 N 多个参数包装成ArgumentsHolder
对象,该对象用于保存参数,我们称之为参数持有者。当将对象包装成ArgumentsHolder
对象后,我们就可以通过它来进行构造函数匹配,匹配又分为严格模式和宽松模式,默认为宽松模式。也就是会使用argsHolder.getTypeDifferenceWeight(paramTypes)
方法进行计算。
- 3.3、通过循环的方式,遍历筛选出来的方法。再次进行筛选,当前方法的参数个数需要大于等于最小的构造方法的参数个数(
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// 如果当前方法的权重比较小,则表示当前方法更合适(分越少优先级越高?)
if (typeDiffWeight < minTypeDiffWeight) {
factoryMethodToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousFactoryMethods = null;
}
为什么分越少优先级越高?
主要是计算找到的bean和构造方法参数类型匹配程度有多高。
假设bean
的类型为 A,A 父类是 B,B 的父类是 C。同时 A 实现了接口 D
- 如果构造方法的参数类型为A,那么完全匹配,得分为0
- 如果构造方法的参数类型为B,那么得分为2
- 如果构造方法的参数类型为C,那么得分为4
- 如果构造方法的参数类型为D,那么得分为1
可以直接使用如下代码进行测试:
Object[] objects = new Object[]{new A()};
// 0
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{A.class}, objects));
// 2
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{B.class}, objects));
// 4
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{C.class}, objects));
// 1
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{D.class}, objects));
到此,工厂对象、工厂方法、参数都已经全部进行确认了,接下来就是调用 InstantiationStrategy
对象的 instantiate()
来创建 bean 实例。
instantiate
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
@Nullable Object factoryBean, final Method factoryMethod, Object... args) {
try {
// 忽略。。。
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(factoryMethod);
return null;
});
}
else {
// 设置给定的方法为可访问
ReflectionUtils.makeAccessible(factoryMethod);
}
Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
try {
currentlyInvokedFactoryMethod.set(factoryMethod);
// 使用反射创建对象
// 重点也就是这句话
Object result = factoryMethod.invoke(factoryBean, args);
if (result == null) {
result = new NullBean();
}
return result;
}
finally {
if (priorInvokedFactoryMethod != null) {
currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
}
else {
currentlyInvokedFactoryMethod.remove();
}
}
}
catch (IllegalArgumentException ex) {
// catch 省略
}
}
本文示例代码已上传:gitee
- 如你对本文有疑问或本文有错误之处,欢迎评论留言指出。如觉得本文对你有所帮助,欢迎点赞和关注。