Spring @Autowire 许多豆

Spring @Autowire many beans

我正在编写一个工厂 class,它根据给定的参数将 return 接口的各种实现:

class Factory {
 public MyType getType(String param) {
  if (param.equals("A")) {
     return new MyTypeA();
   } else if (param.equals("B")) {
     return new MyTypeB();
 } 
}

现在我想利用 Spring 的依赖注入功能,而不是 new。我想使用基于@Annotation 的自动装配。

首先想到的是像这样在字段上使用 @Autowire

class Factory {
@Autowired
private MyTypeA myTypeA;
@Autowired
private MyTypeB myTypeB;
         public MyType getType(String param) {
          if (param.equals("A")) {
             return myTypeA;
           } else if (param.equals("B")) {
             return myTypeB;
         } 
        }

但后来我记得不建议使用字段自动装配,因为很难对这样的 classes 进行单元测试。

接下来我可以尝试使用 setter 级自动装配来进行测试:

class Factory {
private MyTypeA myTypeA;
private MyTypeB myTypeB;
         public MyType getType(String param) {
          if (param.equals("A")) {
             return myTypeA;
           } else if (param.equals("B")) {
             return myTypeB;
         } 

@Autowired
public void setMyTypeA(MyTypeA a) {
 this.myTypeA = a;
}

@Autowired
public void setMyTypeB(MyTypeB b) {
 this.myTypeB = b;
}
}

好的,这看起来更好,但是等等,还有更多 - 我希望我的 class 是不可变的,所以我希望我的私有字段是最终的,并且只在构造函数时填充。所以接下来我可以尝试的是基于构造函数的注入:

class Factory {

private final MyTypeA myTypeA;
private final MyTypeB myTypeB;

public Factory(MyTypeA myTypeA, MyTypeB myTypeB) {
 this.myTypeA = myTypeA;
 this.myTypeB = myTypeB;
}

         public MyType getType(String param) {
          if (param.equals("A")) {
             return myTypeA;
           } else if (param.equals("B")) {
             return myTypeB;
         } 
        }

看起来不错,但问题来了 - 如果我有 20 种不同的类型,我可以根据参数值从这个工厂中 return,我无法创建 20 参数的构造函数。

请提出建议,在这种情况下最好的方法是什么(尽量避免基于 xml 的自动装配)。

谢谢

你可以继续按照这个方法。

    class Factory {
@Autowired
private MyTypeA myTypeA;
@Autowired
private MyTypeB myTypeB;
         public MyType getType(String param) {
          if (param.equals("A")) {
             return myTypeA;
           } else if (param.equals("B")) {
             return myTypeB;
         } 
        }

现在要解决在测试用例中注入模拟的问题,您只需使用@InjectMocks 注释即可。

假设您的所有 MyType 类 已经是 Spring 托管 beans,您可以简单地使用一个列表。

假设

@Configuration
class Config{
   @Bean
   public MyType myTypeA() {
      return new MyTypeA();
   }
   @Bean
   public MyType myTypeB() {
      return new MyTypeB();
   }
}

然后您可以将列表自动连接到 Factory:

@Bean
public Factory factory(List<MyType> myTypes) {
   return new Factory(myTypes);
}

此列表将包含 myTypeAmyTypeB。从那里开始,我可能会在 Factory:

中做这样的事情
public class Factory {

  final Map<String, MyType> myTypes;

  public Factory(List<MyType> types) {
     //build map of types with "param" as the key
  }

  public MyType getType(String param) {
     return myTypes.get(param);
  } 
}