Spring @Autowired and @Qualifier

Difference between @Qualifier and @Resource

@Autowired can be used alone . If it is used alone , it will be wired by type . So problems arises if more than one bean of the same type are declared in the container as @Autowired does not know which beans to use to inject. As a result , use @Qualifier together with @Autowired to clarify which beans to be actually wired by specifying the bean name (wired by name)

@Resource is wired by name too . 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) . Besides , @Resource only supports for fields and setter injection while @Autowired supports fields , setter ,constructors and multi-argument methods injection.

It is suggested to use @Resource for fields and setter injection. Stick with @Qualifier and @Autowired for constructor or a multi-argument method injection.

See this:

If you intend to express annotation-driven injection by name, do not
primarily use @Autowired - even if is technically capable of referring
to a bean name through @Qualifier values. Instead, prefer the JSR-250
@Resource annotation which is semantically defined to identify a
specific target component by its unique name, with the declared type
being irrelevant for the matching process.

When to use Qualifier and Primary in Spring

@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".

Spring @Autowire and @Qualifier annotation strange behaviour

Well you marked your class with @Component

@Component("myPingPongCoach")
public class PingPongCoach implements Coach

Hence during the component scan, spring founds it and initializes it.

You provide a constructor with one parameter to suppress the default constructor, so Spring will pick it.

Difference between @Primary vs @Autowired with @Qualifier annotations

Read @Primary as the "default".

If a bean has @Autowired without any @Qualifier, and multiple beans of the type exist, the candidate bean marked @Primary will be chosen, i.e. it is the default selection when no other information is available, i.e. when @Qualifier is missing.

A good use case is that initially you only had one bean of the type, so none of the code used @Qualifier. When you then add another bean, you then also add @Qualifier to both the old and the new bean, so any @Autowired can choose which one it wants. By also adding @Primary to the old original bean, you don't have to add @Qualifier to all the existing @Autowired. They are "grandfathered" in, so to speak.

@Primary is also good if e.g. 95% of @Autowired wants a particular bean. That way, only the @Autowired that wants the other bean(s) need to specify @Qualifier. That way, you have primary beans that all autowired wants, and @Qualifier is only used to request an "alternate" bean.



Related Topics



Leave a reply



Submit