春豆接线

时间:2014-12-27 03:04:47

标签: java spring dependency-injection javabeans

我正在学习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而不是另一个?或者这不是真实情况/我应该创建特定类的属性,而不是接口的属性?我想我只是难以绕着布线缠绕。

2 个答案:

答案 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