Spring 自 2.0 版本开始,陆续引入了一些注解用于简化 Spring 的开发。@Repository 注解便属于最早引入的一批,它用于将数据访问层 (DAO 层 ) 的类标识为 Spring Bean。具体只需将该注解标注在 DAO 类上便可。同时,为了让 Spring 可以扫描类路径中的类并识别出 @Repository 注解,须要在 XML 配置文件中启用 Bean 的自动扫描功能,这能够经过 <context:component-scan/> 实现。以下所示:java
// 首先使用 @Repository 将 DAO 类声明为 Bean package bookstore.dao; @Repository public class UserDaoImpl implements UserDao{ …… } // 其次,在 XML 配置文件中启动 Spring 的自动扫描功能 <beans … > …… <context:component-scan base-package=”bookstore.dao” /> …… </beans>
如此,咱们就再也不须要在 XML 中显式使用 <bean/> 进行 Bean 的配置。Spring 在容器初始化时将自动扫描 base-package 指定的包及其子包下的全部 class 文件,全部标注了 @Repository 的类都将被注册为 Spring Bean。web
为何 @Repository 只能标注在 DAO 类上呢?这是由于该注解的做用不仅是将类识别为 Bean,同时它还能将所标注的类中抛出的数据访问异常封装为 Spring 的数据访问异常类型。 Spring 自己提供了一个丰富的而且是与具体的数据访问技术无关的数据访问异常结构,用于封装不一样的持久层框架抛出的异常,使得异常独立于底层的框架。算法
Spring 2.5 在 @Repository 的基础上增长了功能相似的额外三个注解:@Component、@Service、@Constroller,它们分别用于软件系统的不一样层次:spring
@Component 是一个泛化的概念,仅仅表示一个组件 (Bean) ,能够做用在任何层次。数组
@Service 一般做用在业务层,可是目前该功能与 @Component 相同。框架
@Constroller 一般做用在控制层,可是目前该功能与 @Component 相同。dom
经过在类上使用 @Repository、@Component、@Service 和 @Constroller 注解,Spring 会自动建立相应的 BeanDefinition 对象,并注册到 ApplicationContext 中。这些类就成了 Spring 受管组件。这三个注解除了做用于不一样软件层次的类,其使用方式与 @Repository 是彻底相同的。函数
另外,除了上面的四个注解外,用户能够建立自定义的注解,而后在注解上标注 @Component,那么,该自定义注解便具备了与所 @Component 相同的功能。不过这个功能并不经常使用。ui
当一个 Bean 被自动检测到时,会根据那个扫描器的 BeanNameGenerator 策略生成它的 bean 名称。默认状况下,对于包含 name 属性的 @Component、@Repository、 @Service 和 @Controller,会把 name 取值做为 Bean 的名字。若是这个注解不包含 name 值或是其余被自定义过滤器发现的组件,默认 Bean 名称会是小写开头的非限定类名。若是你不想使用默认 bean 命名策略,能够提供一个自定义的命名策略。首先实现 BeanNameGenerator 接口,确认包含了一个默认的无参数构造方法。而后在配置扫描器时提供一个全限定类名,以下所示:spa
<beans ...> <context:component-scan base-package="a.b" name-generator="a.SimpleNameGenerator"/> </beans>
与经过 XML 配置的 Spring Bean 同样,经过上述注解标识的 Bean,其默认做用域是"singleton",为了配合这四个注解,在标注 Bean 的同时可以指定 Bean 的做用域,Spring 2.5 引入了 @Scope 注解。使用该注解时只需提供做用域的名称就好了,以下所示:
@Scope("prototype") @Repository public class Demo { … }
若是你想提供一个自定义的做用域解析策略而不使用基于注解的方法,只需实现 ScopeMetadataResolver 接口,确认包含一个默认的没有参数的构造方法。而后在配置扫描器时提供全限定类名:
<context:component-scan base-package="a.b" scope-resolver="footmark.SimpleScopeResolver" />
Spring Bean 是受 Spring IoC 容器管理,由容器进行初始化和销毁的(prototype 类型由容器初始化以后便不受容器管理),一般咱们不须要关注容器对 Bean 的初始化和销毁操做,由 Spring 通过构造函数或者工厂方法建立的 Bean 就是已经初始化完成并当即可用的。然而在某些状况下,可能须要咱们手工作一些额外的初始化或者销毁操做,这一般是针对一些资源的获取和释放操做。Spring 1.x 为此提供了两种方式供用户指定执行生命周期回调的方法。
第一种方式是实现 Spring 提供的两个接口:InitializingBean 和 DisposableBean。若是但愿在 Bean 初始化完成以后执行一些自定义操做,则可让 Bean 实现 InitializingBean 接口,该接口包含一个 afterPropertiesSet() 方法,容器在为该 Bean 设置了属性以后,将自动调用该方法;若是 Bean 实现了 DisposableBean 接口,则容器在销毁该 Bean 以前,将调用该接口的 destroy() 方法。这种方式的缺点是,让 Bean 类实现 Spring 提供的接口,增长了代码与 Spring 框架的耦合度,所以不推荐使用。
第二种方式是在 XML 文件中使用 <bean> 的 init-method 和 destroy-method 属性指定初始化以后和销毁以前的回调方法,代码无需实现任何接口。这两个属性的取值是相应 Bean 类中的初始化和销毁方法,方法名任意,可是方法不能有参数。示例以下:
<bean id=”userService” class=”bookstore.service.UserService” init-method=”init” destroy-method=”destroy”> … </bean>
Spring 2.5 在保留以上两种方式的基础上,提供了对 JSR-250 的支持。JSR-250 规范定义了两个用于指定声明周期方法的注解:@PostConstruct 和 @PreDestroy。这两个注解使用很是简单,只需分别将他们标注于初始化以后执行的回调方法或者销毁以前执行的回调方法上。因为使用了注解,所以须要配置相应的 Bean 后处理器,亦即在 XML 中增长以下一行:
<context:annotation-config />
比较上述三种指定生命周期回调方法的方式,第一种是不建议使用的,不但其用法不如后两种方式灵活,并且无形中增长了代码与框架的耦合度。后面两种方式开发者能够根据使用习惯选择其中一种,可是最好不要混合使用,以避免增长维护的难度。
依赖检查的做用是,判断给定 Bean 的相应 Setter 方法是否都在实例化的时候被调用了,而不是判断字段是否已经存在值了。Spring 进行依赖检查时,只会判断属性是否使用了 Setter 注入。若是某个属性没有使用 Setter 注入,即便是经过构造函数已经为该属性注入了值,Spring 仍然认为它没有执行注入,从而抛出异常。另外,Spring 只管是否经过 Setter 执行了注入,而对注入的值却没有任何要求,即便注入的 <null/>,Spring 也认为是执行了依赖注入。
<bean> 标签提供了 dependency-check 属性用于进行依赖检查。该属性的取值包括如下几种:
none -- 默认不执行依赖检查。能够在 <beans> 标签上使用 default-dependency-check 属性改变默认值。
simple -- 对原始基本类型和集合类型进行检查。
objects -- 对复杂类型进行检查(除了 simple 所检查类型以外的其余类型)。
all -- 对全部类型进行检查。
旧版本使用 dependency-check 在配置文件中设置,缺点是粒度较粗。使用 Spring2.0 提供的 @Required 注解,提供了更细粒度的控制。@Required 注解只能标注在 Setter 方法之上。由于依赖注入的本质是检查 Setter 方法是否被调用了,而不是真的去检查属性是否赋值了以及赋了什么样的值。若是将该注解标注在非 setXxxx() 类型的方法则被忽略。
为了让 Spring 可以处理该注解,须要激活相应的 Bean 后处理器。要激活该后处理器,只需在 XML 中增长以下一行便可。
<context:annotation-config/>
当某个被标注了 @Required 的 Setter 方法没有被调用,则 Spring 在解析的时候会抛出异常,以提醒开发者对相应属性进行设置。
自动装配是指,Spring 在装配 Bean 的时候,根据指定的自动装配规则,将某个 Bean 所须要引用类型的 Bean 注入进来。<bean> 元素提供了一个指定自动装配类型的 autowire 属性,该属性有以下选项:
no -- 显式指定不使用自动装配。
byName -- 若是存在一个和当前属性名字一致的 Bean,则使用该 Bean 进行注入。若是名称匹配可是类型不匹配,则抛出异常。若是没有匹配的类型,则什么也不作。
byType -- 若是存在一个和当前属性类型一致的 Bean ( 相同类型或者子类型 ),则使用该 Bean 进行注入。byType 可以识别工厂方法,即可以识别 factory-method 的返回类型。若是存在多个类型一致的 Bean,则抛出异常。若是没有匹配的类型,则什么也不作。
constructor -- 与 byType 相似,只不过它是针对构造函数注入而言的。若是当前没有与构造函数的参数类型匹配的 Bean,则抛出异常。使用该种装配模式时,优先匹配参数最多的构造函数。
autodetect -- 根据 Bean 的自省机制决定采用 byType 仍是 constructor 进行自动装配。若是 Bean 提供了默认的构造函数,则采用 byType;不然采用 constructor 进行自动装配。
当使用 byType 或者 constructor 类型的自动装配的时候,自动装配也支持引用类型的数组或者使用了泛型的集合,这样,Spring 就会检查容器中全部类型匹配的 Bean,组成集合或者数组后执行注入。对于使用了泛型的 Map 类型,若是键是 String 类型,则 Spring 也会自动执行装配,将全部类型匹配的 Bean 做为值,Bean 的名字做为键。
咱们能够给 <beans> 增长 default-autowire 属性,设置默认的自动封装策略。默认值为"no"。若是使用自动装配的同时,也指定了 property 或者 constructor-arg 标签,则显式指定的值将覆盖自动装配的值。目前的自动封装不支持简单类型,好比基本类型、String、Class,以及它们的数组类型。
在按类型匹配的时候 ( 多是 byType、constructor、autodetect),同一个类型可能存在多个 Bean,若是被注入的属性是数组、集合或者 Map,这可能没有问题,可是若是只是简单的引用类型,则会抛出异常。解决方法有以下几种:
取消该 Bean 的自动装配特性,使用显式的注入。咱们可能不但愿某个 Bean 被看成其余 Bean 执行自动封装时的候选对象,咱们能够给该 <bean> 增长 autowire-candidate="false"。(autowire-candidate 属性和 autowire 属性相互独立,互不相干。某个 Bean 能够将 autowire-candidate 设置为 false,同时使用 autowire 特性。) 另外,咱们能够设置 <beans> 的 default-autowire-candidates 属性,能够在该属性中指定能够用于自动装配候选 Bean 的匹配模式,好比 default-autowire-candidates="*serv,*dao",这表示全部名字以 serv 或者 dao 结尾的 Bean 被列为候选,其余则忽略,至关于其余 Bean 都指定为 autowire-candidate="false",此时能够显式为 <bean> 指定 autowire-candidate="true"。在 <bean> 上指定的设置要覆盖 <beans> 上指定的设置。
若是在多个类型相同的 Bean 中有首选的 Bean,那么能够将该 <bean> 的 primary 属性设置为 "true" ,这样自动装配时便优先使用该 Bean 进行装配。此时不能将 autowire-candidate 设为 false。
若是使用的是 Java 5 以上版本,可使用注解进行更细粒度的控制。
使用 @Autowired 注解进行装配,只能是根据类型进行匹配。@Autowired 注解能够用于 Setter 方法、构造函数、字段,甚至普通方法,前提是方法必须有至少一个参数。@Autowired 能够用于数组和使用泛型的集合类型。而后 Spring 会将容器中全部类型符合的 Bean 注入进来。@Autowired 标注做用于 Map 类型时,若是 Map 的 key 为 String 类型,则 Spring 会将容器中全部类型符合 Map 的 value 对应的类型的 Bean 增长进来,用 Bean 的 id 或 name 做为 Map 的 key。
@Autowired 标注做用于普通方法时,会产生一个反作用,就是在容器初始化该 Bean 实例的时候就会调用该方法。固然,前提是执行了自动装配,对于不知足装配条件的状况,该方法也不会被执行。
当标注了 @Autowired 后,自动注入不能知足,则会抛出异常。咱们能够给 @Autowired 标注增长一个 required=false 属性,以改变这个行为。另外,每个类中只能有一个构造函数的 @Autowired.required() 属性为 true。不然就出问题了。若是用 @Autowired 同时标注了多个构造函数,那么,Spring 将采用贪心算法匹配构造函数 ( 构造函数最长 )。
@Autowired 还有一个做用就是,若是将其标注在 BeanFactory 类型、ApplicationContext 类型、ResourceLoader 类型、ApplicationEventPublisher 类型、MessageSource 类型上,那么 Spring 会自动注入这些实现类的实例,不须要额外的操做。
当容器中存在多个 Bean 的类型与须要注入的相同时,注入将不能执行,咱们能够给 @Autowired 增长一个候选值,作法是在 @Autowired 后面增长一个 @Qualifier 标注,提供一个 String 类型的值做为候选的 Bean 的名字。举例以下:
@Autowired(required=false) @Qualifier("ppp") public void setPerson(person p){}
@Qualifier 甚至能够做用于方法的参数 ( 对于方法只有一个参数的状况,咱们能够将 @Qualifer 标注放置在方法声明上面,可是推荐放置在参数前面 ),举例以下:
@Autowired(required=false) public void sayHello(@Qualifier("ppp")Person p,String name){}
咱们能够在配置文件中指定某个 Bean 的 qualifier 名字,方法以下:
<bean id="person" class="footmark.spring.Person"> <qualifier value="ppp"/> </bean>
若是没有明确指定 Bean 的 qualifier 名字,那么默认名字就是 Bean 的名字。一般,qualifier 应该是有业务含义的,例如 "domain","persistent" 等,而不该该是相似 "person" 方式。
咱们还能够将 @Qualifier 标注在集合类型上,那么全部 qualifier 名字与指定值相同的 Bean 都将被注入进来。
最后,配置文件中须要指定每个自定义注解的属性值。咱们可使用 <meta> 标签来代替 <qualifier/> 标签,若是 <meta> 标签和 <qualifier/> 标签同时出现,那么优先使用 <qualifier> 标签。若是没有 <qualifier> 标签,那么会用 <meta> 提供的键值对来封装 <qualifier> 标签。示例以下:
<bean class="footmark.HelloWorld"> <qualifier type="MovieQualifier"> <attribute key="format" value="VHS"/> <attribute key="genre" value="Comedy"/> </qualifier> </bean> <bean class="footmark.HelloWorld"> <meta key="format" value="DVD"/> <meta key="genre" value="Action"/> </bean>
@Autowired 注解对应的后处理注册与前面类似,只需在配置文件中增长以下一行便可:
<context:annotation-config/>
若是 @Autowired 注入的是 BeanFactory、ApplicationContext、ResourceLoader 等系统类型,那么则不须要 @Qualifier,此时即便提供了 @Qualifier 注解,也将会被忽略;而对于自定义类型的自动装配,若是使用了 @Qualifier 注解而且没有名字与之匹配的 Bean,则自动装配匹配失败。
若是但愿根据 name 执行自动装配,那么应该使用 JSR-250 提供的 @Resource 注解,而不该该使用 @Autowired 与 @Qualifier 的组合。
@Resource 使用 byName 的方式执行自动封装。@Resource 标注能够做用于带一个参数的 Setter 方法、字段,以及带一个参数的普通方法上。@Resource 注解有一个 name 属性,用于指定 Bean 在配置文件中对应的名字。若是没有指定 name 属性,那么默认值就是字段或者属性的名字。@Resource 和 @Qualifier 的配合虽然仍然成立,可是 @Qualifier 对于 @Resource 而言,几乎与 name 属性等效。
若是 @Resource 没有指定 name 属性,那么使用 byName 匹配失败后,会退而使用 byType 继续匹配,若是再失败,则抛出异常。在没有为 @Resource 注解显式指定 name 属性的前提下,若是将其标注在 BeanFactory 类型、ApplicationContext 类型、ResourceLoader 类型、ApplicationEventPublisher 类型、MessageSource 类型上,那么 Spring 会自动注入这些实现类的实例,不须要额外的操做。此时 name 属性不须要指定 ( 或者指定为""),不然注入失败;若是使用了 @Qualifier,则该注解将被忽略。而对于用户自定义类型的注入,@Qualifier 和 name 等价,而且不被忽略。
<bean> 的 primary 和 autowire-candidate 属性对 @Resource、@Autowired 仍然有效。
虽然 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 配置中的 <bean/> 标签。示例以下:
@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 id=”userDao” class=”bookstore.dao.UserDaoImpl”/> <bean id=”bookDao” class=”bookstore.dao.BookDaoImpl”/>
@Bean 具备如下四个属性:
name -- 指定一个或者多个 Bean 的名字。这等价于 XML 配置中 <bean> 的 name 属性。
initMethod -- 容器在初始化完 Bean 以后,会调用该属性指定的方法。这等价于 XML 配置中 <bean> 的 init-method 属性。
destroyMethod -- 该属性与 initMethod 功能类似,在容器销毁 Bean 以前,会调用该属性指定的方法。这等价于 XML 配置中 <bean> 的 destroy-method 属性。
autowire -- 指定 Bean 属性的自动装配策略,取值是 Autowire 类型的三个静态属性。Autowire.BY_NAME,Autowire.BY_TYPE,Autowire.NO。与 XML 配置中的 autowire 属性的取值相比,这里少了 constructor,这是由于 constructor 在这里已经没有意义了。
@Bean 没有直接提供指定做用域的属性,能够经过 @Scope 来实现该功能,关于 @Scope 的用法已在上文列举。
下面讲解基于注解的容器初始化。AnnotationConfigApplicationContext 提供了三个构造函数用于初始化容器。
AnnotationConfigApplicationContext():该构造函数初始化一个空容器,容器不包含任何 Bean 信息,须要在稍后经过调用其 register() 方法注册配置类,并调用 refresh() 方法刷新容器。
AnnotationConfigApplicationContext(Class<?>... annotatedClasses):这是最经常使用的构造函数,经过将涉及到的配置类传递给该构造函数,以实现将相应配置类中的 Bean 自动注册到容器中。
AnnotationConfigApplicationContext(String... basePackages):该构造函数会自动扫描以给定的包及其子包下的全部类,并自动识别全部的 Spring Bean,将其注册到容器中。它不但识别标注 @Configuration 的配置类并正确解析,并且一样能识别使用 @Repository、@Service、@Controller、@Component 标注的类。
除了使用上面第三种类型的构造函数让容器自动扫描 Bean 的配置信息之外,AnnotationConfigApplicationContext 还提供了 scan() 方法,其功能与上面也相似,该方法主要用在容器初始化以后动态增长 Bean 至容器中。调用了该方法之后,一般须要当即手动调用 refresh() 刷新容器,以让变动当即生效。
须要注意的是,AnnotationConfigApplicationContext 在解析配置类时,会将配置类自身注册为一个 Bean,由于 @Configuration 注解自己定义时被 @Component 标注了。所以能够说,一个 @Configuration 同时也是一个 @Component。大多数状况下,开发者用不到该 Bean,而且在理想状况下,该 Bean 应该是对开发者透明的。@Configuration 的定义以下所示:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration { String value() default ""; }
在通常的项目中,为告终构清晰,一般会根据软件的模块或者结构定义多个 XML 配置文件,而后再定义一个入口的配置文件,该文件使用 <import/> 将其余的配置文件组织起来。最后只需将该文件传给 ClassPathXmlApplicationContext 的构造函数便可。针对基于注解的配置,Spring 也提供了相似的功能,只需定义一个入口配置类,并在该类上使用 @Import 注解引入其余的配置类便可,最后只须要将该入口类传递给 AnnotationConfigApplicationContext。具体示例以下:
@Configuration @Import({BookStoreServiceConfig.class,BookStoreDaoConfig.class}) public class BookStoreConfig{ … }
设计 @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>,同时注册处理注解的 Bean 后处理器便可。示例以下:
// 假设存在以下的 @Configuration 类: package bookstore.config; import bookstore.dao.*; @Configuration public class MyConfig{ @Bean public UserDao userDao(){ return new UserDaoImpl(); } } 此时,只需在 XML 中做以下声明便可: <beans … > …… <context:annotation-config /> <bean class=”demo.config.MyConfig”/> </beans>
因为启用了针对注解的 Bean 后处理器,所以在 ApplicationContext 解析到 MyConfig 类时,会发现该类标注了 @Configuration 注解,随后便会处理该类中标注 @Bean 的方法,将这些方法的返回值注册为容器总的 Bean。
对于以上的方式,若是存在多个标注了 @Configuration 的类,则须要在 XML 文件中逐一列出。另外一种方式是使用前面提到的自动扫描功能,配置以下:
<context:component-scan base-package=”bookstore.config” />
如此,Spring 将扫描全部 demo.config 包及其子包中的类,识别全部标记了 @Component、@Controller、@Service、@Repository 注解的类,因为 @Configuration 注解自己也用 @Component 标注了,Spring 将可以识别出 @Configuration 标注类并正确解析之。
对于以注解为中心的配置方式,只需使用 @ImportResource 注解引入存在的 XML 便可,以下所示:
@Configuration @ImportResource(“classpath:/bookstore/config/spring-beans.xml”) public class MyConfig{ …… } // 容器的初始化过程和纯粹的以配置为中心的方式一致: AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class); ……
从 2.0 版本开始,Spring 的每一次更新都会提供更多新的注解供开发者使用。这知足了注解爱好者的胃口。可是正如前面所说,Spring 提供更多的注解并非为了有朝一日取代 XML 配置方式,而是为了给开发者多一种选择。两种声明 Bean 的方式各有特点,XML 方式更加灵活,而且发展的相对成熟,这种配置方式为大多数 Spring 开发者熟悉;注解方式使用起来很是简洁,可是尚处于发展阶段。咱们很难说两种配置方式孰优孰劣,可是若是可以灵活搭配两种方式,必定可以进一步提高开发效率。