简体   繁体   English

春豆接线

[英]Spring Bean Wiring

I'm learning the basics of Spring and right now I'm going over Beans/wiring. 我正在学习Spring的基础知识,现在我正在研究Beans /接线。 This question might not make sense, it's just something I'm thinking about after reading/trying out some examples from the book Spring into Action by Craig Walls. 这个问题可能没有意义,这只是我在阅读/尝试Craig Walls的“Spring into Action”一书中的一些例子之后想到的。 Say there is this interface. 说有这个界面。

public interface CompactDisc {
    void play()
}

And I have two classes that implement this interface. 我有两个实现此接口的类。

public class HybridTheory implements CompactDisc { }
public class Meteora implements CompactDisc { }

My configuration class uses component scanning and creates beans from these two classes. 我的配置类使用组件扫描并从这两个类创建bean。 Now if I had a test class that has an instance of Compact disc and is wired using autowired 现在,如果我有一个具有光盘实例的测试类,并使用自动连接进行连线

public class myTest {
    @Autowired
    private CompactDisc cd;
}  

there would be a problem correct? 会有问题吗? My question is, how do you wire it so that it uses one bean over the other? 我的问题是,你如何连接它,以便它使用一个bean而不是另一个? Or is this not a real situation/should I make the property of a specific class, not of the interface? 或者这不是真实情况/我应该创建特定类的属性,而不是接口的属性? I guess I'm just having difficulty wrapping my head around wiring. 我想我只是难以绕着布线缠绕我的脑袋。

Whenever you run into situation that you have more than one implementing same interface there are few approaches you can take. 每当遇到有多个实现相同接口的情况时,您可以采取的方法很少。

1. Use @Qualifier annotation 1.使用@Qualifier注释

If you use classpath scanning, your classes may look like: 如果您使用类路径扫描,您的类可能如下所示:

@Component
public class HybridTheory implements CompactDisc { }

@Component
public class Meteora implements CompactDisc { }

Each Spring bean gets an id assigned by a container and by default its a class name starting with lower letter. 每个Spring bean都获取一个由容器分配的id,默认情况下它是一个以较小字母开头的类名。 In case of these two components that would be: 如果这两个组件将是:

  • hybridTheory
  • meteora

You may also want to pick custom name by passing name parameter to @Component annotation, for example: @Component("myFavLinkinParkAlbum") . 您可能还希望通过将name参数传递给@Component注释来选择自定义名称,例如: @Component("myFavLinkinParkAlbum")

Then whenever you autowire CompactDisc bean you can pass @Qualifier annotation and tell Spring which exactly bean you have in mind. 然后,每当你自动装配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. Mark one of your beans as @Primary 2.将您的一个bean标记为@Primary

If in majority of injection points you inject always the same bean and the other one is used rarely you may consider marking the former with @Primary . 如果在大多数注射点注射总是相同的豆而另一个很少使用,您可以考虑使用@Primary标记前者。

@Component
@Primary
public class HybridTheory implements CompactDisc { }

Whenever Spring finds out that there is more than one bean that matches injection point it will inject the one annotated with @Primary . 每当Spring发现有多个bean匹配注入点时,它将注入一个用@Primary注释的bean Note that if there is more than one bean annotated with @Primary and implementing interface used in injection point the problem remains. 请注意,如果有多个使用@Primary注释的bean并且实现了注入点中使用的接口,问题仍然存在。

3. Use Java configuration 3.使用Java配置

Although @Qualifier and @Primary solve the problem sometimes you may find that to learn which implementation is injected you need to travel a lot through source code. 虽然@Qualifier@Primary有时会解决问题,但您可能会发现要了解注入了哪些实现,您需要通过源代码大量旅行。 Sometimes the cleaner approach is to drop @Component (or other stereotype annotations) from your classes and declare beans using Java configuration: 有时候更干净的方法是从中删除@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());
    }
}

Choose the one that fits your use case the best! 选择最适合您用例的产品!

A simple and elegant approach is to use byType whenever possible. 一种简单而优雅的方法是尽可能使用byType When that is not possible the byName approach can be used. 当那是不可能的,可以使用的绰号方法。

One way of using this is to name the beans manually - then the bean names will not differ after you change the classname. 使用它的一种方法是手动命名bean - 然后在更改类名后bean名称不会有所不同。 Note that naming the beans should only be used if you have multiple implementation of the same type, otherwise naming is not really needed. 请注意,只有在具有相同类型的多个实现时才应使用命名bean,否则不需要命名。 In the example below, the naming is part of the annotation eg @Component("hybridTheory") . 在下面的示例中,命名是注释的一部分,例如@Component("hybridTheory") This means that you can change the classname of HybridTheory to whatever you want and the bean name will still be hybridTheory . 这意味着您可以将HybridTheory的类名HybridTheory为您想要的任何名称,并且bean名称仍然是hybridTheory

When you inject something byName you can use the @Qualifier annotation to specify which named bean you require. 当您通过名称注入某些内容时 ,可以使用@Qualifier批注指定所需的命名bean。 I personally prefer it to @Resource since you can use @Qualifier in constructors (I prefer constructor injection over setter- and field-based injection). 我个人更喜欢@Resource因为你可以在构造函数中使用@Qualifier (我更喜欢构造函数注入而不是基于setter和field的注入)。

You should NOT inject the concrete types - that is what dependency injection is all about. 应该注入的具体类型-这就是依赖注入是怎么一回事。 Someone else (ie Spring) will handle the object creation for you ;) 其他人(即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());
    }
}

The Spring docs describes the various options here . Spring的文档描述了各种选项在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM