Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use Qualifier and Primary in Spring

I have read that @Qualifier can be used in Injection phase whereas @Primary is used in Configuration phase. Am still unclear when to use which.

Also I have below doubts

  • can @Primary and @Qualifier be used together? if yes does @Qualifier take precedence?

  • can @Primary be used with @Autowired?

  • How is the Injection phase different from Configuration phase, this in respect to Spring beans

like image 635
Just Another Developer Avatar asked Jun 18 '19 05:06

Just Another Developer


People also ask

What is the use of @qualifier and @primary?

It's worth noting that if both the @Qualifier and @Primary annotations are present, then the @Qualifier annotation will have precedence. Basically, @Primary defines a default, while @Qualifier is very specific.

Why qualifier is used in Spring?

One of the most important annotations in spring is @Qualifier annotation which is used to eliminate the issue of which bean needs to be injected.

What is qualifier and primary annotations?

@Primary indicates that a bean should be given preference when multiple candidates are qualified to autowire a single-valued dependency. @Qualifier indicates specific bean should be autowired when there are multiple candidates. For example, we have two beans both implement the same interface.

What is the difference between @autowired and qualifier?

So if @Autowired is used together with @Qualifier , it is the same as the @Resource . The difference are that @Autowired and @Qualifier are the spring annotation while @Resource is the standard java annotation (from JSR-250) .


1 Answers

@Primary indicates that a bean should be given preference when multiple candidates are qualified to autowire a single-valued dependency.

@Qualifier indicates specific bean should be autowired when there are multiple candidates.

For example, we have two beans both implement the same interface.

public interface BeanInterface {

    String getName();
}


public class Bean1 implements BeanInterface {
    @Override
    public String getName() {
        return "bean 1";
    }
}


public class Bean2 implements BeanInterface {
    @Override
    public String getName() {
        return "bean2";
    }
}

Here is our service.

@Service
public class BeanService {

    @Autowired
    private BeanInterface bean;
}

And our configuration.

@Configuration
public class Config {

    @Bean("bean1")
    public BeanInterface bean1() {
        return new Bean1();
    }

    @Bean("bean2")
    public BeanInterface bean2() {
        return new Bean2();
    }
}

When Spring starts, it will find there are two beans("bean1" and "bean2") both can be autowired to BeanService since they implement the same interface BeanInterface. It reports an error in my Idea.

Could not autowire. There is more than one bean of 'BeanInterface' type.
Beans: bean1   (Config.java) 
bean2   (Config.java) 

And without a hint, Spring does not know which one to use.

So in our case, when we add @Primary to Config.bean1().

@Bean("bean1")
@Primary
public BeanInterface bean1() {
    return new Bean1();
}

It tells Spring, "when you find more than one beans that both can be autowired, please use the primary one as your first choose." So, Spring will pick bean1 to autowire to BeanService.

Here is another way to autowire bean1 to BeanService by using @Qualifier in BeanService.class.

@Service
public class BeanService {

    @Autowired
    @Qualifier("bean1")
    private BeanInterface bean;
}

@Qualifier will tell Spring, "no matter how many beans you've found, just use the one I tell you."

So you can find both @Qualifier and @Primary are telling Spring to use the specific bean when multiple candidates are qualified to autowire. But @Qualifier is more specific and has high priority. So when both @Qualifier and @Primary are found, @Primary will be ignored.

Here is the test.

@Configuration
public class Config {

    @Bean("bean1")
    @Primary
    public BeanInterface bean1() {
        return new Bean1();
    }

    @Bean("bean2")
    public BeanInterface bean2() {
        return new Bean2();
    }
}

@Service
public class BeanService {

    @Autowired
    @Qualifier("bean2")
    private BeanInterface bean;

    @PostConstruct
    public void test() {
        String name = bean.getName();
        System.out.println(name);
    }
}

The output is "bean2".

like image 65
weaver Avatar answered Oct 17 '22 01:10

weaver