我正在学习Spring的基础知识,现在我正在学习Beans / wiring。这个问题可能没有意义,它只是我在阅读/尝试Craig Walls的“Spring into Action”一书中的一些例子之后想到的。说有这个界面。
public interface CompactDisc {
void play()
}
我有两个实现此接口的类。
public class HybridTheory implements CompactDisc { }
public class Meteora implements CompactDisc { }
我的配置类使用组件扫描并从这两个类创建bean。现在,如果我有一个具有光盘实例并使用自动装配
连接的测试类public class myTest {
@Autowired
private CompactDisc cd;
}
会出现问题吗?我的问题是,你如何连接它,以便它使用一个bean而不是另一个?或者这不是真实情况/我应该创建特定类的属性,而不是接口的属性?我想我只是难以绕着布线缠绕。
答案 0 :(得分:4)
每当遇到有多个实现相同界面的情况时,您可以采取的方法很少。
<强> 1。使用@Qualifier注释
如果您使用类路径扫描,您的类可能如下所示:
@Component
public class HybridTheory implements CompactDisc { }
@Component
public class Meteora implements CompactDisc { }
每个Spring bean都获取一个容器分配的id,默认情况下它是一个以小写字母开头的类名。如果这两个组成部分是:
hybridTheory
meteora
您可能还希望通过将name
参数传递给@Component注释来选择自定义名称,例如:@Component("myFavLinkinParkAlbum")
。
然后,当你自动装配CompactDisc
bean时,你可以传递@Qualifier注释并告诉Spring你想到的是哪个bean。
@Service
class Player {
private final CompactDisc compactDisc;
// note that starting from Spring 4.3
// you can omit @Autowired annotation from constructor
Player(@Qualifier("hybridTheory") CompactDisc compactDisc) {
this.compactDisc = compactDisc;
}
}
<强> 2。将您的一个bean标记为@Primary
如果在大多数注射点注射总是相同的豆而另一个很少使用,您可以考虑使用@Primary标记前者。
@Component
@Primary
public class HybridTheory implements CompactDisc { }
每当Spring发现有多个bean匹配注入点时,它将注入一个注释为@Primary的bean。请注意,如果有多个bean使用@Primary注释并且实现了注入点中使用的接口,问题仍然存在。
第3。使用Java configuration
虽然@Qualifier和@Primary解决了这个问题,但有时您可能会发现要了解注入了哪个实现,您需要通过源代码大量旅行。有时,更简洁的方法是从类中删除@Component(或其他构造型注释)并使用Java配置声明bean:
public class HybridTheory implements CompactDisc { }
public class Meteora implements CompactDisc { }
@Configuration
class RecordsConfiguration {
@Bean
CompactDisc hybridTheory() {
return new HybridTheory();
}
@Bean
CompactDisc meteora() {
return new Meteora();
}
@Bean
Player player() {
return new Player(meteora());
}
}
选择最适合您用例的那个!
答案 1 :(得分:3)
一种简单而优雅的方法是尽可能使用 byType 。当不可能时,可以使用 byName 方法。
使用它的一种方法是手动命名bean - 然后在更改类名后bean名称不会有所不同。请注意,只有在具有相同类型的多个实现时才应使用命名bean,否则不需要命名。在下面的示例中,命名是注释的一部分,例如@Component("hybridTheory")
。这意味着您可以将HybridTheory
的类名更改为您想要的任何名称,并且bean名称仍为hybridTheory
。
当您注入 byName 时,可以使用@Qualifier
注释指定所需的命名bean。我个人更喜欢它@Resource
,因为你可以在构造函数中使用@Qualifier
(我更喜欢构造函数注入而不是基于setter和field的注入)。
你应该 NOT 注入具体的类型 - 这就是依赖注入的全部内容。其他人(即Spring)将为您处理对象创建;)
public interface CompactDisc {
void play();
}
@Component
class CompactDiscPlayer {
@Autowired
CompactDiscPlayer(@Qualifier("hybridTheory") final CompactDisc compactDisc) {
// The bean of type HybridTheory will be used
compactDisc.play();
}
}
@Component("hybridTheory")
class HybridTheory implements CompactDisc {
public void play() {
System.out.println(getClass().getSimpleName());
}
}
@Component("meteora")
class Meteora implements CompactDisc {
public void play() {
System.out.println(getClass().getSimpleName());
}
}
Spring文档描述了各种选项here。