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);
}
此列表将包含 myTypeA
和 myTypeB
。从那里开始,我可能会在 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);
}
}
我正在编写一个工厂 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);
}
此列表将包含 myTypeA
和 myTypeB
。从那里开始,我可能会在 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);
}
}