在dubbo系列中我写了一篇探究Dubbo服务注册发现的原理,为了在spring中动态注入payservice接口,我利用了BeanDefinitionRegistryPostProcessor接口,中间利用factorybean来实现了一个自定义bean的创建过程.
但是待我运行之后报了这样的错误Could not resolve matching constructor (hint: specify index/type/name arguments for simple parameter,
不得以跟着refresh方法debug,一点点端详,查出了猫腻...
下面是整个代码链路跟踪图,看看这个PayService自定义接口是怎么一步一步注入到spring中的

refresh : 这就不说了,spring的核心方法都在这里
finishBeanFactoryInitialization : 完成此上下文的bean工厂的初始化,初始化所有剩余的单例bean
preInstantiateSingletons : 确保所有非延迟初始单例都实例化,同时考虑到FactoryBeans 。 如果需要,通常在工厂设置结束时调用。
getBean/doGetBean : 返回一个实例可以是指定bean的共享或独立的。
getSingleton : 再次检查单例缓存中是否有手动注册的单例
AH8q3dGK2f2vLZVgbRfLTjQPySe2yRaJHs.doCreateBean : 实际创建指定的bean。 此时已经进行了预创建处理,例如,检查postProcessBeforeInstantiation回调。区分默认的bean实例化,使用工厂方法和自动装配构造函数。
createBeanInstance : 使用适当的实例化策略为指定的bean创建一个新实例:工厂方法,构造函数自动装配或简单实例化
autowireConstructor : “自动装配构造函数”(按类型带有构造函数参数)的行为。 如果指定了显式构造函数参数值,则将所有剩余参数与Bean工厂中的Bean进行匹配时也适用。
这对应于构造函数注入:在这种模式下,Spring Bean工厂能够托管需要基于构造函数的依赖关系解析的组件
贴一下代码中FactoryBean的实现类
1 | /** |
我把断点直接打在ConstructorResolver.autowireConstructor方法上,

这个candidates是当前factorybean所有类型的构造函数,下面的逻辑是遍历且对给定已解析的构造函数参数值,创建一个参数数组以调用构造函数或工厂方法。也就是这个ArgumentsHolder

我写错的地方就是因为没有构造函数,导致constructorToUse == null成立,抛出BeanCreationException异常.
这里是要注入PayService,那假如我弄了个其他的构造函数呢,比如无参构造函数.或者不是interfaceClass,而是executor呢
在上面获取ArgumentsHolder对象时,会走到TypeConverterDelegate.convertIfNecessary方法中进行类型校验
- 对于指定的属性,将值转换为所需的类型(如果需要从字符串转换)。
- @param propertyName属性名
- @param oldValue前一个值,如果可用(可能是{@code null})
- @param newValue建议的新值
- @param requiredType 必须转换为的类型(如果不知道,例如集合元素,则转换为{@code null})
- @param typeDescriptor 目标属性或字段的描述符
- @return 新值,可能是类型转换的结果
- @throws 类型转换失败时抛出IllegalArgumentException异常
判断我当前注入的PayService是不是instance of这个构造函数传的参数,如果是则返回类型转换的结果,都不是,则导致constructorToUse == null成立,抛出BeanCreationException异常.如果中间类型转换失败,抛出IllegalArgumentException异常
再来看下factorybean中redisDiscoveryCenter和executor是怎么注入到PayService中的
1 | /** |
待PayService初始化完成,需要填充属性时执行populateBean方法,然后判断注入是bytype还是byname

我这里是bytype,会走到BeanWrapperImpl.getLocalPropertyHandler方法

然后从propertyDescriptors.get(name)获取到当前属性的PropertyDescriptor;
如果找不到则抛出异常,找到了,则进行反射赋值
**PropertyDescriptor描述了一个Java Bean的属性,通过一对访问器方法导出。所以必须对其属性提供setter方法**