Spring Java Config:如何创建一个带有运行时参数的原型范围 @Bean?

12 浏览
0 Comments

Spring Java Config:如何创建一个带有运行时参数的原型范围 @Bean?

使用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;
    }
}

请注意,名称为final:它只能通过构造函数提供,并保证不可变性。其他依赖项是Thing类的实现特定依赖项,并且不应该被了解(紧密耦合)请求处理程序实现。

这个代码在Spring XML配置下表现得非常出色,例如:

    

如何使用Java配置实现相同的功能?在使用Spring 3.x时,以下代码不起作用:

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

现在,我可以创建一个Factory,例如:

public interface ThingFactory {
    public Thing createThing(String name);
}

但这违反了使用Spring替换ServiceLocator和Factory设计模式的整个目的,这将是这种用例的理想选择。

如果Spring Java Config可以做到这一点,我将能够避免:

定义工厂接口

定义工厂实现

编写工厂实现的测试

这是一项相对而言非常琐碎的工作,Spring已经通过XML配置支持了这个问题。

admin 更改状态以发布 2023年5月21日
0
0 Comments

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

@Configuration    
public class ServiceConfig {
    @Bean
    public Function thingFactory() {
        return name -> thing(name); // or this::thing
    } 
    @Bean
    @Scope(value = "prototype")
    public Thing thing(String name) {
       return new Thing(name);
    }
}

使用方法:

@Autowired
private Function thingFactory;
public void onRequest(Request request) {
    //request is already validated
    String name = request.getParameter("name");
    Thing thing = thingFactory.apply(name);
    // ...
}

现在你可以在运行时获取你的bean。当然,这是一种工厂模式,但是你可以节省编写特定类(例如ThingFactory)的时间(但是,您将不得不编写自定义@FunctionalInterface以传递超过两个参数)。

0
0 Comments

在一个@Configuration类中,像下面这样的一个@Bean方法:\n

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

\n用于注册一个bean定义并提供创建bean的工厂。它所定义的bean仅在使用直接或通过扫描ApplicationContext确定的参数请求时才实例化。\n在原型bean的情况下,每次都会创建一个新对象,因此相应的@Bean方法也会被执行。\n可以通过其BeanFactory#getBean(String name, Object... args)方法从ApplicationContext检索bean,其中明确指定了构造函数参数/工厂方法参数,覆盖了bean定义中指定的默认参数(如果有)。\n换句话说,对于这个作用域为原型的bean,你提供的是将在@Bean方法调用中使用的参数,而不是bean类的构造函数。(这个方法使用名称查找bean,具有非常弱的类型保证。)\n或者,你可以使用具有类型的BeanFactory#getBean(Class requiredType, Object... args)方法按类型查找bean。\n至少对于Spring版本4+来说是这样的。\n请注意,如果你不想从ApplicationContext或BeanFactory开始检索你的bean,你可以注入一个ObjectProvider(自Spring4.3起)。\n这是专门为依赖注入点设计的ObjectFactory变体,允许编程的可选性和宽松的非唯一处理。\n并使用它的getObject(Object... args)方法返回此工厂管理的对象的一个实例(可能是共享的或独立的),允许指定明确的构造参数,类似于BeanFactory.getBean(String, Object)。例如,\n

@Autowired
private ObjectProvider things;
[...]
Thing newThing = things.getObject(name);
[...]

0