在spring 中使用注解,常使用@Autowired, 默认是根据类型Type来自动注入的。但有些特殊情况,对同一个接口,可能会有几种不同的实现类,而默认只会采取其中一种的情况下 @Primary 的作用就出来了。
Primary可以理解为默认优先选择,不可以同时设置多个,内部实质是设置BeanDefinition的primary属性
注解 | 备注 |
---|---|
@Primary |
优先方案,被注解的实现,优先被注入 |
@Qualifier |
先声明后使用,相当于多个实现起多个不同的名字,注入时候告诉我你要注入哪个 |
首先看下源码:
org.springframework.context.annotation
Annotation Type Primary
@Target(value={TYPE,METHOD})
@Retention(value=RUNTIME)
@Inherited
@Documented
public @interface Primary
Indicates that a bean should be given preference when multiple candidates are qualified to autowire a single-valued dependency. If exactly one 'primary' bean exists among the candidates, it will be the autowired value.
This annotation is semantically equivalent to the element's primary attribute in Spring XML.
May be used on any class directly or indirectly annotated with @Component or on methods annotated with @Bean.
Example
@Component
public class FooService {
private FooRepository fooRepository;
@Autowired
public FooService(FooRepository fooRepository) {
this.fooRepository = fooRepository;
}
}
@Component
public class JdbcFooRepository {
public JdbcFooService(DataSource dataSource) {
// ...
}
}
@Primary
@Component
public class HibernateFooRepository {
public HibernateFooService(SessionFactory sessionFactory) {
// ...
}
}
Because HibernateFooRepository is marked with @Primary, it will be injected preferentially over the jdbc-based variant assuming both are present as beans within the same Spring application context, which is often the case when component-scanning is applied liberally.
Note that using @Primary at the class level has no effect unless component-scanning is being used. If a @Primary-annotated class is declared via XML, @Primary annotation metadata is ignored, and is respected instead.
Since:
3.0
Author:
Chris Beams
See Also:
Lazy, Bean, ComponentScan, Component
使用实例
一:@Qualifier
接口:
public interface EmployeeService {
public EmployeeDto getEmployeeById(Long id);
}
接口对应的两个实现类:EmployeeServiceImpl和EmployeeServiceImpl1:接口对应的两个实现类:EmployeeServiceImpl和EmployeeServiceImpl1:
@Service("employeeService")
public class EmployeeServiceImpl implements EmployeeService {
public EmployeeDto getEmployeeById(Long id) {
return new EmployeeDto();
}
}
@Service("employeeService1")
public class EmployeeServiceImpl1 implements EmployeeService {
public EmployeeDto getEmployeeById(Long id) {
return new EmployeeDto();
}
}
这个时候就要用到@Qualifier注解了,qualifier的意思是合格者,通过这个标示,表明了哪个实现类才是我们所需要的,我们修改调用代码,添加@Qualifier注解,需要注意的是@Qualifier的参数名称必须为我们之前定义@Service注解的名称之一!
@Controller
@RequestMapping("/emplayee.do")
public class EmployeeInfoControl {
@Autowired
@Qualifier("employeeService")
EmployeeService employeeService;
@RequestMapping(params = "method=showEmplayeeInfo")
public void showEmplayeeInfo(HttpServletRequest request, HttpServletResponse response, EmployeeDto dto) {
//#略
}
}
二、@Primary:和@Qualifier 一样,@Primary也一样,使用场景经常是:在spring 中使用注解,常使用@Autowired, 默认是根据类型Type来自动注入的。但有些特殊情况,对同一个接口,可能会有几种不同的实现类,而默认只会采取其中一种的情况下 @Primary 的作用就出来了。
简单例子:
接口:
public interface Singer {
String sing(String lyrics);
}
有下面的两个实现类:
@Component // 加注解,让spring识别
public class MetalSinger implements Singer{
@Override
public String sing(String lyrics) {
return "I am singing with DIO voice: "+lyrics;
}
}
@Primary
@Component
public class OperaSinger implements Singer{
@Override
public String sing(String lyrics) {
return "I am singing in Bocelli voice: "+lyrics;
}
}
故:
在spring容器中,如果同一个类型有多个实例,但我们需要注入一个的时候,我们必须采取措施,不然spring容器会报错:....required a single bean, but 2 were found:.........
有时候我们能保证同一个类型在spring容器中只有一个实例,有时候我们保证不了,此时不讨论by name注入。这个时候要使用@Primary注解。
如有不足望不吝赐教!!!