【问题标题】:Dynamically choose dependency without if else在没有 if else 的情况下动态选择依赖项
【发布时间】:2018-08-07 04:28:57
【问题描述】:

如何在没有 if else 条件的情况下选择依赖项。

假设我有一个接口:

public interface A{

String doSomething(String req);
}

有两个服务实现A:

@Component
public class FirstImpl implements A{

   @override
   String doSomething(String req){
   return "something";
  }
}

和:

@Component
public class SecondImpl implements A{

 @override
    String doSomething(String req){
    return "something";
  }
}

现在我创建一个 AdapterService 类:

@Component
public class AdapterService{
    @Autowired
    private FirstImpl first;
    @Autowired
    private SecondImpl second;

    public getService(String name){
        if("name".equals("First")){
            return first;
        }else if("name".equals("Second")){
            return second;
        }
    }
}

现在调用实现:

@Service
public class BusinessService{
    @Autowired
    private AdapterService adapterService;

    void doSomething(String name,String req){
        return adapterService.getService(name).doSomething();
    }
}

现在,如果我需要创建另一个实现 A 的类,则需要在 ServiceAdapter 类中添加条件。像"Third".equals(name) 一样返回另一个注入的服务。对于每个新服务,都需要添加另一个 if else 条件并注入相应的服务。我怎样才能避免这个适配器类。 Spring 从名称中动态选择依赖关系。

【问题讨论】:

  • 如果您可以访问 applicationContext 对象,您可以调用 applicationContext.getBean(name) 并完全避免使用 ServiceAdapter 类。唯一的问题是您需要将这些豆子放在容器中。
  • @RishikeshDhokare 是绝对正确的,如果您可以按照代码所期望的方式命名您的 bean,或者只需在 A 中创建一个名为 getName() 的函数。然后在您的 BusinessService 类中,您可以注入 List<A> 并从中创建一个 Map<String,A>
  • 为什么要创建地图
  • 你没有得到他的解决方案。
  • @rishikeshdhokare 谢谢。它有效

标签: java spring spring-boot design-patterns dependency-injection


【解决方案1】:

如果你可以访问applicationContext对象,你可以调用

applicationContext.getBean(name)

并完全避免使用 ServiceAdapter 类。唯一的问题是您需要将这些 bean 放入容器中。

试试这个:

@Component
public class AdapterService{
    @Autowired
    private ApplicationContext applicationContext;

    public A getService(String name){
        return applicationContext.getBean(name,A.class);
    }
}

【讨论】:

    【解决方案2】:

    这里的java SPI, Service Provider Interface,参见here,与尝试使用弹簧锤一样好。

    对于接口x.y.z.A,有一种使用java SPI实现类的发现机制。

    你可以有几个罐子。

    他们有一个文本文件 META-INF/services/x.y.z.A,其中在不以 # 开头的行上实现类。

    由于您可能不想在按名称选择类的对象之前对其进行实例化,因此您可以在类上使用运行时注释,或者将 SPI 放在 工厂 AFactory 具有较小的构造开销,创建了一个 A。

    ServiceLoader<Dictionary> loader = ServiceLoader.load(A.class);
    Iterator<A> dictionaries = loader.iterator();
    

    【讨论】:

    • tnx 为您的回复。 applicationContext.getBean(name) 也可以使用
    • @sajib 谢谢,这确实是最简单的解决方案;然后检查接口 A。但是,如果必须搜索接口 A 的提供者,则 SPI 很有用。 SPI 不需要每个类都有一个 bean,但这是一个非常小的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-18
    • 1970-01-01
    • 2011-02-18
    • 2019-11-04
    • 1970-01-01
    • 1970-01-01
    • 2012-04-12
    相关资源
    最近更新 更多