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

简介: @Autowired注解还可以应用到一个字段,即使这个字段没有声明为Public。这样,你不能省略这个字段的设值方法或者构造程序的声明。Spring将通过反射把匹配的Bean注入这个字段。但是,用@Autowired注解非公开的字段将降低代码的可测试性,因为代码将很难进行单元测试(黑盒测试法无法使用模拟对象之类的方式操纵这一状态)。

本节书摘来自异步社区《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;
   ...
}
相关文章
|
6月前
|
安全 Java 决策智能
Spring Boot自动装配
Spring Boot自动装配基于“约定优于配置”理念,通过条件化配置与Starters机制,智能推断并加载所需组件,大幅简化开发流程。它实现配置自动化,提升效率,降低维护成本,支持自定义扩展,推动微服务快速构建,是Java生态中开发范式的革新之作。(238字)
|
6月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
675 2
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
942 26
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
424 12
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
557 12
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
1146 4
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
495 6
|
XML Java 数据格式
🌱 深入Spring的心脏:Bean配置的艺术与实践 🌟
本文深入探讨了Spring框架中Bean配置的奥秘,从基本概念到XML配置文件的使用,再到静态工厂方式实例化Bean的详细步骤,通过实际代码示例帮助读者更好地理解和应用Spring的Bean配置。希望对你的Spring开发之旅有所助益。
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
383 1