虽然 2.0 版本发布以来,Spring 陆续提供了十多个注解,但是提供的这些注解只是为了在某些情况下简化 XML 的配置,并非要取代 XML 配置方式。这一点可以从 Spring IoC 容器的初始化类可以看出:ApplicationContext 接口的最常用的实现类是 ClassPathXmlApplicationContext
和 FileSystemXmlApplicationContext,以及面向 Portlet 的 XmlPortletApplicationContext 和面向 web 的 XmlWebApplicationContext,它们都是面向 XML 的。Spring 3.0 新增了另外两个实现类:AnnotationConfigApplicationContext 和 AnnotationConfigWebApplicationContext。从名字便可以看出,它们是为注解而生,直接依赖于注解作为容器配置信息来
源的 IoC 容器初始化类。由于 AnnotationConfigWebApplicationContext 是 AnnotationConfigApplicationContext 的 web 版本,其用法与后者相比几乎没有什么差别,因此本文将以 AnnotationConfigApplicationContext 为例进行讲解。
AnnotationConfigApplicationContext 搭配上 @Configuration 和 @Bean 注解,自此,XML 配置方式不再是 Spring IoC 容器的唯一配置方式。两者在一定范围内存在着竞争的关系,但是它们在大多数情况下还是相互协作的关系,两者的结合使得 Spring
IoC 容器的配置更简单,更强大。
之前,我们将配置信息集中写在 XML 中,如今使用注解,配置信息的载体由 XML 文件转移到了 Java 类中。我们通常将用于存放配置信息的类的类名以 “Config” 结尾,比如 AppDaoConfig.java、AppServiceConfig.java 等等。我们需要在用于指定配置信息的类上加上
@Configuration 注解,以明确指出该类是 Bean 配置的信息源。并且 Spring 对标注 Configuration 的类有如下要求:
配置类不能是 final 的;配置类不能是本地化的,亦即不能将配置类定义在其他类的方法内部;配置类必须有一个无参构造函数。AnnotationConfigApplicationContext 将配置类中标注了 @Bean 的方法的返回值识别为 Spring Bean,并注册到容器中,受 IoC 容器管理。@Bean
的作用等价于 XML 配置中的 标签。示例如下:
@Configuration
public class BookStoreDaoConfig{
@Bean
public UserDao userDao(){ return new UserDaoImpl();}
@Bean
public BookDao bookDao(){return new BookDaoImpl();}
}
Spring 在解析到以上文件时,将识别出标注 @Bean 的所有方法,执行之,并将方法的返回值 ( 这里是 UserDaoImpl 和 BookDaoImpl 对象 ) 注册到 IoC 容器中。默认情况下,Bean 的名字即为方法名。因此,与以上配置等价的 XML 配置如下:
@Bean 具有以下四个属性:
name -- 指定一个或者多个 Bean 的名字。这等价于 XML 配置中 的 name 属性。initMethod -- 容器在初始化完 Bean 之后,会调用该属性指定的方法。这等价于 XML 配置中 的 init-method 属性。destroyMethod -- 该属性与 initMethod
功能相似,在容器销毁 Bean 之前,会调用该属性指定的方法。这等价于 XML 配置中 的 destroy-method 属性。autowire -- 指定 Bean 属性的自动装配策略,取值是 Autowire 类型的三个静态属性。Autowire.BY_NAME,Autowire.BY_TYPE,Autowire.NO。与 XML 配置中的 autowire 属性的取值相比,这里少了 constructor,这是因为 constructor 在这里已经没有意义了。@Bean 没有直接提供指定作用域的属性,可以通过
@Scope 来实现该功能,关于 @Scope 的用法已在上文列举。
设计 @Configuration 和 @Bean 的初衷,并不是为了完全取代 XML,而是为了在 XML 之外多一种可行的选择。由于 Spring 自发布以来,Spring 开发小组便不断简化 XML 配置,使得 XML 配置方式已经非常成熟,加上 Spring 2.0 以后出现了一系列命名空间的支持,使得
XML 配置方式成为了使用简单、功能强大的 Bean 定义方式。而且,XML 配置的一些高级功能目前还没有相关注解能够直接支持。因此,在目前的多数项目中,要么使用纯粹的 XML 配置方式进行 Bean 的配置,要么使用以注解为主,XML 为辅的配置方式进行 Bean 的配置。
之所以会出现两者共存的情况,主要归结为三个原因:其一,目前绝大多数采用 Spring 进行开发的项目,几乎都是基于 XML 配置方式的,Spring 在引入注解的同时,必须保证注解能够与 XML 和谐共存,这是前提;其二,由于注解引入较晚,因此功能也没有发展多年的 XML 强大,因此,对于复杂的配置,注解还很难独当一面,在一段时间内仍然需要
XML 的配合才能解决问题。除此之外,Spring 的 Bean 的配置方式与 Spring 核心模块之间是解耦的,因此,改变配置方式对 Spring 的框架自身是透明的。Spring 可以通过使用 Bean 后处理器 (BeanPostProcessor) 非常方便的增加对于注解的支持。这在技术实现上非常容易的事情。
要使用混合配置方式,首先需要判断以哪一种配置方式为主。对这个问题的不同回答将会直接影响到实现的方式。然而大可不必为此伤脑筋,因为不论是以 XML 为主,还是以注解为主,配置方式都是简单而且容易理解的。这里不存在错误的决定,因为仅仅是表现方式不一样。我们首先假设以 XML 配置为主的情况。
对于已经存在的大型项目,可能初期是以 XML 进行 Bean 配置的,后续逐渐加入了注解的支持,这时我们只需在 XML 配置文件中将被 @Configuration 标注的类定义为普通的 ,同时注册处理注解的 Bean 后处理器即可。示例如下: