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

use*_*666 8 junit spring autowired spring-boot

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

tsa*_*txt 19

使用@Qualifier批注来区分同一接口的bean
请查看Spring Boot 文档。
此外,要注入同一接口的所有bean,只需自动装配 List接口即可
(在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);
    }

}

}
Run Code Online (Sandbox Code Playgroud)

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


小智 14

假设您有一个GreetingService

public interface GreetingService {
    void doGreetings();
}
Run Code Online (Sandbox Code Playgroud)

你有 2 个实现HelloService

@Service
@Slf4j
public class HelloService implements GreetingService{
    @Override
    public void doGreetings() {
        log.info("Hello world!");       
    }
}
Run Code Online (Sandbox Code Playgroud)

HiService

@Slf4j
@Service
public class HiService implements GreetingService{
    @Override
    public void doGreetings() {
        log.info("Hi world!");
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你还有一个接口,就是BusinessService调用一些业务

public interface BusinessService {
    void doGreetings();
}
Run Code Online (Sandbox Code Playgroud)

有一些方法可以做到这一点

#1. 使用@Autowired

@Component
public class BusinessServiceImpl implements BusinessService{
    
    @Autowired
    private GreetingService hiService; // Spring automatically maps the name for you, if you don't want to change it.
    
    @Autowired
    private GreetingService helloService;
    

    @Override
    public void doGreetings() {
        hiService.doGreetings();
        helloService.doGreetings();
    }

}
Run Code Online (Sandbox Code Playgroud)

如果您需要更改实现 bean 名称,请参考其他答案,例如将名称设置为您的 bean@Service("myCustomName")并应用@Qualifier("myCustomName")

#2. 您还可以使用构造函数注入

@Component
public class BusinessServiceImpl implements BusinessService {

    private final GreetingService hiService;

    private final GreetingService helloService;

    public BusinessServiceImpl(GreetingService hiService, GreetingService helloService) {
        this.hiService = hiService;
        this.helloService = helloService;
    }

    @Override
    public void doGreetings() {
        hiService.doGreetings();
        helloService.doGreetings();
    }

}
Run Code Online (Sandbox Code Playgroud)

这可以是

public BusinessServiceImpl(@Qualifier("hiService") GreetingService hiService, @Qualifier("helloService") GreetingService helloService)
Run Code Online (Sandbox Code Playgroud)

但我正在使用 Spring Boot2.6.5并且

public BusinessServiceImpl(GreetingService hiService, GreetingService helloService)
Run Code Online (Sandbox Code Playgroud)

工作正常,因为 Spring 自动为我们获取名称。

#3 . 您也可以用于Map此目的

@Component
@RequiredArgsConstructor
public class BusinessServiceImpl implements BusinessService {

    private final Map<String, GreetingService> servicesMap; // Spring automatically get the bean name as key

    @Override
    public void doGreetings() {
        servicesMap.get("hiService").doGreetings();
        servicesMap.get("helloService").doGreetings();
    }

}
Run Code Online (Sandbox Code Playgroud)

List如果您运行所有服务也可以正常工作。但有一种情况,你想要得到一些特定的实现,你需要为它定义一个名称或类似的东西。我的参考资料在这里

对于这个,我使用@RequiredArgsConstructor来自 Lombok 的。


Raj*_*hah 9

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

例如:

@Autowired
MyService firstService;

@Autowired
MyService secondService;
Run Code Online (Sandbox Code Playgroud)

  • 这很好,但这真的是依赖注入吗?因为我们将变量与服务名称本身耦合。 (5认同)
  • 这个很重要! (4认同)

nen*_*ito 5

当我们自动装配具有多个实现的接口时,有两种方法:

\n
    \n
  1. Spring @Primary 注解
  2. \n
\n

简而言之,每当我们尝试自动装配我们的接口以使用标有@Primary注释的特定实现时,它都会告诉我们的 Spring 应用程序。它就像默认的自动装配设置。每个接口实现集群只能使用一次。\xe2\x86\x92 @Primary 文档

\n
    \n
  1. Spring @Qualifier 注解
  2. \n
\n

无论何时定义对接口的引用,在其选项中进行选择,这个 Spring 注释都为我们提供了更多的控制权来选择准确的实现。\xe2\x86\x92 @Qualifier 文档

\n

有关更多详细信息,请点击其文档的链接。

\n


归档时间:

查看次数:

13251 次

最近记录:

6 年,6 月 前