当前位置: 首页 > 知识库问答 >
问题:

spring·Java配置:如何使用运行时参数创建一个原型范围的@bean?

辛龙野
2023-03-14

使用spring的Java配置,我需要获取/实例化一个具有构造函数参数的原型范围的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;
    }
}

注意namefinal:它只能通过构造函数提供,并保证不变性。其他依赖项是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和工厂设计模式的全部意义,而这些模式对于这个用例来说是非常理想的。

如果spring·Java配置可以这样做,我就可以避免:

  • 定义工厂接口
  • 定义工厂实现
  • 为工厂实现编写测试

对于spring已经通过XML Config支持的如此琐碎的东西来说,这是一大堆工作(相对而言)。

共有1个答案

艾修然
2023-03-14

@configuration类中,@bean方法如下所示

@Bean
@Scope("prototype")
public Thing thing(String name) {
    return new Thing(name);
}

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

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

您可以通过BeanFactory的#getBean(String name,Object...args)方法从ApplicationContext中检索一个bean

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

参数:

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

换句话说,对于这个prototype作用域bean,您提供的参数不是在bean类的构造函数中使用,而是在@bean方法调用中使用。(此方法的类型保证非常弱,因为它使用了bean的名称查找。)

或者,您可以使用类型化的BeanFactory#GetBean(Class requiredType,Object...args)方法,该方法按类型查找bean。

至少对于spring 4+版来说是这样的。

请注意,如果您不想从ApplicationContextBeanFactory开始检索bean,您可以注入ObjectProvider(自spring 4.3以来)。

objectFactory的一个变体,专门为注入点设计,允许编程的可选性和宽松的非唯一处理。

并使用其getObject(对象...args)方法

返回此工厂管理的对象的一个实例(可能是共享的或独立的)。

允许按照beanfactory.getBean(String,Object)的行指定显式构造参数。

例如,

@Autowired
private ObjectProvider<Thing> things;

[...]
Thing newThing = things.getObject(name);
[...]

 类似资料:
  • 问题内容: 使用Spring的Java Config,我需要使用只能在运行时获得的构造函数参数来获取/实例化作用域原型的bean。考虑以下代码示例(为简便起见,已简化): Thing类的定义如下: 注意事项name是final:它只能通过构造函数来提供,并保证不变性。其他依赖关系是Thing类的特定于实现的依赖关系,不应知道(紧密耦合到)请求处理程序实现。 这段代码与Spring XML配置完美配

  • 我是Spring框架的新手,找不到实现以下内容的方法: 我正在使用一个类,它的属性都是私有的,没有设置器(使用该类对象的预期方式是用构造函数设置一次属性)-我将它称为首选项。我还有几个类,每个类都有相同的首选项实例作为属性。首选项旨在包含某些属性,其中一些只能在运行时解析(例如由用户提供)。

  • 问题内容: 我想知道,如果有人能告诉我,范围函数如何采用:单个参数,或或。它是否使用一个参数来收集参数,然后使用一系列if语句根据所提供的参数数量来分配正确的值?从本质上说,它规定,如果有一个参数,然后将其设置成停止争论,或者如果有两个那么他们,和,或者如果有三个然后设置这些作为,和分别?我想知道如果要用纯Cpython编写范围怎么办。谢谢!!! 更新 :当我最初问这个问题时,我并没有澄清我想知道

  • 问题内容: 我有一个表,其中的行带有范围的开始和结束编号,例如 等等.. 我想创建一个临时表(或表变量/ cte等),其中每个数字都有一行,并且它们之间的范围也包括在内-即给出上述示例,我希望看到一个具有以下行的表: 谁能指出我朝着实现这一目标的快捷方式的方向?我考虑过以某种方式使用数字表,但是我正在查看的表具有> 200m行,而我没有那么大的数字表! 任何帮助深表感谢。提前致谢。 问题答案: