1. 准备
先定义一个接口 Human,以及它的两个实现类 Male 和 FeMale。作为下面将用到的示例。
//Human.java
@Component
public interface Human {
String say();
}
//Male.java
@Component
public class Male implements Human {
@Override
public String say() {
return "I'm a man";
}
}
//Female.java
@Component
public class FeMale implements Human {
@Override
public String say() {
return "I'm a girl";
}
}
2. @Autowired 和 @Resource 的相同点
Spring在实现依赖注入(DI)时可以使用 @Autowired 或 @Resource 来实现Bean的自动装配(即自动满足Bean依赖,在Spring初始化bean之后)。
@Component
public class DiTest{
@Autorired
private Human human;
// @Resource
// private Human human;
public void test(){
System.out.println(human.say());
}
}
3. @Autowired 和 @Resource 的比较
(1)来源
@Autowired(org.springframework.beans.factory.annotation.Autowired) 是 Spring 自带的注解;
@Resource(javax.annotation.Resource) 是 J2EE 的注解。
(2)@Autowired 的用法
【###】注解源码
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
【###】@Autowired 默认按照bean的类型进行匹配
@Autowired
private Human human;
上述示例中,@Autowired 注解会去Spring容器中寻找类型为Human或Human子类的Bean,并注入到变量human中。
如果匹配到多个结果则会抛出异常,因为它不知道该用哪个Bean。
同样,如果一个也没有匹配到,也会抛出异常,因为 @Autowired 注解默认情况下要求依赖对象必须存在(从上面源码可以看到 required 属性值默认为 true)。如果想要允许null值,可以设置它的 required 属性为 false。
@Autowired(required = false)
private Human human;
【###】按照bean名称进行匹配
bean名称即 Spring 容器中bean的id属性值,如果想要 @Autowired 注解按照bean名称进行匹配,则需要再加一个注解。
@Autowired
@Qualifier("male")
private Human human;
【###】@Autowired 注解还可以用在构造器上
@Component
public class DiTest{
private Human human;
@Autorired
public DiTest(Human human){
this.human = human;
}
public void test(){
System.out.println(human.say());
}
}
该注解会自动匹配构造器所有参数所需要的bean依赖。
【###】@Autowired 注解还可以用在普通方法上
无论是 setter 方法还是其他普通方法,都可以加上 @Autowired 注解来实现和上面一样的效果。
@Component
public class DiTest{
private Human human;
@Autorired
public void hello(Human human){
this.human = human;
}
public void test(){
System.out.println(human.say());
}
}
(3)@Resource 的用法
【###】注解源码
@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
String name() default "";
String lookup() default "";
Class<?> type() default java.lang.Object.class;
enum AuthenticationType {
CONTAINER,
APPLICATION
}
AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
boolean shareable() default true;
String mappedName() default "";
String description() default "";
}
【###】@Resource 默认按照bean名称进行bean匹配
@Resource
private Human human;
bean的名称默认为当前变量名。
上述示例中,@Resource 注解会去Spring容器中寻找名称(即id)为 “human” 的Bean,并注入到变量human中。
如果按照bean名称没有匹配到Bean,则退一步再按照bean类型(Human或Human子类)进行匹配;如果没有匹配到或匹配到多个则抛出异常。
【###】只按照bean名称匹配
@Resource(name="female")
private Human human;
指定了 name 属性值后,@Resource 注解则只按照 name 属性值所指定的bean名称去Spring容器中匹配。如果没有匹配到Bean则抛出异常。
注意:这种方式不可能出现匹配到多个Bean的情况,因为Bean的id值在Spring容器中是唯一的。如果有重复的属性值,则Spring应用在启动时就会抛出异常。
【###】只按照bean类型进行匹配
@Resource(type=Human.class)
private Human human;
从上述源码中可以看到,type属性的值为 Class 类型参数,默认为 java.lang.Object.class 。
指定了 type 属性值后,@Resource 注解则只按照 type 属性值所指定的bean类型(或子类类型)去 Spring 容器中匹配。如果没有匹配到 Bean 或匹配到多个结果则抛出异常。
【###】同时按照bean名称和bean类型进行匹配
@Resource(name="male",type=Human.class)
private Human human;
指定了 name 和 type 属性值后,@Resource 注解将去 Spring 容器中寻找 Id 属性值为 “male”,且类型为 Human(或Human子类类型)的Bean。如果没有匹配到,则抛出异常。
两个条件缺一不可。
【###】@Resource 注解不能用在类构造器上
【###】@Resource 注解可以用在普通方法上
@Resource 注解可以用在 setter 方法或其他普通方法上。
@Component
public class DiTest{
private Human human;
@Resource
public void hello(Human human){
this.human = human;
}
public void test(){
System.out.println(human.say());
}
}