《Spring攻略(第2版)》——1.12 用@Autowired和@Resource自动装配Bean

本节书摘来自异步社区《Spring攻略(第2版)》一书中的第1章,第1.12节,作者: 【美】Gary Mak , Josh Long , Daniel Rubio著,更多章节内容可以访问云栖社区“异步社区”公众号查看

1.12 用@Autowired和@Resource自动装配Bean

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;
   ...
}
上一篇:详细的正则表达式


下一篇:Palo Alto Networks与普华永道共同建立漏洞防护安全机制