@Autowired @Qualifier @Resource 之Spring三兄弟详解

前言:

       Spring注入三兄弟一如奶茶三兄弟,三者各有不同却总因为神似混淆。

@Autowired @Qualifier 属于 Spring 定义的注解

@Resource 属于 JSR-250 规范定义的注解。

@Autowired 

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

以下是@Autowired 的源码:


package org.springframework.beans.factory.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}

从源码中可以看出:

首先,@Autowired可修饰的对象包含:构造函数、方法、参数、字段、注解类型。

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

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

@Qualifier

@Qualifier注解,根据bean名称进行对象注入。始于spring2.5.

以下是@Qualifier源码:


package org.springframework.beans.factory.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@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运行时被其他代码读取和使用。这点与@Autowired相同。

@Resource 源码:

@Resource属于JSR-250规范定义的注解,支持根据类型和名称进行对象注入。

@Resource注解始于jdk1.6。


package javax.annotation;

import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;

/**
 * The Resource annotation marks a resource that is needed
 * by the application.  This annotation may be applied to an
 * application component class, or to fields or methods of the
 * component class.  When the annotation is applied to a
 * field or method, the container will inject an instance
 * of the requested resource into the application component
 * when the component is initialized.  If the annotation is
 * applied to the component class, the annotation declares a
 * resource that the application will look up at runtime. <p>
 *
 * Even though this annotation is not marked Inherited, deployment
 * tools are required to examine all superclasses of any component
 * class to discover all uses of this annotation in all superclasses.
 * All such annotation instances specify resources that are needed
 * by the application component.  Note that this annotation may
 * appear on private fields and methods of superclasses; the container
 * is required to perform injection in these cases as well.
 *
 * @since Common Annotations 1.0
 */
@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 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 <code>name</code>
     * element or defaulted, is a name that is local to the application
     * component using the resource.  (It's a name in the JNDI
     * <code>java:comp/env</code> 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
     * <i>global</i> JNDI name, but may be a name of any form. <p>
     *
     * 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可修饰的对象包含:类型、字段、方法,它修饰的范围与以上二者都不同。

其次,它包含的属性较多,如下:

name:用来指定bean名称

type:用来指定bean类型

lookup:不知

shareable:不知

mappedName:不知

description:资源的描述

authenticationType:不知

最后,通过@Retention(RetentionPolicy.RUNTIME)元注解,可以得知@Resource可以在JVM运行时被其他代码读取和使用,与以上二者相同。

注意:

1.@Resource默认根据name进行注入。

2.如果同一类型被注入两次,两次命名都不同,那么Spring会根据属性名称(name)从上下文中找到唯一匹配的bean进行装配。如果没有找到符合的bean,则会根据该类型(type)进行查找,如果找到就注入。如果找不到或者找到多个都会抛出异常。

3.如果@Resource注解修饰的是方法,那么默认会从set方法截取现年供应的属性名称(name),之后会根据属性名称查找bean.

4.如果即指定了name,又指定了type,Spring会从上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。

结:

       理解原理之后更有助于使用以及排查问题。

我变秃了,也变强了...

发布了36 篇原创文章 · 获赞 46 · 访问量 7870

猜你喜欢

转载自blog.csdn.net/weixin_41860630/article/details/98639389