从Spring2.5开始就可以使用注解自动装配Bean的属性。使用注解自动装配与XML中使用autowire属性自动装配并没有太大差别。
Spring容器默认禁用注解装配。所以在基于注解自动装配,我们需要在Spring配置中启用它。如:<context:annotation-config/>
<context:annotation-config/>他的作用是向Spring容器注册
AutowiredAnnotationBeanPostProcessor(@Autowired)
CommonAnnotationBeanPostProcessor(@ Resource 、@ PostConstruct、@ PreDestroy等注解)
PersistenceAnnotationBeanPostProcessor(@PersistenceContext)
RequiredAnnotationBeanPostProcessor (@Required)
这四个BeanPostProcessor。
总是需要按照传统的方式一条一条配置显得有些繁琐和没有必要,于是spring给我们提供<context:annotation-config/>的简化配置方式,自动帮你完成声明。
Spring还有一个配置<context:component-scan base-package=”cn.com.xx.xx”/>能替代<context:annotation-config/>,我们后面在说。
@Autowired的使用
使用@Autowired我们得知道它是按照byType自动装配的,可以无需写set方法,甚至不会受限于private关键字。即使是私有实例变量,它仍然可以被自动装配。是不是感觉@Autowired注解没有任何限制?实际上会有两种情况出现异常:
1、如果没有匹配到Bean
可以使用@Autowired(required=false)即时没有匹配到也不会异常,而是将值设置为null。来看看@Autowired注解源码:
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, 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;//required默认是true,必须满足依赖否则异常,我们可以将这个值改为fasle改变这一行为
}
2、如果存在多个匹配的Bean
可以使用@Qualifier("users")来注入ID为users的Bean。来看看@Qualifier注解源码:
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {
String value() default "";//默认是空字符串,也就是不指定匹配的Bean ID,必要时我们可以指定value的值(也就是Bean的ID)这时候会按照byName去自动装配
}
下面来看下例子:
public class Roles {
private int id;
private String roleName;
@Autowired
private Users users;
//@Autowired(required=false)//即时没匹配到ID为users也不会异常,而是null
//@Qualifier("users")//获得ID为users的Bean
//private Users users;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
//没有users的get,set方法
//重写toString方法,方便测试
@Override
public String toString() {
return "Roles [id=" + id + ", roleName=" + roleName + ", users="
+ users + "]";
}
}
public class Users {
private int id;
private String name;
//省略set get方法
@Override
public String toString() {
return "Users [id=" + id + ", name=" + name + "]";
}
}
<bean id="roles" class="cn.com.ztz.spring.model.Roles">
<property name="id" value="1"/>
<property name="roleName" value="管理员"/>
</bean>
<bean id="users" class="cn.com.ztz.spring.model.Users">
<property name="id" value="2"/>
<property name="name" value="张三"/>
</bean>
<context:annotation-config/>
运行测试方法:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:spring.xml"})
public class JunitTest {
@Autowired
private Roles roles;
@Test
public void testSpring(){
System.out.println(roles);
}
}
Roles [id=1, roleName=管理员, users=Users [id=2, name=张三]]
@resource跟@Autowired的区别
@resource注解其实跟@Autowired差不多的,他们的区别是:
1、@resource是JDK的,@Autowired是Spring的
2、@resource按照byName自动装配,@Autowired按照byType自动装配。
@Autowired装配顺序
2、如果存在且唯一,则OK
3、如果不唯一,寻找name为users的bean。因为bean的name有唯一性,所以,到这里应该能确定是否存在满足要求的bean了
@Autowired也可以手动指定按照byName方式注入,使用@Qualifier标签,例如:
@Autowired()
@Qualifier("users" )
@Resource装配顺序
1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;
ps:有哪不对的地方,还请指出。