Spring注解@Autowired、@Resource、@Inject

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方法之上

猜你喜欢

转载自blog.csdn.net/pzjtian/article/details/82658321