本节书摘来自异步社区《Spring攻略(第2版)》一书中的第1章,第1.12节,作者: 【美】Gary Mak , Josh Long , Daniel Rubio著,更多章节内容可以访问云栖社区“异步社区”公众号查看
1.12.1 问题在Bean配置文件中设置autowire属性进行的自动装配将装配一个Bean的所有属性。这样的灵活性不足以仅仅装配特定的属性。而且,你只能通过类型或者名称自动装配Bean。如果这两种策略都不能满足你的需求,就必须明确地装配Bean。
1.12.2 解决方案从Spring 2.5起,自动装配功能进行了多处改进。你可以通过用@Autowired或者@Resource(在JSR-250:Java平台常见注解中定义)注解一个设值方法、构造程序、字段甚至任意方法自动装配特定的属性。这意味着你除了设置autowire属性之外,还有一个能够满足需求的选择。但是,这种基于注解的选项要求你使用Java 1.5或者更高版本。
1.12.3 工作原理为了要求Spring自动装配具有@Autowired或者@Resource注解的属性,你必须在IoC容器中注册一个AutowiredAnnotationBeanPostProcessor实例。如果你使用一个Bean工厂,就必须通过API注册这个Bean后处理器,否则,你只能在你的应用上下文里声明一个实例。
<bean class="org.springframework.beans.factory.annotation. AutowiredAnnotationBeanPostProcessor" />你也可以简单地在Bean配置文件中包含元素,这将自动注册一个AutowiredAnnotationBeanPostProcessor实例。
<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"> <context:annotation-config /> ... </beans>自动装配一个兼容类型的Bean@Autowired可以应用到一个特定的需要Spring自动装配的属性。例如,你可以用@Autowired注解prefixGenerator属性的设值方法。然后,Spring将试图装配一个类型与prefixGenerator兼容的Bean。
package com.apress.springrecipes.sequence; import org.springframework.beans.factory.annotation.Autowired; public class SequenceGenerator { ... @Autowired public void setPrefixGenerator(PrefixGenerator prefixGenerator) { this.prefixGenerator = prefixGenerator; } }如果你在IoC容器中定义了一个与PrefixGenerator类型兼容的Bean,它将自动地设置到PrefixGenerator属性上。
<beans ...> ... <bean id="sequenceGenerator" class="com.apress.springrecipes.sequence.SequenceGenerator"> <property name="initial" value="100000" /> <property name="suffix" value="A" /> </bean> <bean id="datePrefixGenerator" class="com.apress.springrecipes.sequence.DatePrefixGenerator"> <property name="pattern" value="yyyyMMdd" /> </bean> </beans>默认情况下,所有带有@Autowired的属性都是必需的。当Spring不能找到匹配的Bean进行装配时,将会抛出一个异常。如果你希望某个属性是可选的,将@Autowired的required属性设置为false。之后,当Spring找不到匹配的Bean,将不设置该属性。
package com.apress.springrecipes.sequence; import org.springframework.beans.factory.annotation.Autowired; public class SequenceGenerator { ... @Autowired(required = false) public void setPrefixGenerator(PrefixGenerator prefixGenerator) { this.prefixGenerator = prefixGenerator; } }除了设值方法之外,@Autowired注解还可以应用到构造程序,Spring将为每个构造程序参数寻找一个具有兼容类型的Bean。
package com.apress.springrecipes.sequence; import org.springframework.beans.factory.annotation.Autowired; public class SequenceGenerator { ... @Autowired public SequenceGenerator(PrefixGenerator prefixGenerator) { this.prefixGenerator = prefixGenerator; } }@Autowired注解还可以应用到一个字段,即使这个字段没有声明为Public。这样,你不能省略这个字段的设值方法或者构造程序的声明。Spring将通过反射把匹配的Bean注入这个字段。但是,用@Autowired注解非公开的字段将降低代码的可测试性,因为代码将很难进行单元测试(黑盒测试法无法使用模拟对象之类的方式操纵这一状态)。
package com.apress.springrecipes.sequence; import org.springframework.beans.factory.annotation.Autowired; public class SequenceGenerator { @Autowired private PrefixGenerator prefixGenerator; ... }你甚至可以将@Autowired注解应用到具有任意名称和任意数量参数的方法上,在这种情况下,Spring将试图为每个方法参数装配一个类型兼容的Bean。
package com.apress.springrecipes.sequence; import org.springframework.beans.factory.annotation.Autowired; public class SequenceGenerator { ... @Autowired public void inject(PrefixGenerator prefixGenerator) { this.prefixGenerator = prefixGenerator; } }自动装配所有兼容类型的Bean@Autowired注解还可以应用到一个数组类型的属性上,让Spring自动装配所有匹配的Bean。例如,你可以用@Autowired注解一个PrefixGenerator[]属性。然后,Spring将一次性自动装配所有类型与PrefixGenerator兼容的Bean。
package com.apress.springrecipes.sequence; import org.springframework.beans.factory.annotation.Autowired; public class SequenceGenerator { @Autowired private PrefixGenerator[] prefixGenerators; ... }如果你在IoC容器中有多个类型与PrefixGenerator兼容类型的Bean,它们将自动被添加到PrefixGenerators数组中。
<beans ...> ... <bean id="datePrefixGenerator" class="com.apress.springrecipes.sequence.DatePrefixGenerator"> <property name="pattern" value="yyyyMMdd" /> </bean> <bean id="yearPrefixGenerator" class="com.apress.springrecipes.sequence.DatePrefixGenerator"> <property name="pattern" value="yyyy" /> </bean> </beans>相似地,你可以将@Autowired注解应用类型安全的集合。Spring能够读取这个集合的类型信息,自动装配所有类型兼容的Bean。
package com.apress.springrecipes.sequence; import org.springframework.beans.factory.annotation.Autowired; public class SequenceGenerator { @Autowired private List<PrefixGenerator> prefixGenerators; ... }如果Spring注意到@Autowired注解应用到了一个关键字为字符串的类型安全java.util.Map,它将在这个Map中添加所有Bean名称与关键字相同的兼容类型Bean。
package com.apress.springrecipes.sequence; import org.springframework.beans.factory.annotation.Autowired; public class SequenceGenerator { @Autowired private Map<String, PrefixGenerator> prefixGenerators; ... }使用限定符的按类型自动装配默认情况下,按照类型的自动装配在IoC容器中有超过一个类型兼容的Bean时无效。但是,Spring允许你指定一个候选Bean,这个Bean的名称在@Qualifier注解中提供。
package com.apress.springrecipes.sequence; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; public class SequenceGenerator { @Autowired @Qualifier("datePrefixGenerator") private PrefixGenerator prefixGenerator; ... }完成了这项工作,Spring将会试图在IoC容器中查找一个具有这个名称的Bean,将其装配到这个属性中。
<bean id="datePrefixGenerator" class="com.apress.springrecipes.sequence.DatePrefixGenerator"> <property name="pattern" value="yyyyMMdd" /> </bean> @Qualifier注解也可以应用到方法参数中进行自动装配。 package com.apress.springrecipes.sequence; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; public class SequenceGenerator { ... @Autowired public void inject( @Qualifier("datePrefixGenerator") PrefixGenerator prefixGenerator) { this.prefixGenerator = prefixGenerator; } }你可以为自动装配创建一个自定义的限定符注解类型。这种注解类型必须用@Qualifier注解。如果你希望一种特殊的Bean和配置在注解装饰字段或者设值方法时注入,那么就可以使用这种注解类型。
package com.apress.springrecipes.sequence; import java.lang.annotation.Target; import java.lang.annotation.Retention; import java.lang.annotation.ElementType; import java.lang.annotation.RetentionPolicy;import org.springframework.beans.factory.annotation.Qualifier; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.PARAMETER }) @Qualifier public @interface Generator { String value(); }之后,你可以将这个注解应用到@Autowired bean属性。这将要求Spring自动装配带有这个限定符注解和特定值的Bean。
package com.apress.springrecipes.sequence; import org.springframework.beans.factory.annotation.Autowired; public class SequenceGenerator { @Autowired @Generator("prefix") private PrefixGenerator prefixGenerator; ... }你必须向希望自动装配到前述的属性中的目标Bean提供这个限定符。限定符由带有type属性的元素添加。限定符值在value属性中指定。Value属性映射到注解的String value()属性。
<bean id="datePrefixGenerator" class="com.apress.springrecipes.sequence.DatePrefixGenerator"> <qualifier type="Generator" value="prefix" /> <property name="pattern" value="yyyyMMdd" /> </bean>按照名称自动装配如果你希望按照名称自动装配Bean属性,可以用JSR-250 @Resource注解为一个设值方法、构造程序或者字段加上注解。默认情况下,Spring将试图找到一个与属性同名的Bean。但是你可以显式地在name属性中指定Bean名称。
注:
为了使用JSR-250注解,你必须包含JSR 250依赖。如果你使用Maven,添加以下内容:
<dependency> <groupId>javax.annotation</groupId> <artifactId>jsr250-api</artifactId> <version>1.0</version> </dependency> package com.apress.springrecipes.sequence; import javax.annotation.Resource; public class SequenceGenerator { @Resource(name = "datePrefixGenerator") private PrefixGenerator prefixGenerator; ... } 相关资源:敏捷开发V1.0.pptx