【问题标题】:How to inject or get bean dynamically based on input value?如何根据输入值动态注入或获取bean?
【发布时间】:2020-04-19 14:53:26
【问题描述】:

抱歉,我对 Spring 很陌生。我想根据用户的输入值动态注入或获取 bean。

例如:

public interface PaymentGateway {}

public class PayPal implement PaymentGateway {}

public class Stripe implement PaymentGateway {}

public class Square implement PaymentGateway {}

public class PaymentService {

    @Autowired
    private final PaymentGateway gateway;

    // TODO

}

我让用户选择一个支付网关(PayPal、Stripe 或 Square)并注入一个 PaymentGateway 来处理。如何动态注入或获取bean?

非常感谢!

【问题讨论】:

标签: java spring spring-boot dependency-injection


【解决方案1】:

我认为您有多种方法可以做到这一点。

其中一个将是以下一个。

我看到PaymentGateway 这是一个private final,它强制您使用构造函数注入,即使您将@Autowired 放在成员字段的顶部。这意味着您可以通过以下方式将 PaymentService 创建为 bean:

@Bean
public PaymentService paymentService(PaymentGateway gw) {
   return new PaymentService(gw);
}

在这里您可以让您的客户使用任何PaymentGateway 实现想要的东西。

编辑

稍后的编辑是为了引入 Dispatcher 来找到正确的 PaymentGateway bean。

首先介绍一个枚举类型,比方说

enum PmtGatewayType {
PayPal,
Stripe,
Square
}

现在,在PaymentGateway 接口中添加如下方法:

public boolean accept(PmtGatewayType pmtGatewayType);

并通过以下方式实现它:

class Stripe implements PaymentGateway {

private PmtGatewayType gwType;

@Override
public boolean accept(PmtGatewayType pmtGwType) {

   return gwType.equals(pmtGwType);

}

现在,您可以创建另一个名为 PmtGwDispatcher 的类,您将在其中注入所有 PaymentGateway bean 的 List,如下所示:

@Component
class PmtGwDispacher {

@Autowired
private List<PaymentGateway> pmtGateways;

public PaymentGateway select(PmtGatewayType gwType) {

PaymentGateway gw = pmtGateways.stream().filter(gw -> gw.accept(gwType)).findFirst().get();

    if(gw == null) {
       throw new IllegalArgumentException("The provided gateway type is invalid");
    }
    }

现在,您可以在PaymentService 中注入PmtGwDispatcher 并使用它。

解决方案有点复杂,但它尊重 SOLID 原则。每个组件都遵守 SRP,每次您需要添加新的 PaymentGateway 时,您必须在枚举中添加一个条目并添加新网关的实现。

【讨论】:

  • 根据输入值注入 ApplicationContext 和 getBean() 怎么样?我根据值使用 switch-case 和 getBean()?
  • IMO 这不是一个好的解决方案,因为您的代码将被框架或依赖注入上下文耦合很多。 Spring 不再鼓励你这样做。您可以使用诸如 Dispatcher 之类的东西来查找您的 bean。我会用这样一个例子来编辑我的答案。
  • @Geany 在 Spring 中,您不能动态注入 bean,并且不建议使用每个注入接口的多个实现
  • 谢谢!我明白了。我不应该注入 ApplicationContext 因为引入了对 Spring 的依赖。我们必须创建一个新的中间层DispatchFactory 来与Spring Container 解耦。
  • @Geany 我不记得我是否写过这个,ApplicationContext 是一个内部 Spring 基础 bean,不应该在 Spring 本身之外使用。
猜你喜欢
  • 2021-09-05
  • 1970-01-01
  • 1970-01-01
  • 2020-09-11
  • 2017-02-27
  • 2023-03-10
  • 2021-08-24
  • 2021-01-19
  • 2011-12-16
相关资源
最近更新 更多