首页 > 解决方案 > 策略模式@Service 重复组件名的两种用法

问题描述

在 Spring Boot 的帮助下实现了一个非常简单的策略模式:

我有一个界面:

public interface IOneStrategy {
  void executeTheThing();
}

我有一个这样的策略 One 的实现:

@Service("FIRST")
public class OneStrategyFirst implements IOneStrategy {

  @Override
  public void executeTheThing() {
    System.out.println("OneStrategyFirst.executeTheThing");
  }
}

我有一个使用注入实现的类:

@Service
public class ExecuteStrategyOne {
  private Map<String, IOneStrategy> strategies;

  public void executeStrategyOne(String name) {
    if (!strategies.containsKey(name)) {
      throw new IllegalArgumentException("The key " + name + " does not exist.");
    }
    strategies.get(name).executeTheThing();
  }

   
}

并且这些实现将由 Spring boot 通过使用 name FIRST、 'SECOND' 等自动注入(假设这只是一个 String 等。效果很好。)。

但现在我想通过第二个接口实现另一种策略:

public interface ITwoStrategy {
  void executeTheThing();
}

以及策略的执行服务:

@Service
public class ExecuteStrategyTwo {
  private Map<String, ITwoStrategy> strategies;
  ...
   
}

现在是有问题的部分,因为我的应用程序使用相同的名称,应该将其作为上述地图的键的一部分,我想使用以下内容:

@Service("FIRST")
public class TwoStrategyFirst implements ITwoStrategy {

  @Override
  public void executeTheThing() {
    System.out.println("TwoStrategyFirst.executeTheThing");
  }
}

这当然会导致基于重复的 bean 名称的异常。确实需要名称FIRST来区分实现。

我已经找到了@Qualifier可以用来代替的东西@Service(FIRST)

@Service
@Qualifier(FIRST)
public class TwoStrategyFirst implements ITwoStrategy {

  @Override
  public void executeTheThing() {
    System.out.println("TwoStrategyFirst.executeTheThing");
  }
}

不幸的是,它并没有通过使用限定符的名称将类注入到映射中,这不是我打算做的。

是否存在与在策略执行中获取地图键相同的解决方案@Service("FIRST")

标签: javaspring-bootspring-framework-beans

解决方案


我可以通过使用 Qualifier 注释来使用解决方案,如下所示:

@Service
@Qualifier(FIRST)
public class TwoStrategyFirst implements ITwoStrategy {
...
}

基于此,通过一些代码或多或少有一个简单的解决方案:

@Service
public class ExecuteStrategyTwo {


  private Map<String, ITwoStrategy> strategies;

  public ExecuteStrategyOne(List<ITwoStrategy> strategies) {
    this.strategies = strategies.stream()
        .collect(
            Collectors.toMap(k -> k.getClass().getDeclaredAnnotation(Qualifier.class).value(), Function.identity()));
  }

这会将所有实现注入到构造函数列表中,并将通过使用限定符注释转换为映射。


推荐阅读