Spring编程: @Autowired @Qualifier @Resource 注解详解

首先明确一点:@Autowired @Qualifier 属于 Spring 定义的注解,@Resource 属于 JSR-250 规范定义的注解。以上注解 Spring 都支持。文章仅代表个人观点,如有不正之处,欢迎批评指正。

@Autowired

根据 bean 类型进行对象注入。@Autowired 注解始于 Spring2.5。

包路径:org.springframework.beans.factory.annotation

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

Defaults to {@code true}. */ boolean required() default true; }

从源码中可以看出,@Autowired 修饰的对象包含:构造函数、方法、参数、字段、注解类型。

它包含一个 required 属性,用来声明注解的对象是否是必须的,默认值为true。

通过 @Retention(RetentionPolicy.RUNTIME) 元注解,我们可以得知,@Autowired 可以在 JVM 运行被其他代码读取和使用。

@Qualifier

我们可以通过 @Autowired 根据 bean 类型进行对象注入,如果我们想要根据 bean 名称注入,该怎么办呢?Spring 提供了 @Qualifier 注解,通过它进行 bean 名称注入。@Qualifier 注解始于 Spring2.5。

包路径:org.springframework.beans.factory.annotation

@Qualifier 注解的源码:

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {

	String value() default "";

}

从源码中可以看出,@Qualifier 修饰的对象范围包含:字段、方法、参数、类型、注解类型,它修饰的对象范围与 @Autowired 的范围有所不同。

它包含一个 value 属性,用来指定注入的 bean 的名称,默认值为空。

通过 @Retention(RetentionPolicy.RUNTIME) 元注解,我们也可以得知,@Qualifier 可以在 JVM 运行被其他代码读取和使用。

@Resource

通过上面的讲解我们了解到:@Autowired 可以根据类型注入对象,@Qualifier 可以根据 bean 名称注入对象。那 @Resource 的作用是什么呢?@Resource 属于 JSR-250 规范定义的注解,支持根据类型和名称进行对象注入。@Resource 注解始于 jdk1.6。

包路径:javax.annotation (从包路径也可以看出该注解不属于 Spring)

@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
    /**
     * The JNDI name of the resource.  For field annotations,
     * the default is the field name.  For method annotations,
     * the default is the JavaBeans property name corresponding
     * to the method.  For class annotations, there is no default
     * and this must be specified.
     */
    String name() default "";

    /**
     * The name of the resource that the reference points to. It can
     * link to any compatible resource using the global JNDI names.
     *
     * @since 1.7, Common Annotations 1.1
     */

    String lookup() default "";

    /**
     * The Java type of the resource.  For field annotations,
     * the default is the type of the field.  For method annotations,
     * the default is the type of the JavaBeans property.
     * For class annotations, there is no default and this must be
     * specified.
     */
    Class type() default java.lang.Object.class;

    /**
     * The two possible authentication types for a resource.
     */
    enum AuthenticationType {
            CONTAINER,
            APPLICATION
    }

    /**
     * The authentication type to use for this resource.
     * This may be specified for resources representing a
     * connection factory of any supported type, and must
     * not be specified for resources of other types.
     */
    AuthenticationType authenticationType() default AuthenticationType.CONTAINER;

    /**
     * Indicates whether this resource can be shared between
     * this component and other components.
     * This may be specified for resources representing a
     * connection factory of any supported type, and must
     * not be specified for resources of other types.
     */
    boolean shareable() default true;

    /**
     * A product specific name that this resource should be mapped to.
     * The name of this resource, as defined by the name
     * element or defaulted, is a name that is local to the application
     * component using the resource.  (It's a name in the JNDI
     * java:comp/env namespace.)  Many application servers
     * provide a way to map these local names to names of resources
     * known to the application server.  This mapped name is often a
     * global JNDI name, but may be a name of any form. 

* * Application servers are not required to support any particular * form or type of mapped name, nor the ability to use mapped names. * The mapped name is product-dependent and often installation-dependent. * No use of a mapped name is portable. */ String mappedName() default ""; /** * Description of this resource. The description is expected * to be in the default language of the system on which the * application is deployed. The description can be presented * to the Deployer to help in choosing the correct resource. */ String description() default ""; }

从源码中可以看出,@Resource 修饰的对象范围包含:类型、字段、方法,它修饰的对象范围与 @Autowired、@Qualifier 的范围有所不同。

它包含属性如下:

  • name:用来指定 bean 名称
  • type:用来指定 bean 类型
  • lookup:未知
  • shareable:未知
  • mappedName:未知
  • description:资源的描述,帮助开发者选择正确的资源
  • authenticationType:未知

通过 @Retention(RetentionPolicy.RUNTIME) 元注解,我们也可以得知,@Resource 可以在 JVM 运行被其他代码读取和使用。

关于 @Resource name 和 type 的说明:@Resource默认按根据 name 进行注入的。

###1、既不指定 name 属性,也不指定 type 属性###
Spring 会根据属性名称(userMapper1、userMapper2)从上下文中找到唯一匹配的 bean 进行装配。如果没有找到符合的bean,则回退为一个原始类型进行进行查找,如果找到就注入。
示例:

    @Resource
    private UserMapper userMapper1;

    @Resource
    private UserMapper userMapper2;

配置:




如上,没有指定 @Resource 的 name 和 type,此时 Spring 会根据 userMapper1 userMapper2 查找 bean,没有找到,之后 Spring 会根据这两个对象的类型查找 bean,通过配置文件我们可以发现,存在两个 UserMapper 类型的 bean,这时 Spring 报错,提示expected single matching bean but found 2:

如果 @Resource 注解修饰的是方法,默认会从 set 方法中截取相应的属性名称,之后会根据属性名称查找 bean,如下:

@Resource
public UserMapper setUserMapper(){
	return this.userMapper;
}

Spring 会从setUserMapper方法中截取userMapper作为属性名称,之后会根据属性名称查找 bean。

###2、只指定 name 属性,不指定 type 属性###
Spring 会根据 name 从上下文中找到唯一匹配的 bean 进行装配。
###3、不指定 name 属性,只指定 type 属性###
Spring 会根据 type 从上下文中找到唯一匹配的 bean 进行装配,找不到或者找到多个,都会抛出异常。
###4、既指定 name 属性,又指定 type 属性###
Spring 会根据 name 和 type 属性从上下文中找到唯一匹配的 bean 进行装配,找不到则抛出异常。

你可能感兴趣的:(Java编程,spring编程)