ConstructorResolver.autowireConstructor(...)
的javadoc说
如果指定了显式构造函数参数值,则还应用,将所有剩余参数与bean工厂中的bean匹配。
但我无法让它发挥作用。我得到了BeanCreationException
:
无法解析匹配的构造函数(提示:为简单参数指定索引/类型/名称参数以避免类型歧义)
在这个例子中,我有一个带有构造函数的bean,它接受Spring bean以及只在运行时才知道的String
和int
。
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class BeanWithRuntimeDependencies {
public final DependencyA dependencyA;
public final DependencyB dependencyB;
public final String myString;
public final int myInt;
public BeanWithRuntimeDependencies(
DependencyA dependencyA, DependencyB dependencyB,
String myString, int myInt) {
this.dependencyA = dependencyA;
this.dependencyB = dependencyB;
this.myString = myString;
this.myInt = myInt;
}
}
@Component
public class DependencyA { /* ... */ }
@Component
public class DependencyB { /* ... */ }
和我的测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class PrototypeBeanConstructorsApplicationTests {
@Autowired private ApplicationContext context;
@Autowired private DependencyA dependencyA;
@Autowired private DependencyB dependencyB;
@Test
public void getBeanFromContext() {
BeanWithRuntimeDependencies bean =
context.getBean(BeanWithRuntimeDependencies.class, "runtime string", 10);
assertNotNull(bean);
assertEquals(dependencyA, bean.dependencyA);
assertEquals(dependencyB, bean.dependencyB);
assertEquals("runtime string", bean.myString);
assertEquals(10, bean.myInt);
}
}
ConstructorResolver.autowireConstructor(...)
的源代码有一条评论:
// Explicit arguments given -> arguments length must match exactly.
似乎与其javadoc相矛盾。
有可能这样做吗?我做错了什么?
答案 0 :(得分:4)
看起来不可能按照你的方式去做。
实际上这是奇怪的情况。根据{{1}}中的下一个片段(源代码行#207 ),Spring不会将您的构造函数视为调用的候选者:ConstructorResolver.autowireConstructor(...)
正如您所正确指出的那样,它与javadoc声明完全相反:
...将所有剩余参数与bean工厂中的bean匹配
但是无论如何实现意味着默认情况下Spring不能解析构造函数来实例化这样的bean。您必须手动创建工厂方法。类似的东西:
...
// Explicit arguments given -> arguments length must match exactly.
if (paramTypes.length != explicitArgs.length) {
continue;
}
然后你可以根据需要从上下文中获取bean:
@Configuration
public class Config{
@Bean
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public BeanWithRuntimeDependencies beanWithRuntimeDependencies(String myString, int myInt){
return new BeanWithRuntimeDependencies(dependencyA(), dependencyB(), myString, myInt);
}
@Bean
public DependencyA dependencyA(){
return new dependencyA();
}
@Bean
public DependencyB dependencyB(){
return new dependencyB();
}
}
如果您不想与配置类和工厂方法达成协议,您只需将所需的bean传递到BeanWithRuntimeDependencies bean =
context.getBean(BeanWithRuntimeDependencies.class, "runtime string", 10);
即可。当然你必须从上下文中获取这些bean:
context.getBean()