Autowiring – @Qualifier

Spring has another a annotation that we can use when we have multiple beans to inject in a dependency, this annotation is @Qualifier. This annotation gives priority to one bean over others if two o more beans of the same type are found. The beans that are specified with the @Qualifier annotation qualifies to be injected as a dependency.

So, when we need to use it? To be more specific this annotation can be used in scenarios when we have two objects of the same type and autowiring by name cannot be used because the variable name doesn’t match any bean name.

Let’s explain how to use the @Qualifier annotation.

We have a component to create a Latte coffee called LatteCoffee.java, this class has already the @Component annotation, indicating that Spring need to create this bean.

@Component
public class LatteCoffee implements Coffee {
   // class body...
}

If we have a scenario similar to the one described above, then we need to use the @Qualifier annotation to sort the situation, we just add the annotation in to the class, and the annotation will have the argument of the name in which Spring will know the bena that must be injected.

@Component
@Qualifier("Latte")
public class LatteCoffee implements Coffee {
   // class body...
}

Note: If we add the argument in the @Component annotation we don’t need to add the @Qualifier annotation in the bean. Spring will recognize that the bean has the name specified in the @Component annotation. Therefore, you can use any of these methods to provide a name for the beans.

@Component("Latte")
public class LatteCoffee implements Coffee {
   // class body...
}

After providing a name to the bean, we can use the @Qualifier annotation in the class where the bean is injected. In this case in the MakeCoffeeImplementation class.

public class MakeCoffeeImplementation {

    @Autowired
    @Qualifier("Latte")
    Coffee coffee;

    public void prepareCoffe(){
        coffee.prepareCoffee();
        System.out.println("The Coffee is ready");
    }
}

The name of the coffe implementation used with the @Qualifier annotation, “Latte”, must match the name used with the @Qualifier or @Component annotations of the class.

So, when the application run, the LatteCoffe bean qualifies to be autowired in the MakeCoffeImplementation.

But, what about the other possible implementation like MochaCoffe, in this case it will be ignored and it will be not used, but if we want to use it we can add the @Qualifier annotation to the MochaCoffe bean.

@Component
@Qualifier("Mocha")
public class MochaCoffee implements Coffee {

    @Override
    public void prepareCoffee() {
        System.out.println("Making a Mocha...");
    }
}

Note: remember that we can use too the @Component annotation and provide their name instead of @Qualifier to give names to the beans, our MochaCoffee bean should be like this:

@Component("Mocha")
public class MochaCoffee implements Coffee {

    @Override
    public void prepareCoffee() {
        System.out.println("Making a Mocha...");
    }
}

Now if we want to use this MochaCoffe bean, we can change the name in the @Qualifier annotation in the MakeCoffeImplementation class:

public class MakeCoffeeImplementation {

    @Autowired
    @Qualifier("Mocha")
    Coffee coffee;

    public void prepareCoffe(){
        coffee.prepareCoffee();
        System.out.println("The Coffee is ready");
    }
}

As you can see, there are several ways to handle autowiring depending on the scenario we are in. In the case of autowiring using the @Qualifier annotation, we only need to change the name of the bean we want to use.

Remember that you can download the code from CoffeShop, this code in under the package: com.programmingsquirrel.coffeeshop.qualifier.

@Primary vs @Quallifier

For Spring, who has major precedence @Qualifier or @Primary? well @Qualifier has precedence over @Primary, this means that Spring will look for bean name, not for the default value that is indicated by @Primary annotation.

Let’s add the @Primary to MochaCoffee bean:

@Component
@Primary
@Qualifier("Mocha")
public class MochaCoffee implements Coffee {

    @Override
    public void prepareCoffee() {
        System.out.println("Making a Mocha...");
    }
}

Also we have the LatteCoffee bean and the MakeCoffeeImplementation class like this:

@Component("Latte")
public class LatteCoffee implements Coffee {
   // class body...
}
public class MakeCoffeeImplementation {

    @Autowired
    @Qualifier("Latte")
    Coffee coffee;

    public void prepareCoffe(){
        coffee.prepareCoffee();
        System.out.println("The Coffee is ready");
    }
}

So, when we run the application we will have the next output:

....
2023-07-10 14:40:48.118  INFO 2817 --- [           main] c.p.c.qualifier.CoffeeshopApplication    : Started CoffeeshopApplication in 0.748 seconds (JVM running for 1.134)
Making a Latte...
The Coffee is ready

Spring will prioritize the use of @Qualifier annotation over @Primary. As we mentioned before, the @Qualifier annotation specifies which bean should be used, while @Primary is the default setting.

So, when should we use the @Primary annotation? It should be used when there is a clear favourite bean implementation thst is suitable for the majority of situations. Spring will automatically choose the @Primary bean as the primary choice, unless a specific bean is specified using the @Qualifier annotation.

Thanks for reading and happy Learning!!!

Leave a comment