为了账号安全,请及时绑定邮箱和手机立即绑定

Spring Java Config:如何使用运行时参数创建原型范围的@Bean?

Spring Java Config:如何使用运行时参数创建原型范围的@Bean?

白衣非少年 2019-12-10 10:22:14
使用Spring的Java Config,我需要使用只能在运行时获得的构造函数参数来获取/实例化作用域原型的bean。考虑以下代码示例(为简便起见,对其进行了简化):@Autowiredprivate 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配置支持了很多工作(相对而言)。
查看完整描述

3 回答

?
哈士奇WWW

TA贡献1799条经验 获得超6个赞

在@Configuration课堂上,@Bean像这样的方法


@Bean

@Scope("prototype")

public Thing thing(String name) {

    return new Thing(name);

}

用于注册bean定义并提供创建bean的工厂。它定义的Bean仅在请求时使用直接或通过扫描确定的参数实例化ApplicationContext。


对于prototypeBean,每次都会创建一个新对象,因此@Bean也会执行相应的方法。


您可以ApplicationContext通过的BeanFactory#getBean(String name, Object... args)方法检索Bean,该方法指出


允许指定显式构造函数自变量/工厂方法自变量,覆盖Bean定义中指定的默认自变量(如果有)。


参数:


如果使用静态工厂方法的显式参数创建原型,则使用args参数。在任何其他情况下,使用非null的args值都是无效的。


换句话说,对于此prototype作用域的bean,您将提供将要使用的参数,而不是在bean类的构造函数中,而是在@Bean方法调用中。


对于Spring 4+版本至少是这样。


查看完整回答
反对 回复 2019-12-10
?
慕标琳琳

TA贡献1830条经验 获得超9个赞

使用Spring> 4.0和Java 8,您可以更安全地执行此操作:


@Configuration    

public class ServiceConfig {


    @Bean

    public Function<String, Thing> thingFactory() {

        return name -> thing(name); // or this::thing

    } 


    @Bean

    @Scope(value = "prototype")

    public Thing thing(String name) {

       return new Thing(name);

    }


}

用法:


@Autowired

private Function<String, Thing> thingFactory;


public void onRequest(Request request) {

    //request is already validated

    String name = request.getParameter("name");

    Thing thing = thingFactory.apply(name);


    // ...

}

因此,现在您可以在运行时获取bean。当然,这是一种工厂模式,但是您可以节省一些时间来编写特定的类,例如ThingFactory(但是您必须编写custom @FunctionalInterface来传递两个以上的参数)。


查看完整回答
反对 回复 2019-12-10
  • 3 回答
  • 0 关注
  • 775 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信