Autowiring is one of the most significant features of spring framework. It is the process through which spring identifies and injects dependencies automatically. Suppose, we are making a candy in a candy factory. An important property for the candy is its flavour. So, if we are representing creating candy in Java then the implementation would be:
public interface Flavour {
public String getFlavour();
}
@Component
public class ChocolateFlavour implements Flavour {
@Override
public String getFlavour() {
return "chocolate";
}
}
@Component
public class Candy {
@Autowired
private Flavour flavour;
public void createCandy() {
System.out.println("Created " + flavour.getFlavour() + " flavoured candy");
}
}
@SpringBootApplication
public class CandyfactoryApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(CandyfactoryApplication.class, args);
Candy chocolateCandy = applicationContext.getBean(Candy.class);
chocolateCandy.createCandy();
}
}
In the above implementation, autowiring works fine. When the application is running Spring tries to inject dependency of type Flavour
, so it searches the entire package and finds ChocolateFlavour
. As only one class is found, Spring is sure we need to inject it.
But problem will arise when we introduce another class of Flavour
type(i.e. a class that implements Flavour
interface). Let's consider the class to be the following:
@Component
public class MangoFlavour implements Flavour {
@Override
public String getFlavour() {
return "mango";
}
}
If we try to run the application now, it will throw the following error:
Field flavour in com.candy.candyfactory.Candy required a single bean, but 2 were found
Why is this error thrown?
The above problem is occuring because with the introduction of the MangoFlavour
class, spring has 2 components of same type and its unable to decide which to inject. To resolve such conflicts, spring provides 3 ways, they are:
1. @Primary
Annotation
It is clearly what the annotation suggests i.e. giving more importance to a component than the others. Defining a component as primary will allow spring to prioritise it and inject that component, so if we define the MangoFlavour
as @Primary
flavour and change the code as below:
@Component
@Primary
public class MangoFlavour implements Flavour {
@Override
public String getFlavour() {
return "mango";
}
}
then our application runs fine and gives the following output: Created mango flavoured candy
and if we had made ChocolateFlavour
as @Primary
then output would be: Created chocolate flavoured candy
.
2. Autowiring by name
This is a very widely used method of autowiring where you name the autowiring variable the same name as the class name but with the first letter small. So, if we want to use MangoFlavour
class for autowiring then the variable name should be mangoFlavour
and the code for the class Candy
would be:
@Component
public class Candy {
@Autowired
private Flavour mangoFlavour;
public void createCandy() {
System.out.println("Created " + mangoFlavour.getFlavour() + " flavoured candy");
}
}
Since the variable name now matches the class MangoFlavour
, spring is able to understand that an instance of the MangoFlavour
class should be injected as the dependency.
3. Using @Qualifier("value")
@Component
@Qualifier("chocolate")
public class ChocolateFlavour implements Flavour {
@Override
public String getFlavour() {
return "chocolate";
}
}
@Component
@Qualifier("mango")
public class MangoFlavour implements Flavour {
@Override
public String getFlavour() {
return "mango";
}
}
@Component
public class Candy {
@Autowired
@Qualifier("mango")
private Flavour flavour;
public void createCandy() {
System.out.println("Created " + flavour.getFlavour() + " flavoured candy");
}
}
@Qualifier
is simplest among all. You assign a qualifier value to each component and assign which qualifier to use in autowiring and spring will match the values and inject the dependency.
Among the 3 types of autowiring, their priority order is
@Qualifier() > @Primary > Autowiring by name
Top comments (0)