@Autowired 和 @Resource 的区别
- 都可以用来装配 bean,都可以写在字段上或者方法上。
- @Autowired 属于Spring的;@Resource 为 JSR-250 标准的注释,属于 J2EE 的。
- @Autowired 默认按类型装配,默认情况下必须要求依赖对象必须存在,如果要允许 null 值,可以设置它的 required 属性为 false,例如:@Autowired(required=false),如果我们想使用名称装配可以结合 @Qualifier 注解进行使用,如下:
@Autowired()
@Qualifier("baseDao")
private BaseDao baseDao;
- @Resource 默认安装名称进行装配,名称可以通过 name 属性进行指定,如果没有指定 name 属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在 setter 方法上默认取属性名进行装配。当找不到与名称匹配的 bean 时才按照类型进行装配。但是需要注意的是,如果 name 属性一旦指定,就只会按照名称进行装配。例如:
@Resource(name="baseDao")
private BaseDao baseDao;
- 推荐使用:@Resource 注解在字段上,这样就不用写 setter 方法了,并且这个注解是属于 J2EE 的,减少了与 spring 的耦合。这样代码看起就比较优雅。
@Qualifier
- 说明
在使用 Spring 框架中 @Autowired 标签时默认情况下使用 @Autowired 注释进行自动注入时,Spring 容器中匹配的候选 Bean 数目必须有且仅有一个。当找不到一个匹配的 Bean 时,Spring 容器将抛 BeanCreationException 异常,并指出必须至少拥有一个匹配的 Bean。
Spring 允许我们通过 @Qualifier 注释指定注入 Bean 的名称,这样歧义就消除。
- 意义
@Qualifier("XXX") 中的 XXX 是 Bean 的名称,所以 @Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了。
@Autowired 可以对成员变量、方法以及构造函数进行注释,而 @Qualifier 的标注对象是成员变量、方法入参、构造函数入参。
- 示例
@Autowired
@Qualifier("userServiceImpl")
publicIUserService userService;
混合使用注解和 xml
- autowire 的取值有
byType / byName / Contructor / Autodetect
- 假如在 xml 中定义 bean 来自动装配,如不指定 autowire 的值,则必须指定这个 bean 的所有属性值,例如
<bean id="testDao" class="com.ggli.core.dal.dao.TestDao">
<property name="key" value="apple"/>
<property name="val" value="iphone"/>
<property name="log" ref="logDao"/>
</bean>
相应的 TestDao 为
package com.ggli.core.dal.dao;
public class TestDao {
private String key;
private String val;
private LogDao log;
public void setKey(String key) {
this.key = key;
}
public void setVal(String val) {
this.val = val;
}
public void setLog(LogDao logDao) {
this.log = logDao;
}
@Override
public String toString() {
return String.format("key[%s], val[%s], log[%s]", key, val, log.toString());
}
}
public class LogDao {
@Override
public String toString() {
return "LogDao sends the regards";
}
}
当 xml 中设置了正确的 property 之后,在 TestDao.java 中编辑器的左边 gutter 中会出现图标,鼠标移上去会显示 Navigate to the spring bean property
,点击该图标将会跳转到 xml 中定义该 bean 处。
而且,若 bean 的所有属性都列出后,autowire 的值对 bean 没有影响。
- 若在 bean 中指定
autowire="byName"
, xml 可以修改为
<bean id="testDao" class="com.ggli.core.dal.dao.TestDao" autowire="byName">
<property name="key" value="apple"/>
<property name="val" value="iphone"/>
</bean>
<bean id="log" class="com.ggli.core.dal.dao.LogDao"/>
当给 LogDao 命名适当的 bean id 时,TestDao.java 对应该属性的 setter 函数旁的 gutter 会出现图标,否则,autowire 失败,运行时会抛出 NullPointerException。
- 若在 bean 中指定
autowire="byType"
, xml 可以修改为
<bean id="testDao" class="com.ggli.core.dal.dao.TestDao" autowire="byType">
<property name="key" value="apple"/>
<property name="val" value="iphone"/>
</bean>
<bean class="com.ggli.core.dal.dao.LogDao"/>
此时,LogDao 的 bean 中可以不定义 id。
- 有的接口在 xml 中定义,有的接口使用 @Repository 或 @Component 标注的情况。在 xml 中的 bean 中使用 autowire 就能使用后者,同样可以通过 bean 左边的 gutter 图标导航。
注:上述方法中,在 xml 定义 bean 的类,需要有 setter 方法。如果没有 setter 方法,则属性应加上注解 @Autowire
关于 <context:annotation-config>
有时,在 spring 配置文件中可以看到 <context:annotation-config>
标签,它的作用是向 Spring 容器注册 AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、
PersistenceAnnotationBeanPostProcessor 和 RequiredAnnotationBeanPostProcessor 这 4 个BeanPostProcessor,从而系统能够识别相应的注解。
例如,使用 @Autowired 注解,那么就必须事先在 Spring 容器中声明 AutowiredAnnotationBeanPostProcessor Bean。
使用 @Resource 、@PostConstruct、@PreDestroy 等注解就必须先在 Spring 容器中声明 CommonAnnotationBeanPostProcessor Bean。
使用 @PersistenceContext 注解,就必须先声明 PersistenceAnnotationBeanPostProcessor Bean。
使用 @Required 注解,就必须声明 RequiredAnnotationBeanPostProcessor Bean。
传统的声明方法是
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor "/>
为了避免繁琐的逐条声明,Spring 提供了 <context:annotation-config>
标签来简化配置。
不过,使用注解方式注入,往往都会配置扫描包路径,例如
<context:component-scan base-package="com.ggli.core.dal"/>
该标签也包含了自动注入上述 processor 的功能,因此当使用 <context:component-scan/>
后,就可以移除 <context:annotation-config/>
了。