Learnitweb

Spring @Qualifier annotation

1. Introduction

In this tutorial, we’ll discuss what is the use of @Qualifier annotation and which problem it solves. In this tutorial we’ll also discuss how @Qualifier is different from @Primary annotation.

2. What problem does @Qualifier solve?

While autowiring beans, Spring by default searches by types and does the bean injection. However, Spring may find it difficult when two or more beans qualifyfor injection as they are of the same type. When two or more beans qualify the search, Spring may not decide which bean should it inject. Let us see this with an example. In this example, we are trying to autowire a Printable service in a Controller. Two services FilePrinter and ScreenPrinter are eligible for autowiring as both are Printable.

@RestController
public class HelloController {

	@Autowired
	Printable printer;

	@GetMapping("/print")
	public void print() {
		printer.print();
	}
}
// imports omitted for brevity

@Service("filePrinter")
public class FilePrinter implements Printable {

	@Override
	public void print() {
		System.out.println("file printer");
	}
}
// imports omitted for brevity

@Service("screenPrinter")
public class ScreenPrinter implements Printable {

	@Override
	public void print() {
		System.out.println("Screen Printer");
	}
}

When you start the application you’ll get the error similar to this:

***************************
APPLICATION FAILED TO START
***************************

Description:

Field printer in com.learnitweb.demo.controller.HelloController required a single bean, but 2 were found:
	- filePrinter: defined in file [D:\sts-workspace\demo\target\classes\com\learnitweb\demo\ServiceImpl\FilePrinter.class]
	- screenPrinter: defined in file [D:\sts-workspace\demo\target\classes\com\learnitweb\demo\ServiceImpl\ScreenPrinter.class]


Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed

As you can see in the error, to solve this issue there are two options, using @Primary and @Qualifier.

3. @Qualifier annotation

By using the @Qualifier annotation, we can specify which bean needs to be injected. Lets work on our previous example to make it work using @Qualifier.

@RestController
public class HelloController {

	@Autowired
	@Qualifier("filePrinter")
	Printable printer;

	@GetMapping("/print")
	public void print() {
		printer.print();
	}
}

Notice the use of @Qualifier("filePrinter"). Using @Qualifier, we are specifying that we want a FilePrinter to be used. This will help Spring to avoid the ambiguity. Note that the name provided in @Qualifier annotation is name provided while implementing Printable like @Service("filePrinter").

@Qualifier may also be used to annotate other annotations that can then in turn be used as qualifiers. So @Qualifier can be applied to the implementor of Printable to achieve the same result.

@Service
@Qualifier("filePrinter")
public class FilePrinter implements Printable {

	@Override
	public void print() {
		System.out.println("file printer");
	}
}
@Service
@Qualifier("screenPrinter")
public class ScreenPrinter implements Printable {

	@Override
	public void print() {
		System.out.println("Screen Printer");
	}
}

4. @Primary annotation

Using @Primary annotation is another way of solving ambiguity when more that one beans are eligible for autowiring.

@Primary annotation indicates that a bean should be given preference when multiple candidates are qualified to autowire a single-valued dependency. If there is exactly one bean annotated with @Primary, this bean is used for autowiring. In our example, there are two Printable, FilePrinter and ScreenPrinter. Since more than one bean is eligible to be autowired, you can annotate one with @Primary to tell spring that this bean should be given preference in case of ambiguity.

@Service
@Primary
public class ScreenPrinter implements Printable {

	@Override
	public void print() {
		System.out.println("Screen Printer");
	}
}

In this example, ScreenPrinter will be used in case of ambiguity.

If both the @Qualifier and @Primary annotations are present, then the @Qualifier annotation will have precedence.