@Qualifier vs @Primary with Examples:

In this article, Let us discuss about @Qualifier and @Primary annotations with examples.

@Primary:

When more than one bean qualifies for the dependency to be autowired, @Primary specifies which bean should be given preference.
Among the eligible beans, there should be exactly one primary bean.

@Qualifier:

When more than one bean meets the requirements for the dependency, we may use a qualifier annotation to explicitly define the bean name and let spring know which dependency should be really called for.

Let us try to understand in a more simpler way with an example,

Project Structure:

Let us create an interface University,

package com.javainfinite.annotation.dao;

public interface University {

    public String display();
}

University.java

Now this university is implemented by couple of services, Alpha University and Beta University,

package com.javainfinite.annotation.service;

import com.javainfinite.annotation.dao.University;
import org.springframework.stereotype.Service;

@Service
public class AlphaUniversity implements University {

    @Override
    public String display() {

        return "This is a message from Alpha University";
    }
}

AlphaUniversity.java

package com.javainfinite.annotation.service;

import com.javainfinite.annotation.dao.University;
import org.springframework.stereotype.Service;

@Service
public class BetaUniversity implements University {

    @Override
    public String display() {

        return "This is a message from Beta University";
    }
}

BetaUniversity.java

Now let us have a controller,

package com.javainfinite.annotation.controller;

import com.javainfinite.annotation.dao.University;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UniversityController {

    @Autowired
    private University AlphaUniversity;

    @GetMapping ("/university")
    public String getUniversity() {

        return AlphaUniversity.display();
    }
}

UniversityController.java

What have we done here?

We have created an interface university and that has been implemented by AlphaUniversity and BetaUniversity.

We have autowired that interface in our UniversityController class.

Now when we call “/univeristy” API which dependency will be actually called? will it be AlphaUniversity or BetaUniversity?

Let us try to run this code and understand the behaviour,

Error

We will get an error like above mentioned to use either Primary or Qualifier annotation.

Springboot is unsure which dependency to use because both AlphaUniversity and BetaUniversity have implemented University.

Now let us use @Primary annotation for resolving this issue,

Now I am going to mark BetaUniversity with @Primary annotation,

package com.javainfinite.annotation.service;

import com.javainfinite.annotation.dao.University;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

@Service
@Primary
public class BetaUniversity implements University {

    @Override
    public String display() {

        return "This is a message from Beta University";
    }
}

BetaUniversity.java

Now we have included @Primary annotation, Now springboot will know which bean should be given preference when we autowire University,

let us try to call the API endpoint,

Spring boot has considered BetaUniversity as a preferred bean when University is Autowired.

Now let us use @Qualifier annotation to differentiate beans,

package com.javainfinite.annotation.service;

import com.javainfinite.annotation.dao.University;
import org.springframework.stereotype.Service;

@Service("Alpha")
public class AlphaUniversity implements University {

    @Override
    public String display() {

        return "This is a message from Alpha University";
    }
}

AlphaUniversity.java

package com.javainfinite.annotation.service;

import com.javainfinite.annotation.dao.University;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

@Service("Beta")
@Primary
public class BetaUniversity implements University {

    @Override
    public String display() {

        return "This is a message from Beta University";
    }
}

BetaUniveristy.java

package com.javainfinite.annotation.controller;

import com.javainfinite.annotation.dao.University;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UniversityController {

    @Autowired
    @Qualifier("Alpha")
    private University AlphaUniversity;

    @GetMapping ("/university")
    public String getUniversity() {

        return AlphaUniversity.display();
    }
}

UniversityController.java

On calling the API end point – “/university”,

Which is of higher priority @Primary or @Qualifier?

@Qualifier has higher priority than @Primary annotation. In the above example we have used both @Primary and @Qualifier together – Qualifier has taken higher priority than @Primary.

Can we declare both @Primary and @Qualifier together?

Yes, Both annotations can be used together but only one can be executed at a time. (Qualifier first, if qualifier not present it will execute primary)

Complete Code:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.7.0</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.javainfinite</groupId>
	<artifactId>annotation</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>annotation</name>
	<description>Qualifier vs Primary</description>
	<properties>
		<java.version>17</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

pom.xml

UniversityController.java

package com.javainfinite.annotation.controller;

import com.javainfinite.annotation.dao.University;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UniversityController {

    @Autowired
    @Qualifier("Alpha")
    private University AlphaUniversity;

    @GetMapping ("/university")
    public String getUniversity() {

        return AlphaUniversity.display();
    }
}

University.java

package com.javainfinite.annotation.dao;

public interface University {

    public String display();
}

AlphaUniversity.java

package com.javainfinite.annotation.service;

import com.javainfinite.annotation.dao.University;
import org.springframework.stereotype.Service;

@Service("Alpha")
public class AlphaUniversity implements University {

    @Override
    public String display() {

        return "This is a message from Alpha University";
    }
}

BetaUniversity.java

package com.javainfinite.annotation.service;

import com.javainfinite.annotation.dao.University;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

@Service("Beta")
@Primary
public class BetaUniversity implements University {

    @Override
    public String display() {

        return "This is a message from Beta University";
    }
}

AnnotationApplication.java

package com.javainfinite.annotation;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AnnotationApplication {

	public static void main(String[] args) {
		SpringApplication.run(AnnotationApplication.class, args);
	}

}

Complete code here

By Sri

Leave a Reply

Your email address will not be published.