Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring boot autowiring an interface with multiple implementations

In normal Spring, when we want to autowire an interface, we define it's implementation in Spring context file.

  1. What about Spring boot?
  2. 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...

like image 692
user666 Avatar asked Aug 09 '18 11:08

user666


People also ask

Can we Autowired interface in Spring boot?

Dependency Injection has eased developer's life. Earlier, we use to write factory methods to get objects of services and repositories. Now With help of Spring boot and Autowired annotation, we can inject dependency in any classes easily.

Can we use @autowired for interface?

If you try to use @Autowired on an interface, the Spring framework would throw an exception as it won't be able to decide which implementation class to use.

Can we Autowire an interface without the implemented class?

So, you can't autowire an interface without any implementation in Spring.

Why do we Autowire the interface and not the implemented class?

You autowire the interface so you can wire in a different implementation--that's one of the points of coding to the interface, not the class.


2 Answers

Use @Qualifier annotation 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 autowire List of interface
(The same way in Spring / Spring Boot / SpringBootTest)
Example below:

@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

like image 183
tsarenkotxt Avatar answered Sep 24 '22 05:09

tsarenkotxt


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

Eg:

@Autowired MyService firstService;  @Autowired MyService secondService; 
like image 32
Raj Shah Avatar answered Sep 23 '22 05:09

Raj Shah