Spring提供了几种技巧,可以减少XML的配置数量:
- 自动装配(autowiring):可以减少
<property>
和<constructor-arg>
元素,让Spring自动识别如何装配Bean的依赖关系; - 自动检测(autodiscovery):Spring能够自动识别哪些类需要被装配成Spring Bean,从而减少对
<bean>
的使用。
自动装配Bean属性
4种自动装配
- byName:把与Bean属性具有相同名字(或id)的其他Bean自动装配到Bean的对应属性中;
- byType:把与Bean属性具有相同类型的其他Bean自动装配到Bean的对应属性中;
- constructor:把与Bean的构造函数的入参具有相同类型的其他Bean自动装配到Bean的构造函数对应的入参中;
- autodetect:先尝试使用constructor,失败后再使用byType。
byName
为属性自动装配id与该属性的名字相同的Bean。使用方法:1
2
3<bean id="kenny" class="com.springinaction.springidol.Instrumentalist" autowire="byName">
<property name="song" value="Happy" />
</bean>
通过配置Bean Kenny的autowire="byName"
属性,Spring就可以利用此信息自动装配Kenny的instrument属性了。
缺点:需要假设Bean的名字(如instrument)与其他Bean的属性的名字一样,若其他多个Bean的属性都是instrument,那么让他们将使用同一个instrument。
byType
当Spring根据类型匹配到多个Bean时,会抛出异常,形如:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘kenny’ defined in class path resource [spring-idol.xml]: Unsatisfied dependency expressed through bean property ‘instrument’: : No qualifying bean of type [com.springinaction.springidol.Instrument] is defined: expected single matching bean but found 2: saxphone,guitar;
为了避免这种异常(expected single matching bean but found 2)的出现,Spring提供了两种方案:可以自动装配标识一个首选Bean,或者可以取消某个Bean的自动装配的候选资格。
标识首选Bean:primary=”true”
可以使用primary属性将Bean设置为首选Bean,那么它将会得到优选被选择权:1
2
3
4
5
6
7<bean id="saxphone" class="com.springinaction.springidol.Saxophone" />
<bean id="guitar" class="com.springinaction.springidol.Guitar" primary="true"/>
<bean id="kenny" class="com.springinaction.springidol.Instrumentalist"
autowire="byType">
<property name="song" value="Happy" />
</bean>
有两个Bean类型满足kenny的instrument属性,但是guitar设置了primary="true"
,因此会注入guitar。
排除其他Bean: autowire-candidate=”false”
1 | <bean id="saxphone" class="com.springinaction.springidol.Saxophone" autowire-candidate="false"/> |
通过排除其他Bean的候选资格来达到和上面设置primary同样的效果。
constructor
当有多个Bean匹配某个构造函数的入参时,Spring同样会抛出异常。
默认自动装配方式
可以在根元素<beans>
上添加default-autowire
属性来设置该配置文件中的
混用自动装配和显示装配
显示装配会覆盖掉自动装配:1
2
3
4
5
6
7<bean id="saxphone" class="com.springinaction.springidol.Saxophone" autowire-candidate="false"/>
<bean id="guitar" class="com.springinaction.springidol.Guitar"/>
<bean id="kenny" class="com.springinaction.springidol.Instrumentalist"
autowire="byType">
<property name="song" value="Happy" />
<property name="instrument" ref="saxphone"></property>
</bean>
虽然取消了saxphone的候选资格,但最终仍是saxphone注入到了kenny的属性中。
注意
当使用constructor自动装配时,就不能混合使用constructor自动装配和
使用注解装配
启用注解装配:<context:annotation-config />
。
- Spring自带的@Autowired注解
- JSR-330的@Inject注解
- JSR-250的@Resource注解
@Autowired
使用方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// 1、可以标注setter
public void setInstrument(Instrument instrument) {
this.instrument = instrument;
}
// 2、标注其他方法
public void heresYourInstrument(Instrument instrument) {
this.instrument = instrument;
}
// 3、标注构造器
public Instrumentalist(Instrument instrument) {
this.instrument = instrument;
}
// 4、直接标注属性
private Instrument instrument;
使用@Autowired进行自动装配时,在遇到多个匹配的Bean或者没有匹配的Bean也会出现问题。
可选的自动装配
通过设置@Autowired的required属性为false来配置可选。1
2false) (required=
private Instrument instrument;
这时,若没有找到匹配到的instrument Bean,应用也不会出现异常,instrument会被设置为null。
注意:
当使用构造器装配时,只有一个构造器可以将@Autowired的required属性设置为true,其他使用@Autowired注解的required属性必须设置为false。此外,当使用@Autowired标注多个构造器时,Spring会从所有满足装配条件的构造器中选择入参最多的那个。
限制歧义性的依赖
当有多个Bean满足装配条件时,可以配合使用@Qualifier
注解。1
2
3
"guitar") (
private Instrument instrument;
@Qualifier
注解缩小了自动装配候选Bean的范围。
@Inject
和@Autowired一样,@Inject可以装配 属性、方法和构造器;但是@Inject没有required属性,因此@Inject注解所依赖的bean是必须存在的,如果不存在就会抛出异常。
使用@Inject注入一个Provider,从而可以实现Bean引用的延迟注入以及注入多个Bean实例的功能。
1 | private Set<Knife> knives; |
KnifeJuggler类需要注入多个Knife实例,假设Knife Bean的作用域是prototype的,那么KnifeJuggler将获得一个Provider
限定@Inject所注入的属性:@Named
1 |
|
在注解中使用表达式:@Value
可以使用@Value装配简单值:String类型和基本类型,如:1
2"Happy") (
private String song;
@Value可以配合SpEL使用:1
2"#{systemProperties.myFavoriteSong}") (
private String song;
#自动检测Bean:
使用<context:component-scan base-package="com.springinaction.springidol"/>
标注Bean
- @Component:通用的构造型注解,标识该类为Spring组件;
- @Controller:标识该类为Spring MVC controller;
- @Repository:标识为数据仓库;
- @Service:标识为服务;
- @Component:标注为自定义注解。
1 | package com.springinaction.springidol; |
Spring扫描com.springinaction.springidol包时,会发现使用@Component注解所标注的Guitar,会自动将它注册为Spring Bean,其id会是guitar。
定义组件扫描策略
过滤器类型 | 描述 |
---|---|
annotation | 扫描使用指定注解所标注的类,通过expression属性指定要扫描的注解 |
assignable | 扫描派生于expression属性所指定类型的那些类 |
aspectj | 扫描与expression属性所指定的AspectJ表达式多匹配的那些类 |
custom | 使用自定义的org.springframework.core.type.TypeFilter实现类,该类由expression属性指定 |
regex | 扫描类名称与expression属性所指定的正则表达式所匹配的类 |
以下配置实现了:自动注册所有实现了Instrument接口的类,并且排除使用自定义@SkipIt注解的类。
1 | <context:component-scan base-package="com.springinaction.springidol"> |