使用 Spring 的 Java Config,我需要获取/实例化一个原型范围的 bean,其构造函数参数只能在运行时获得。考虑以下代码示例(为简洁起见进行了简化):
@Autowired
private ApplicationContext appCtx;
public void onRequest(Request request) {
//request is already validated
String name = request.getParameter("name");
Thing thing = appCtx.getBean(Thing.class, name);
//System.out.println(thing.getName()); //prints name
}
其中 Thing 类定义如下:
public class Thing {
private final String name;
@Autowired
private SomeComponent someComponent;
@Autowired
private AnotherComponent anotherComponent;
public Thing(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
注意 name
是 final
:它只能通过构造函数提供,并保证不变性。其他依赖项是 Thing
类的特定于实现的依赖项,不应为请求处理程序实现所知(紧密耦合)。
此代码与 Spring XML 配置完美配合,例如:
<bean id="thing", class="com.whatever.Thing" scope="prototype">
<!-- other post-instantiation properties omitted -->
</bean>
我如何使用 Java 配置实现相同的目的?以下不适用于 Spring 3.x:
@Bean
@Scope("prototype")
public Thing thing(String name) {
return new Thing(name);
}
现在,我 可以 创建一个工厂,例如:
public interface ThingFactory {
public Thing createThing(String name);
}
但这 _破坏了使用 Spring 替换 ServiceLocator 和 Factory 设计模式的全部意义_,这对于这个用例来说是理想的。
如果 Spring Java Config 可以做到这一点,我将能够避免:
- 定义工厂接口
- 定义工厂实现
- 为工厂实现编写测试
对于 Spring 已经通过 XML 配置支持的如此微不足道的事情,这是大量的工作(相对而言)。
原文由 Les Hazlewood 发布,翻译遵循 CC BY-SA 4.0 许可协议
在
@Configuration
类中,一个@Bean
方法就像这样用于注册 bean 定义并提供创建 bean 的工厂。它定义的 bean 仅根据请求使用直接或通过扫描
ApplicationContext
确定的参数实例化。在
prototype
bean 的情况下,每次都会创建一个新对象,因此也会执行相应的@Bean
方法。您可以通过它的
BeanFactory#getBean(String name, Object... args)
方法从ApplicationContext
检索一个 bean— 说明换句话说,对于这个
prototype
作用域 bean,您提供将要使用的参数,不是在 bean 类的构造函数中,而是在@Bean
方法调用中。 (此方法的类型保证非常弱,因为它使用 bean 的名称查找。)或者,您可以使用 typed
BeanFactory#getBean(Class requiredType, Object... args)
按类型查找 bean 的方法。这至少对于 Spring 4+ 版本是正确的。
请注意,如果您不想从
ApplicationContext
或BeanFactory
开始用于您的 bean 检索,您可以注入ObjectProvider
)。并使用其
getObject(Object... args)
方法例如,