Spring注入的方式有很多,下面介绍一下常用的几个用于注入的注解
@Autowired
首先来看一下@Autowired注解的定义:
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
/**
* Declares whether the annotated dependency is required.
* <p>Defaults to {@code true}.
*/
boolean required() default true;
}
从源码可以看出,@Autowired注解可以用在以下几个地方
- 构造方法
- 普通方法
- 方法参数
- 字段
- 其他注解
@Autowired注解只有一个required属性,默认为true,说明默认情况下是要求一定要有对象注入才行,要不然会报空指针异常。如果允许为null,可以设置required为false。
下面我们来通过一个例子看一下@Autowired在不同地方的注入:
public class Cat {
public String show(){
return "Cat";
}
}
public class Dog {
public String show(){
return "Dog";
}
}
public class Cattle {
public String show(){
return "Cattle";
}
}
@Configuration
public class ServiceConfig {
@Autowired
private Dog dog;
private Cat cat;
private Cattle cattle;
@Autowired
public ServiceConfig(Cattle cattle){
this.cattle = cattle;
}
@Autowired
public void setCat(Cat cat){
this.cat = cat;
}
public String getDesc(){
return dog.show() + "|" + cat.show() + "|" + cattle.show();
}
}
public class ServiceDemoMain {
public static void main(String[] args){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(Config.class, ServiceConfig.class);
context.refresh();
ServiceConfig config = context.getBean(ServiceConfig.class);
System.out.println(config.getDesc());
}
}
@Autowired注解默认是通过类型来注入的,假如同一个类型的对象存在多个,就会出现对象的歧义,Spring不知道该注入哪个对象了,如下:
@Service
public class UserServiceImpl implements UserService {
}
@Service
public class UserServiceImpl2 implements UserService {
}
public class Test{
@Autowired
private UserService userService;
}
如何解决多个对象的歧义性呢?
1.通过名称注入,配置Qualifier注解通过名称来注入,通过给不同的对象设置不同的名称来实现注入
@Service("UserServiceImpl")
public class UserServiceImpl implements UserService {
}
@Service("UserServiceImpl2")
public class UserServiceImpl2 implements UserService {
}
public class Test{
@Autowired
@Qualifier("UserServiceImpl")
private UserService userService;
}
2.使用@Primary注解来标识,假如有同一个类型的多个对象存在,会优先注入@Primary标记的对象。注意:同一个类型的对象,只能有一个用@Primary来标记,如果多个对象都标识了@Primary,还是会存在歧义的问题
@Service
public class UserServiceImpl implements UserService {
}
@Service
@Primary
public class UserServiceImpl2 implements UserService {
}
public class Test{
@Autowired
private UserService userService;
}
@Resource
- @Resource默认是通过name来注入的,有两个重要属性可以指定:name和type
- 默认情况下,既不指定name,也不指定type,会默认按照name来查找匹配的对象,当有唯一的对象则进行注入;若没有,则尝试用type来进行匹配,匹配到唯一对象,则进行注入
- 指定name属性,则用name来进行查询,没有则直接抛异常
- 指定type属性,则用type来进行匹配,没有则直接抛异常
@Configuration
public class Config {
@Bean(name="userServiceImpl")
public UserService getUserServiceImpl(){
return new UserServiceImpl();
}
@Bean(name="userServiceImpl2")
public UserService getUserServiceImpl2(){
return new UserServiceImpl2();
}
}
/**
* 默认通过名称来注入
**/
@Resource
private UserService userServiceImpl;
@Resource
private UserService userServiceImpl2;
当名称没有匹配时,则用类型来进行匹配
@Configuration
public class Config {
@Bean(name="userServiceImpl")
public UserService getUserServiceImpl(){
return new UserServiceImpl();
}
}
/**
* userServiceImpl2通过名称没有匹配上时,则用类型进行匹配,两个对象都注入userServiceImpl
**/
@Resource
private UserService userServiceImpl;
@Resource
private UserService userServiceImpl2;
@Inject
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Inject {
}
从源码可以看出@Inject可以用在普通方法、构造方法、字段上,@Inject没有required属性,对象为空会抛异常
- @Inject是JSR330 (Dependency Injection for Java)中的规范,需要导入javax.inject.Inject
- @Inject与@Autowired一样,默认是按照类型来实现注入的,类型注入没有找到则用名称去匹配,只是@Autowired是Spring提供的,@Inject是J2EE提供的
- @Inject通过类型匹配到多个对象时,跟@Autowired一样会产生歧义,不知道该注入哪一个对象,当出现歧义时配合@Named注解按名称来进行注入
@Inject
@Named("userServiceImpl")
private UserService userService;
@Bean(name="userServiceImpl")
public UserService getUserServiceImpl(){
return new UserServiceImpl();
}
@Bean(name="userServiceImpl2")
public UserService getUserServiceImpl2(){
return new UserServiceImpl2();
}
@Inject通过类型注入没有找到唯一的对象后,还会通过名称匹配,匹配上也是可以成功注入的
/**
* 测试发现,这样也可以注入成功,说明@Inject不光通过类型来注入,也会通过属性名userServiceImpl2来进行注入
**/
@Inject
private UserService userServiceImpl2;
@Bean(name="userServiceImpl")
public UserService getUserServiceImpl(){
return new UserServiceImpl();
}
@Bean(name="userServiceImpl2")
public UserService getUserServiceImpl2(){
return new UserServiceImpl2();
}
@Autowired、@Resource、@Inject三者间的区别
1、@Autowired默认是按照类型装配注入的,类型没有注入成功,会用对象名称来进行注入,默认情况下它要求依赖对象必须存在如果允许为null,可以设置它required属性为false,如果想按照自定义名称来进行注入,则需要结合@Qualifier一起使用;@Inject与@Autowired一样,只是@Inject没有required属性,@Inject想按照自定义名称来进行注入需结合@Named注解使用,当然结合@Qualifier也可以
2、@Resource默认按照名称装配,当找不到与名称匹配的bean才会按照类型装配,可以通过name属性指定,如果没有指定name属 性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找 依赖对象.注意:如果没有指定name属性,并且按照默认的名称仍然找不到依赖的对象时候,会按照类型装配,但一旦指定了name属性,就只能按照名称装配了.
3、@Resource、@Inject注解是由J2EE提供,@Resource是JSR-250提供的注解,@Inject是JSR-330提供的注解,而@Autowired是由spring提供;
4、@Resource、@Autowired、@Inject都可以书写标注在字段或者该字段的setter方法之上