3.3 自动检查 Bean
<context:annotation-config />
可以帮助我们完全消除Spring配置中的<property>
和<constructor-arg>
元素,我们仍需要使用<bean>
元素显式定义Bean。
<context:component-scan>
元素除了能完成与<context:annotation-config />
一样的工作外,还允许Spring自动检测 Bean 和定义Bean。这以为着不使用<bean>
元素,spring应用中的大多数(或者所有)Bean都能够实现定义和装配。
<context:component-scan>
元素会扫描指定的包及其所有子包,并查找出能够自动注册为Spring Bean的类。base-package属性标识了<context:component-scan>
元素所扫描的包。
注:base-package属性中的值只能精确到包,不能通过”.*”来精确到类,否则会找不到Bean
3.3.1 为自动检测标注Bean
默认情况下,<context:component-scan>
元素查找使用构造型(stereotype)注解所标注的类,这些特殊的注解如下:
注解 | 说明 |
---|---|
@Component | 通用的构造型注解,标识该类为Spring组件。 |
@Controller | 标识将该类定义为 Spring MVC controller。 |
@Repository | 标识将该类定义为数据仓库。 |
@Service | 标识将该类定义为服务。 |
/**
* Spring 扫描包时,会发现使用 @Component 注解所标注的Guitar,并自动地将它注册为 Spring Bean。Bean的ID默认为无限定类名。
*/
package com.springinaction.springidol;
import org.springframework.stereotype.Component
@Component
public class Guitar implements Instrument{
...
}
/**
* 指定 Bean ID 作为 @Component 注解的参数。该 Bean 的 ID 不会被默认设置为类的名称 "instrumentalist",而是显示的命名为 eddie 。
*/
package com.springinaction.springidol;
import org.springframework.stereotype.Component
@Component("eddie")
public class Instrumentalist implements Performer {
//...
}
3.3.2 过滤组件扫描
通过为 <context:component-scan>
配置 <context:include-filter>
和/或者 <context:exclude-filter>
子元素,我们可以随意调整扫描行为。
<!-- <context:include-filter>的type和expression属性一起协作来定义组件扫描策略。在这种情况下,我们要求派生于Instrument的所有类自动注册为Spring Bean。 -->
<context:component-scan base-package="com.springinaction.springidol">
<context:include-filter type="assignable" expression="com.springinaction.springidol.Instrument" />
</context:component-scan>
<!-- 除了使用自定义 @SkipIt 注解的类,其他所有的Instrument实现都需要注册为 Spring Bean。 -->
<context:component-scan base-package="com.springinaction.springidol">
<context:include-filter type="assignable" expression="com.springinaction.springidol.Instrument" />
<context:exclude-filter type="annotation" expression="com.springinaction.springidol.SkipIt"/>
</context:component-scan>
使用5种过滤器类型的任意一种来自定义组件扫描方式:
过滤器类型 | 描述 |
---|---|
annotation | 过滤器扫描使用指定注解所标注的那些类,通过 expression 属性指定要扫描的注解 |
assignable | 过滤器扫描派生于expression属性所指定类型的那些类 |
aspectj | 过滤器扫描与expression属性所指定的AspectJ表达式所匹配的那些类 |
custom | 使用自定义的 org.springframework.core.type.TypeFilter 实现类,该类由expression属性指定 |
regex | 过滤器扫描类的名称与 expression 属性所指定的正则表达式所匹配的那些类 |
3.4 使用 Spring 基于 Java 的配置
Spring 3.0 提供使用Java代码来配置 Spring 应用的方式。
3.4.1 创建基于Java的配置
使用极少量的XML来启用Java配置:
<!-- <context:component-scan>会自动加载使用 @Configuration 注解所标注的类。在该示例中,base-package属性告知 Spring 在 com.springinaction.springidol 包内查找使用 @Configuration 注解所标注的所有类。 -->
<?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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd" default-lazy-init="true">
<context:component-scan base-package="com.springinaction.springidol" />
</beans>
3.4.2 定义一个配置类
在基于 Java 的配置里使用 @Configuration 注解的 Java 类,就等价与 XML 配置中的 <beans>
元素。@Configuration 注解会作为一个标识告知Spring:这个类将包含一个或多个 Spring Bean 的定义。这些 Bean 的定义是使用 @Bean 注解所标注的方法。
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringIdolConfig {
// Bean declaration methods go here
}
3.4.3 声明一个简单的Bean
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringIdolConfig {
<!-- 基于Java的配置来装配 Bean ID 为 "duke" 的Bean -->
@Bean
public Performer duke(){
return new Juggler();
}
}
3.4.4 使用 Spring 的基于 Java 的配置进行注入
//示例1,注入数值型参数15
@Bean
public Performer duke15(){
return new Juggler(15);
}
//示例2,注入字符串型参数
@Bean
public Performer kenny(){
Instrumentalist kenny = new Instrumentslist();
kenny.setSong("Jingle Bells");
return kenny;
}
//示例3,注入其他Bean引用。在 Spring 的 Java 配置中,通过声明方法引用一个 Bean 并不等同于调用该方法。通过使用 @Bean 注解标注 sonnet29() 方法,会告知 Spring 我们希望该方法定义的 Bean 要被注册进 Spring 的应用上下文中。因此,在其他 Bean 的声明方法中引用这个方法时,Spring 都会拦截该方法的调用,并尝试在应用上下文查找该 Bean,而不是让方法创建一个新的实例。
@Bean
private Poem sonnet29(){
return new Sonnet29();
}
@Bean
public Performer poeticDuke(){
return new PoeticJuggler(sonnet29());
}