Spring Boot 自动装配具有多个实现的接口

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/51766013/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 01:38:04  来源:igfitidea点击:

Spring boot autowiring an interface with multiple implementations

springspring-bootjunitautowired

提问by user666

In normal Spring, when we want to autowire an interface, we define it's implementation in Spring context file. What about Spring boot? how can we achieve this? currently we only autowire classes that are not interfaces. Another part of this question is about using a class in a Junit class inside a Spring boot project. If we want to use a CalendarUtil for example, if we autowire CalendarUtil, it will throw a null pointer exception. What can we do in this case? I just initialized using "new" for now...

在普通的 Spring 中,当我们想要自动装配一个接口时,我们在 Spring 上下文文件中定义它的实现。弹簧靴呢?我们怎样才能做到这一点?目前我们只自动装配不是接口的类。这个问题的另一部分是关于在 Spring boot 项目中的 Junit 类中使用一个类。例如,如果我们想使用 CalendarUtil,如果我们自动装配 CalendarUtil,它将抛出空指针异常。在这种情况下我们能做什么?我现在刚刚使用“new”初始化......

回答by tsarenkotxt

Use @Qualifierannotation is used to differentiate beans of the same interface
Take look at Spring Boot documentation
Also, to inject all beans of the same interface, just autowireListof interface
(The same way in Spring / Spring Boot / SpringBootTest)
Example below:

使用@Qualifier注解来区分同一个接口的bean
看Spring Boot的文档
另外,要注入同一个接口的所有bean,只需要autowireList接口即可
(Spring / Spring Boot / SpringBootTest中的方法相同)
示例如下:

@SpringBootApplication
public class DemoApplication {

public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
}

public interface MyService {

    void doWork();

}

@Service
@Qualifier("firstService")
public static class FirstServiceImpl implements MyService {

    @Override
    public void doWork() {
        System.out.println("firstService work");
    }

}

@Service
@Qualifier("secondService")
public static class SecondServiceImpl implements MyService {

    @Override
    public void doWork() {
        System.out.println("secondService work");
    }

}

@Component
public static class FirstManager {

    private final MyService myService;

    @Autowired // inject FirstServiceImpl
    public FirstManager(@Qualifier("firstService") MyService myService) {
        this.myService = myService;
    }

    @PostConstruct
    public void startWork() {
        System.out.println("firstManager start work");
        myService.doWork();
    }

}

@Component
public static class SecondManager {

    private final List<MyService> myServices;

    @Autowired // inject MyService all implementations
    public SecondManager(List<MyService> myServices) {
        this.myServices = myServices;
    }

    @PostConstruct
    public void startWork() {
        System.out.println("secondManager start work");
        myServices.forEach(MyService::doWork);
    }

}

}

For the second part of your question, take look at this useful answers first/ second

对于您问题的第二部分,请先/ 第二次查看此有用的答案

回答by Raj Shah

You can also make it work by giving it the name of the implementation.

您还可以通过为其指定实现名称来使其工作。

Eg:

例如:

@Autowired
MyService firstService;

@Autowired
MyService secondService;

回答by Urosh T.

As mentioned in the comments, by using the @Qualifierannotation, you can distinguish different implementations as described in the docs.

正如评论中提到的,通过使用@Qualifier注释,您可以区分文档中描述的不同实现。

For testing, you can use also do the same. For example:

对于测试,您也可以使用同样的方法。例如:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class MyClassTests {

        @Autowired
        private MyClass testClass;
        @MockBean
        @Qualifier("default")
        private MyImplementation defaultImpl;

        @Test
        public void givenMultipleImpl_whenAutowiring_thenReturnDefaultImpl() {
    // your test here....
    }
}