前言:
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进行装配,找不到则抛出异常。
结:
理解原理之后更有助于使用以及排查问题。