18-01-2022 - Shai Zambrovski
Almost every Java
developer knows the Autowired
keyword (an annotation in Spring
that used to automatically wire (inject) dependencies into a bean without explicitly specifying them in the code).
But what if we have an interface in which two or more beans are implements it?
Lets take the next example:
We have a main class with a Program class that contains an IGenerator instance.
The IGenerator has two implementations KooGenerator
and FooGenerator
:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(DemoApplication.class, args);
Program program = applicationContext.getBean(Program.class);
System.out.println(program.run());
}
@Component
public class Program {
@Autowired
private IGenerator generator;
public String run() {
return generator.sayWhoIAm();
}
}
public interface IGenerator {
String sayWhoIAm();
}
@Component("kooGenerator")
public class KooGenerator implements IGenerator {
@Override
public String sayWhoIAm() {
return "I'm KOO";
}
}
@Component("fooGenerator")
public class FooGenerator implements IGenerator {
@Override
public String sayWhoIAm() {
return "I'm FOO";
}
}
}
Once we run the application we will get an exeption: org.springframework.beans.factory.NoUniqueBeanDefinitionException
, tha’s because Spring doesn’t know which implementation to take.
Let’s take a look of our solutions:
@Component
public class Program {
@Autowired
@Qualifier("kooGenerator")
private IGenerator generator;
public String run() {
return generator.sayWhoIAm();
}
}
By using the name of the implementation in the @Qualifier annotation, we can tell which bean we want to use and to avoid the NoUniqueBeanDefinitionException
.
Spring also allow us to define a primary bean implementation to use, in case of multipe implementation.
Need to remember that @Qualifier
as bigger priority then @Primary,
that’s means that it’s waste to define both of the annotations.
@Primary
means default implementation, while @Qualifier
is the specific implementation.
public interface IGenerator {
String sayWhoIAm();
}
@Component
public class KooGenerator implements IGenerator {
@Override
public String sayWhoIAm() {
return "I'm KOO";
}
}
@Primary
@Component
public class FooGenerator implements IGenerator {
@Override
public String sayWhoIAm() {
return "I'm FOO";
}
}
Another way to resolve the bean implementation is via the name of the bean.
This is the default way.
In this case, the Program
will take the kooGenerator
implementation as this is the bean name next to the @Component
.
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(DemoApplication.class, args);
Program program = applicationContext.getBean(Program.class);
System.out.println(program.run());
}
@Component
public class Program {
@Autowired
private IGenerator kooGenerator;
public String run() {
return kooGenerator.sayWhoIAm();
}
}
public interface IGenerator {
String sayWhoIAm();
}
@Component("kooGenerator")
public class KooGenerator implements IGenerator {
@Override
public String sayWhoIAm() {
return "I'm KOO";
}
}
@Component("fooGenerator")
public class FooGenerator implements IGenerator {
@Override
public String sayWhoIAm() {
return "I'm FOO";
}
}
}