Spring学习笔记
@Autowired
注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。............. BeanPostProcessor
对 @Autowired
进行解析,所以要让@Autowired
起作用必须事先在 Spring 容器中声明AutowiredAnnotationBeanPostProcessor
Bean。BeanPostProcessor
对 @Autowired
进行解析,所以要让@Autowired
起作用必须事先在 Spring 容器中声明AutowiredAnnotationBeanPostProcessor
Bean。<!-- 该 BeanPostProcessor 将自动起作用,对标注 @Autowired 的 Bean 进行自动注入 --> <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
当不能确定 Spring 容器中一定拥有某个类的 Bean 时,可以在需要自动注入该类 Bean 的地方可以使用@Autowired(required = false
)
,这等于告诉 Spring:在找不到匹配 Bean 时也不报错。
当然,一般情况下,使用 @Autowired
的地方都是需要注入 Bean 的,使用了自动注入而又允许不注入的情况一般仅会在开发期或测试期碰到(如为了快速启动 Spring 容器,仅引入一些模块的 Spring 配置文件),所以@Autowired(required = false)
会很少用到。
和找不到一个类型匹配 Bean 相反的一个错误是:如果 Spring 容器中拥有多个候选 Bean,Spring 容器在启动时也会抛出 BeanCreationException
异常。
清单 13. 使用 @Qualifier 注释指定注入 Bean 的名称
@Autowired public void setOffice(@Qualifier("office")Office office) { this.office = office; } .... @Autowired @Qualifier("office") private Office office; ....... |
@Resource
的作用相当于 @Autowired
,只不过 @Autowired
按 byType 自动注入,面@Resource
默认按 byName 自动注入罢了。@Resource
有两个属性是比较重要的,分别是 name 和 type,Spring 将@Resource
注释的 name 属性解析为 Bean 的名字,而 type 属性则解析为 Bean 的类型。所以如果使用 name 属性,则使用 byName 的自动注入策略,而使用 type 属性时则使用 byType 自动注入策略。如果既不指定 name 也不指定 type 属性,这时将通过反射机制使用 byName 自动注入策略。
Resource 注释类位于 Spring 发布包的 lib/j2ee/common-annotations.jar 类包中,因此在使用之前必须将其加入到项目的类库中。来看一个使用@Resource
的例子:
package com.baobaotao; import javax.annotation.Resource; public class Boss { // 自动注入类型为 Car 的 Bean @Resource private Car car; // 自动注入 bean 名称为 office 的 Bean @Resource(name = "office") private Office office; }
@PostConstruct 和 @PreDestroy
Spring 容器中的 Bean 是有生命周期的,Spring 允许在 Bean 在初始化完成后以及 Bean 销毁前执行特定的操作,您既可以通过实现 InitializingBean/DisposableBean 接口来定制初始化之后 / 销毁之前的操作方法,也可以通过 <bean> 元素的 init-method/destroy-method 属性指定初始化之后 / 销毁之前调用的操作方法。关于 Spring 的生命周期,笔者在《精通 Spring 2.x—企业应用开发精解》第 3 章进行了详细的描述,有兴趣的读者可以查阅。
JSR-250 为初始化之后/销毁之前方法的指定定义了两个注释类,分别是 @PostConstruct 和 @PreDestroy,这两个注释只能应用于方法上。标注了 @PostConstruct 注释的方法将在类实例化后调用,而标注了 @PreDestroy 的方法将在类销毁之前调用。
/**************************** 重点 start *********************/
虽然我们可以通过 @Autowired
或 @Resource
在 Bean 类中使用自动注入功能,但是 Bean 还是在 XML 文件中通过 <bean> 进行定义 —— 也就是说,在 XML 配置文件中定义 Bean,通过@Autowired
或 @Resource
为 Bean 的成员变量、方法入参或构造函数入参提供自动注入的功能。能否也通过注释定义 Bean,从 XML 配置文件中完全移除 Bean 定义的配置呢?答案是肯定的,我们通过 Spring 2.5 提供的@Component
注释就可以达到这个目标了。
为什么 @Repository 只能标注在 DAO 类上呢?这是因为该注解的作用不只是将类识别为 Bean,同时它还能将所标注的类中抛出的数据访问异常封装为 Spring 的数据访问异常类型。 Spring 本身提供了一个丰富的并且是与具体的数据访问技术无关的数据访问异常结构,用于封装不同的持久层框架抛出的异常,使得异常独立于底层的框架。
Spring 2.5 在 @Repository 的基础上增加了功能类似的额外三个注解:@Component、@Service、@Constroller,它们分别用于软件系统的不同层次:
- @Component 是一个泛化的概念,仅仅表示一个组件 (Bean) ,可以作用在任何层次。
- @Service 通常作用在业务层,但是目前该功能与 @Component 相同。
- @Constroller 通常作用在控制层,但是目前该功能与 @Component 相同。
通过在类上使用 @Repository、@Component、@Service 和 @Constroller 注解,Spring 会自动创建相应的 BeanDefinition 对象,并注册到 ApplicationContext 中。这些类就成了 Spring 受管组件。这三个注解除了作用于不同软件层次的类,其使用方式与 @Repository 是完全相同的。
......................
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:component-scan base-package="com.baobaotao"/> </beans> |
这里,所有通过 <bean> 元素定义 Bean 的配置内容已经被移除,仅需要添加一行 <context:component-scan/> 配置就解决所有问题了——Spring XML 配置文件得到了极致的简化(当然配置元数据还是需要的,只不过以注释形式存在罢了)。<context:component-scan/> 的 base-package 属性指定了需要扫描的类包,类包及其递归子包中所有的类都会被处理。
<context:component-scan/> 还允许定义过滤器将基包下的某些类纳入或排除。Spring 支持以下 4 种类型的过滤方式,通过下表说明:
表 1. 扫描过滤方式过滤器类型 | 说明 |
---|---|
注释 | 假如 com.baobaotao.SomeAnnotation 是一个注释类,我们可以将使用该注释的类过滤出来。 |
类名指定 | 通过全限定类名进行过滤,如您可以指定将 com.baobaotao.Boss 纳入扫描,而将 com.baobaotao.Car 排除在外。 |
正则表达式 | 通过正则表达式定义过滤的类,如下所示: com\.baobaotao\.Default.* |
AspectJ 表达式 | 通过 AspectJ 表达式定义过滤的类,如下所示: com. baobaotao..*Service+ |
下面是一个简单的例子:
<context:component-scan base-package="com.baobaotao"> <context:include-filter type="regex" expression="com\.baobaotao\.service\..*"/> <context:exclude-filter type="aspectj" expression="com.baobaotao.util..*"/> </context:component-scan> |
值得注意的是 <context:component-scan/> 配置项不但启用了对类包进行扫描以实施注释驱动 Bean 定义的功能,同时还启用了注释驱动自动注入的功能(即还隐式地在内部注册了AutowiredAnnotationBeanPostProcessor
和 CommonAnnotationBeanPostProcessor
),因此当使用 <context:component-scan/> 后,就可以将 <context:annotation-config/> 移除了。
默认情况下通过 @Component
定义的 Bean 都是 singleton 的,如果需要使用其它作用范围的 Bean,可以通过@Scope
注释来达到目标,如以下代码所示
/**************************** 重点 end *********************/
package com.baobaotao; import org.springframework.context.annotation.Scope; … @Scope("prototype") @Component("boss") public class Boss { … }