核心技术
Core Technologies
This part of the reference documentation covers all the technologies that are absolutely integral to the Spring Framework.
这部分参考文档涵盖了所有对于Spring框架至关重要的技术。
Foremost amongst these is the Spring Framework’s Inversion of Control (IoC) container. A thorough treatment of the Spring Framework’s IoC container is closely followed by comprehensive coverage of Spring’s Aspect-Oriented Programming (AOP) technologies. The Spring Framework has its own AOP framework, which is conceptually easy to understand and which successfully addresses the 80% sweet spot of AOP requirements in Java enterprise programming.
其中最重要的是Spring框架的控制反转(IoC)容器。对Spring框架的IoC容器进行了全面的介绍,紧接着是对Spring面向切面编程(AOP)技术的全面覆盖。Spring框架拥有自己的AOP框架,概念上易于理解,并且成功地解决了Java企业编程中80%的AOP需求。
Coverage of Spring’s integration with AspectJ (currently the richest — in terms of features — and certainly most mature AOP implementation in the Java enterprise space) is also provided.
还介绍了Spring与AspectJ的集成(目前在Java企业领域中功能最丰富且最成熟的AOP实现)。
AOT processing can be used to optimize your application ahead-of-time. It is typically used for native image deployment using GraalVM.
AOT处理可用于提前优化应用程序。通常用于使用GraalVM进行本地镜像部署。
1、Spring IOC 容器
The IoC Container
1.1 Spring IOC 容器与Beans介绍
# Introduction to the Spring IoC Container and Beans
This chapter covers the Spring Framework implementation of the Inversion of Control (IoC) principle. IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies (that is, the other objects they work with) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes or a mechanism such as the Service Locator pattern.
本章介绍了Spring框架对控制反转(IoC)原则的实现。IoC也被称为依赖注入(DI)。它是一种对象通过构造函数参数、工厂方法参数或在对象实例构造或从工厂方法返回后设置的属性来定义它们的依赖关系(即与其一起工作的其他对象)的过程。然后容器在创建Bean时注入这些依赖关系。这个过程基本上是Bean本身通过直接构造类或使用Service Locator模式等机制来控制其依赖项的实例化或定位的反向(因此命名为控制反转)。
The org.springframework.beans and org.springframework.context packages are the basis for Spring Framework’s IoC container. The BeanFactory interface provides an advanced configuration mechanism capable of managing any type of object. ApplicationContext is a sub-interface of BeanFactory. It adds:
- Easier integration with Spring’s AOP features
- Message resource handling (for use in internationalization)
- Event publication
- Application-layer specific contexts such as the WebApplicationContext for use in web applications.
org.springframework.beans和org.springframework.context包是Spring框架IoC容器的基础。BeanFactory接口提供了一种高级配置机制,能够管理任何类型的对象。ApplicationContext是BeanFactory的子接口。它增加了:
- 与Spring的AOP功能更容易集成
- 消息资源处理(用于国际化)
- 事件发布
- 用于Web应用程序的WebApplicationContext等应用程序特定上下文。
In short, the BeanFactory provides the configuration framework and basic functionality, and the ApplicationContext adds more enterprise-specific functionality. The ApplicationContext is a complete superset of the BeanFactory and is used exclusively in this chapter in descriptions of Spring’s IoC container. For more information on using the BeanFactory instead of the ApplicationContext, see the section covering the BeanFactory API.
简而言之,BeanFactory提供了配置框架和基本功能,而ApplicationContext添加了更多的企业特定功能。ApplicationContext是BeanFactory的完整超集,并且在本章中专门用于描述Spring的IoC容器。有关使用BeanFactory而不是ApplicationContext的更多信息,请参阅涵盖BeanFactory API的部分。
In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application. Beans, and the dependencies among them, are reflected in the configuration metadata used by a container.
在Spring中,由Spring IoC容器管理的构成应用程序骨干的对象被称为Bean。Bean是由Spring IoC容器实例化、组装和管理的对象。否则,Bean只是应用程序中的众多对象之一。Bean及其之间的依赖关系在容器使用的配置元数据中反映出来。
1.2 容器概述
Container Overview
The org.springframework.context.ApplicationContext interface represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the beans. The container gets its instructions on what objects to instantiate, configure, and assemble by reading configuration metadata. The configuration metadata is represented in XML, Java annotations, or Java code. It lets you express the objects that compose your application and the rich interdependencies between those objects.
org.springframework.context.ApplicationContext接口代表Spring IoC容器,负责实例化、配置和组装bean。容器通过读取配置元数据来获取关于实例化、配置和组装对象的指令。配置元数据可以用XML、Java注解或Java代码表示。它允许您表达组成应用程序的对象以及这些对象之间的丰富相互依赖关系。
Several implementations of the ApplicationContext interface are supplied with Spring. In stand-alone applications, it is common to create an instance of ClassPathXmlApplicationContext or FileSystemXmlApplicationContext. While XML has been the traditional format for defining configuration metadata, you can instruct the container to use Java annotations or code as the metadata format by providing a small amount of XML configuration to declaratively enable support for these additional metadata formats.
Spring提供了多个ApplicationContext接口的实现。在独立应用程序中,通常会创建ClassPathXmlApplicationContext或FileSystemXmlApplicationContext的实例。虽然XML一直是定义配置元数据的传统格式,但您可以通过提供少量的XML配置来声明性地启用对Java注解或代码的支持,从而指示容器使用Java注解或代码作为元数据格式。
In most application scenarios, explicit user code is not required to instantiate one or more instances of a Spring IoC container. For example, in a web application scenario, a simple eight (or so) lines of boilerplate web descriptor XML in the web.xml file of the application typically suffices (see Convenient ApplicationContext Instantiation for Web Applications). If you use the Spring Tools for Eclipse (an Eclipse-powered development environment), you can easily create this boilerplate configuration with a few mouse clicks or keystrokes.
在大多数应用程序场景中,通常不需要显式用户代码来实例化一个或多个Spring IoC容器的实例。例如,在Web应用程序场景中,通常只需在应用程序的web.xml文件中添加几行简单的样板web描述符XML即可(请参阅方便的Web应用程序的ApplicationContext实例化)。如果您使用Spring Tools for Eclipse(基于Eclipse的开发环境),您可以轻松地通过几次鼠标点击或按键来创建这个样板配置。
The following diagram shows a high-level view of how Spring works. Your application classes are combined with configuration metadata so that, after the ApplicationContext is created and initialized, you have a fully configured and executable system or application.
如下图显示了Spring的高级视图。您的应用程序类与配置元数据结合在一起,因此在创建和初始化ApplicationContext之后,您将拥有一个完全配置和可执行的系统或应用程序。
1.2.1 配置元数据
Configuration Metadata
As the preceding diagram shows, the Spring IoC container consumes a form of configuration metadata. This configuration metadata represents how you, as an application developer, tell the Spring container to instantiate, configure, and assemble the objects in your application.
如先前上图所示,Spring IoC容器使用一种配置元数据。这个配置元数据代表了作为应用程序开发者,您告诉Spring容器如何实例化、配置和组装应用程序中的对象。
Configuration metadata is traditionally supplied in a simple and intuitive XML format, which is what most of this chapter uses to convey key concepts and features of the Spring IoC container.
传统上,配置元数据以一种简单直观的XML格式提供,这也是本章大部分内容用来传达Spring IoC容器的关键概念和特性的方式。
XML-based metadata is not the only allowed form of configuration metadata. The Spring IoC container itself is totally decoupled from the format in which this configuration metadata is actually written. These days, many developers choose Java-based configuration for their Spring applications. For information about using other forms of metadata with the Spring container, see:
基于XML的元数据配置并不是唯一允许的配置元数据形式。Spring IoC容器本身与实际编写配置元数据的格式完全解耦。如今,许多开发者选择使用基于Java的配置来进行Spring应用程序的配置。有关在Spring容器中使用其他形式的元数据的信息,请参阅:
Annotation-based configuration: define beans using annotation-based configuration metadata.
基于注解的配置:使用基于注解的配置元数据定义bean。
Java-based configuration: define beans external to your application classes by using Java rather than XML files. To use these features, see the @Configuration, @Bean, @Import, and @DependsOn annotations.
基于Java的配置:使用Java而不是XML文件在应用程序类之外定义bean。要使用这些功能,请参阅@Configuration、@Bean、@Import和@DependsOn注解。
Spring configuration consists of at least one and typically more than one bean definition that the container must manage. XML-based configuration metadata configures these beans as elements inside a top-level element. Java configuration typically uses @Bean-annotated methods within a @Configuration class.
Spring配置至少包含一个,通常是多个bean定义,容器必须管理这些定义。基于XML的配置元数据将这些bean配置为顶级元素内的元素。基于Java的配置通常使用@Configuration类中的@Bean注解方法。
These bean definitions correspond to the actual objects that make up your application. Typically, you define service layer objects, persistence layer objects such as repositories or data access objects (DAOs), presentation objects such as Web controllers, infrastructure objects such as a JPA EntityManagerFactory, JMS queues, and so forth. Typically, one does not configure fine-grained domain objects in the container, because it is usually the responsibility of repositories and business logic to create and load domain objects.
The following example shows the basic structure of XML-based configuration metadata:
这些bean定义对应于构成您的应用程序的实际对象。通常,您定义服务层对象、持久化层对象(如存储库或数据访问对象(DAO))、表示层对象(如Web控制器)、基础设施对象(如JPA EntityManagerFactory、JMS队列)等。通常,不会在容器中配置细粒度的领域对象,因为创建和加载领域对象通常是存储库和业务逻辑的责任。
以下示例显示了基于XML的配置元数据的基本结构:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
note
- The id attribute is a string that identifies the individual bean definition.
- The class attribute defines the type of the bean and uses the fully qualified class name.
The value of the id attribute can be used to refer to collaborating objects. The XML for referring to collaborating objects is not shown in this example. See Dependencies for more information.
- id属性是一个字符串,用于标识单个bean定义。
- class属性定义了bean的类型,并使用完全限定的类名。
id属性的值可以用于引用协作对象。在此示例中,未显示用于引用协作对象的XML。有关更多信息,请参阅依赖项。
1.2.2 实例化一个容器
Instantiating a Container
The location path or paths supplied to an ApplicationContext constructor are resource strings that let the container load configuration metadata from a variety of external resources, such as the local file system, the Java CLASSPATH, and so on.
ApplicationContext构造函数中提供的位置路径是资源字符串,它允许容器从各种外部资源加载配置元数据,例如本地文件系统、Java CLASSPATH等。
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml", "daos.xml");
After you learn about Spring’s IoC container, you may want to know more about Spring’s Resource abstraction (as described in Resources), which provides a convenient mechanism for reading an InputStream from locations defined in a URI syntax. In particular, Resource paths are used to construct applications contexts, as described in Application Contexts and Resource Paths.
在了解了Spring的IoC容器之后,您可能想进一步了解Spring的资源抽象(如在资源中描述的那样),它提供了一种方便的机制,用于从URI语法中定义的位置读取InputStream。特别是,资源路径用于构建应用程序上下文,如在应用程序上下文和资源路径中所述。
The following example shows the service layer objects (services.xml) configuration file:
下面的示例显示了服务层对象(services.xml)的配置文件:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- services -->
<bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="itemDao" ref="itemDao"/>
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for services go here -->
</beans>
In the preceding example, the service layer consists of the PetStoreServiceImpl class and two data access objects of the types JpaAccountDao and JpaItemDao (based on the JPA Object-Relational Mapping standard). The property name element refers to the name of the JavaBean property, and the ref element refers to the name of another bean definition. This linkage between id and ref elements expresses the dependency between collaborating objects. For details of configuring an object’s dependencies, see Dependencies.
在前面的示例中,服务层由PetStoreServiceImpl类和两个数据访问对象组成,分别是基于JPA对象关系映射标准的JpaAccountDao和JpaItemDao。属性名元素指的是JavaBean属性的名称,而ref元素指的是另一个bean定义的名称。id和ref元素之间的链接表示协作对象之间的依赖关系。有关配置对象依赖项的详细信息,请参阅Dependencies
1.2.3 组合基于XML的配置元数据
Composing XML-based Configuration Metadata
It can be useful to have bean definitions span multiple XML files. Often, each individual XML configuration file represents a logical layer or module in your architecture.
You can use the application context constructor to load bean definitions from all these XML fragments. This constructor takes multiple Resource locations, as was shown in the previous section. Alternatively, use one or more occurrences of the element to load bean definitions from another file or files. The following example shows how to do so:
将bean定义跨多个XML文件可以非常有用。通常,每个单独的XML配置文件代表了架构中的一个逻辑层或模块。
您可以使用应用程序上下文的构造函数从所有这些XML片段加载bean定义。这个构造函数接受多个资源位置,就像前面的部分所示的那样。或者,使用一个或多个元素来从另一个文件或多个文件中加载bean定义。下面的示例展示了如何这样做。
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>
It is possible, but not recommended, to reference files in parent directories using a relative "../" path. Doing so creates a dependency on a file that is outside the current application. In particular, this reference is not recommended for classpath: URLs (for example, classpath:../services.xml), where the runtime resolution process chooses the “nearest” classpath root and then looks into its parent directory. Classpath configuration changes may lead to the choice of a different, incorrect directory.
可以使用相对的"../"路径引用父目录中的文件,但不建议这样做。这样做会创建一个对当前应用程序之外的文件的依赖。特别是对于类路径(classpath:)URLs(例如,classpath:../services.xml),不建议使用此引用,因为运行时解析过程会选择“最近”的类路径根目录,然后查找其父目录。类路径配置的更改可能导致选择不同的、不正确的目录。
You can always use fully qualified resource locations instead of relative paths: for example, file:C:/config/services.xml or classpath:/config/services.xml. However, be aware that you are coupling your application’s configuration to specific absolute locations. It is generally preferable to keep an indirection for such absolute locations — for example, through "${…}" placeholders that are resolved against JVM system properties at runtime.
您总是可以使用完全限定的资源位置,而不是相对路径:例如,file:C:/config/services.xml或classpath:/config/services.xml。但是,请注意,这样做会将应用程序的配置与特定的绝对位置耦合在一起。通常最好为这样的绝对位置保留一个间接引用,例如通过在运行时根据JVM系统属性解析的"${...}"占位符。
The namespace itself provides the import directive feature. Further configuration features beyond plain bean definitions are available in a selection of XML namespaces provided by Spring — for example, the context and util namespaces.
命名空间本身提供了导入指令功能。Spring提供了一些XML命名空间,除了普通的bean定义之外,还提供了更多的配置特性,例如context和util命名空间。
1.2.4 Groovy Bean 定义 DSL
The Groovy Bean Definition DSL.
使用特定领域语言 Groovy 配置Bean定义
As a further example for externalized configuration metadata, bean definitions can also be expressed in Spring’s Groovy Bean Definition DSL, as known from the Grails framework. Typically, such configuration live in a ".groovy" file with the structure shown in the following example:
作为外部化配置元数据的进一步示例,Bean定义也可以使用Spring的Groovy Bean Definition DSL来表示,这在Grails框架中是众所周知的。通常,这样的配置位于一个以".groovy"结尾的文件中,其结构如下所示的示例:
beans {
dataSource(BasicDataSource) {
driverClassName = "org.hsqldb.jdbcDriver"
url = "jdbc:hsqldb:mem:grailsDB"
username = "sa"
password = ""
settings = [mynew:"setting"]
}
sessionFactory(SessionFactory) {
dataSource = dataSource
}
myService(MyService) {
nestedBean = { AnotherBean bean ->
dataSource = dataSource
}
}
}
This configuration style is largely equivalent to XML bean definitions and even supports Spring’s XML configuration namespaces. It also allows for importing XML bean definition files through an importBeans directive.
这种配置风格在很大程度上等同于XML bean定义,甚至支持Spring的XML配置命名空间。它还允许通过importBeans指令允许导入XML bean定义文件。
1.2.5 使用容器
Using the Container
The ApplicationContext is the interface for an advanced factory capable of maintaining a registry of different beans and their dependencies. By using the method T getBean(String name, Class requiredType), you can retrieve instances of your beans.
The ApplicationContext lets you read bean definitions and access them, as the following example shows:
ApplicationContext是一个高级工厂的接口,能够维护不同bean及其依赖关系的注册表。通过使用方法T getBean(String name, Class requiredType),您可以检索您的bean的实例。
ApplicationContext允许您读取bean的定义并访问它们,如下面的示例所示:
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("applicatiion.xml", "beans.xml");
// retrieve configured instance
UserService service = context.getBean("userService", UserService.class);
// use configured instance
List<String> userList = service.getUsernameList();
With Groovy configuration, bootstrapping looks very similar. It has a different context implementation class which is Groovy-aware (but also understands XML bean definitions). The following example shows Groovy configuration:
使用Groovy配置,引导过程看起来非常相似。它有一个不同的上下文实现类,它是Groovy感知的(但也理解XML bean定义)。以下示例显示了Groovy配置:
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
The most flexible variant is GenericApplicationContext in combination with reader delegates — for example, with XmlBeanDefinitionReader for XML files, as the following example shows:
最灵活的变体是GenericApplicationContext与读取器委托的组合,例如,使用XmlBeanDefinitionReader用于XML文件,如下面的示例所示:
GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
context.refresh();
You can mix and match such reader delegates on the same ApplicationContext, reading bean definitions from diverse configuration sources.
You can then use getBean to retrieve instances of your beans. The ApplicationContext interface has a few other methods for retrieving beans, but, ideally, your application code should never use them. Indeed, your application code should have no calls to the getBean() method at all and thus have no dependency on Spring APIs at all. For example, Spring’s integration with web frameworks provides dependency injection for various web framework components such as controllers and JSF-managed beans, letting you declare a dependency on a specific bean through metadata (such as an autowiring annotation).
您可以在同一个ApplicationContext中混合使用这些读取器委托,从不同的配置源读取bean定义。
然后,您可以使用getBean来检索您的bean的实例。ApplicationContext接口还有一些其他方法用于检索bean,但是理想情况下,您的应用程序代码不应该使用它们。实际上,您的应用程序代码根本不应该调用getBean()方法,因此完全不依赖于Spring的API。例如,Spring与Web框架的集成为各种Web框架组件(如控制器和JSF管理的bean)提供了依赖注入,使您可以通过元数据(例如自动装配注解)声明对特定bean的依赖。
- getBean()方法不建议使用,建议通过依赖注入
1.3 Bean概述
Bean Overview
A Spring IoC container manages one or more beans. These beans are created with the configuration metadata that you supply to the container (for example, in the form of XML <bean/> definitions).
一个Spring IoC容器管理一个或多个bean。这些bean是通过您提供给容器的配置元数据创建的(例如,以XML 定义的形式)。
Within the container itself, these bean definitions are represented as BeanDefinition objects, which contain (among other information) the following metadata:
在容器内部,这些bean定义被表示为BeanDefinition对象,其中包含以下元数据(以及其他信息):
-
A package-qualified class name: typically, the actual implementation class of the bean being defined.
-
Bean behavioral configuration elements, which state how the bean should behave in the container (scope, lifecycle callbacks, and so forth).
-
References to other beans that are needed for the bean to do its work. These references are also called collaborators or dependencies.
-
Other configuration settings to set in the newly created object — for example, the size limit of the pool or the number of connections to use in a bean that manages a connection pool.
- 包限定的类名:通常是定义的bean的实际实现类。
- Bean行为配置元素,用于定义bean在容器中的行为(作用域、生命周期回调等)。
- 对其他bean的引用,这些bean是bean执行工作所需的。这些引用也被称为协作者或依赖项。
- 其他配置设置,用于在新创建的对象中进行设置,例如连接池的大小限制或在管理连接池的bean中使用的连接数。
This metadata translates to a set of properties that make up each bean definition. The following table describes these properties:
这些元数据转化为构成每个bean定义的一组属性。下表描述了这些属性:
| 属性 | 描述 |
|---|---|
| 类(class) | 实例化Bean(Instantiatin Beans) |
| 名称(name) | 为Bean命名(Naming Beans) |
| 作用域(scope) | bean的作用域 (Bean Scopes) |
| 构造函数参数(Constructor argument) | 用于注入其他bean 对象(Dependency Injection) |
| 属性(Properties) | 用于注入其他属性(Dependency Injection) |
| 自动注入模式(Autowiring mode) | 自动装配协作者(Autowiring Collaborators) |
| 延迟初始化模式 (Lazy initialization mode) | 用于控制bean是否延迟实例化(Lazy-initialized Beans) |
| 初始化方法 (Initialization method) | 在对象实例化式时调用(Initialization Callbacks) |
| 销毁方法 (Destruction method) | 在对象销毁时调用(Destruction Callbacks) |
In addition to bean definitions that contain information on how to create a specific bean, the ApplicationContext implementations also permit the registration of existing objects that are created outside the container (by users). This is done by accessing the ApplicationContext’s BeanFactory through the getBeanFactory() method, which returns the DefaultListableBeanFactory implementation. DefaultListableBeanFactory supports this registration through the registerSingleton(..) and registerBeanDefinition(..) methods. However, typical applications work solely with beans defined through regular bean definition metadata.
除了包含有关如何创建特定bean的信息的bean定义外,ApplicationContext实现还允许注册在容器之外(由用户)创建的现有对象。这是通过访问ApplicationContext的BeanFactory来完成的,通过调用getBeanFactory()方法,该方法返回DefaultListableBeanFactory实现。DefaultListableBeanFactory通过registerSingleton(..)和registerBeanDefinition(..)方法支持此注册。然而,典型的应用程序仅使用通过常规bean定义元数据定义的bean。
Note
Bean metadata and manually supplied singleton instances need to be registered as early as possible, in order for the container to properly reason about them during autowiring and other introspection steps. While overriding existing metadata and existing singleton instances is supported to some degree, the registration of new beans at runtime (concurrently with live access to the factory) is not officially supported and may lead to concurrent access exceptions, inconsistent state in the bean container, or both.
为了使容器在自动装配和其他内省步骤中正确处理Bean元数据和手动提供的单例实例,这些数据需要尽早注册。虽然在一定程度上支持覆盖现有的元数据和实例,但在运行时注册新的Bean(与工厂的实时访问并发进行)并不得到官方支持,可能会导致并发访问异常、Bean容器中的不一致状态或两者同时发生。
1.3.1 命名Beans
## Naming Beans
Every bean has one or more identifiers. These identifiers must be unique within the container that hosts the bean. A bean usually has only one identifier. However, if it requires more than one, the extra ones can be considered aliases.
每个Bean都有一个或多个标识符。这些标识符在托管Bean的容器内必须是唯一的。通常,一个Bean只有一个标识符。然而,如果需要多个标识符,额外的标识符可以被视为别名。
In XML-based configuration metadata, you use the id attribute, the name attribute, or both to specify bean identifiers. The id attribute lets you specify exactly one id. Conventionally, these names are alphanumeric ('myBean', 'someService', etc.), but they can contain special characters as well. If you want to introduce other aliases for the bean, you can also specify them in the name attribute, separated by a comma (,), semicolon (;), or white space. Although the id attribute is defined as an xsd:string type, bean id uniqueness is enforced by the container, though not by XML parsers.
在基于XML的配置元数据中,可以使用id属性、name属性或两者来指定Bean的标识符。id属性允许您指定一个id。通常,这些名称是字母数字的('myBean','someService'等),但也可以包含特殊字符。如果您想为Bean引入其他别名,还可以在name属性中指定它们,用逗号(,)、分号(;)或空格分隔。虽然id属性被定义为xsd:string类型,但Bean的id唯一性是由容器强制执行的,而不是由XML解析器。
You are not required to supply a name or an id for a bean. If you do not supply a name or id explicitly, the container generates a unique name for that bean. However, if you want to refer to that bean by name, through the use of the ref element or a Service Locator style lookup, you must provide a name. Motivations for not supplying a name are related to using inner beans and autowiring collaborators.
您不需要为Bean提供名称或id。如果您没有显式提供名称或id,容器会为该Bean生成一个唯一的名称。然而,如果您想通过名称引用该Bean,通过使用ref元素或Service Locator样式的查找,您必须提供一个名称。不提供名称的动机与使用内部Bean和自动装配协作者有关。
1.3.1.1 Beans 命名约定、惯例、规范
Bean Naming Conventions
The convention is to use the standard Java convention for instance field names when naming beans. That is, bean names start with a lowercase letter and are camel-cased from there. Examples of such names include accountManager, accountService, userDao, loginController, and so forth.
Naming beans consistently makes your configuration easier to read and understand. Also, if you use Spring AOP, it helps a lot when applying advice to a set of beans related by name.
Bean命名约定是使用标准的Java约定来命名实例字段。也就是说,bean名称以小写字母开头,然后采用驼峰命名法。例如:accountManager、accountService、userDao、loginController等。
一致地命名bean可以使您的配置更易于阅读和理解。此外,如果使用Spring AOP,按名称对一组相关的bean应用通知会非常有帮助。
1.3.1.2 注意
Note
With component scanning in the classpath, Spring generates bean names for unnamed components, following the rules described earlier: essentially, taking the simple class name and turning its initial character to lower-case. However, in the (unusual) special case when there is more than one character and both the first and second characters are upper case, the original casing gets preserved. These are the same rules as defined by java.beans.Introspector.decapitalize (which Spring uses here).
在类路径中启用了组件扫描后,Spring会为未命名的组件生成bean名称,遵循先前描述的规则:基本上,将简单类名的首字母转为小写。然而,在(不常见的)特殊情况下,如果有两个以上的字符,并且第一个和第二个字符都是大写的,那么原始大小写将被保留。这些规则与java.beans.Introspector.decapitalize定义的规则相同(Spring在此处使用)。
1.3.1.3 在Bean定义之外给Bean起别名
Aliasing a Bean outside the Bean Definition
In a bean definition itself, you can supply more than one name for the bean, by using a combination of up to one name specified by the id attribute and any number of other names in the name attribute. These names can be equivalent aliases to the same bean and are useful for some situations, such as letting each component in an application refer to a common dependency by using a bean name that is specific to that component itself.
在bean定义本身中,您可以通过使用id属性指定的一个名称以及name属性中的任意数量的其他名称来为bean提供多个名称。这些名称可以是等效的别名,指向同一个bean,并且在某些情况下非常有用,例如,让应用程序中的每个组件通过使用特定于该组件的bean名称来引用共享的依赖项。
Specifying all aliases where the bean is actually defined is not always adequate, however. It is sometimes desirable to introduce an alias for a bean that is defined elsewhere. This is commonly the case in large systems where configuration is split amongst each subsystem, with each subsystem having its own set of object definitions. In XML-based configuration metadata, you can use the element to accomplish this. The following example shows how to do so:
然而,仅在定义bean的位置指定所有别名并不总是足够的。有时候需要为在其他地方定义的bean引入别名。这在大型系统中很常见,其中配置在每个子系统之间分割,每个子系统都有自己的对象定义集合。在基于XML的配置元数据中,您可以使用元素来实现这一点。以下示例展示了如何使用它:
<alias name="fromName" alias="toName"/>
In this case, a bean (in the same container) named fromName may also, after the use of this alias definition, be referred to as toName.
在这种情况下,使用别名定义后,同一个容器中的一个名为fromName的bean也可以被称为toName。
For example, the configuration metadata for subsystem A may refer to a DataSource by the name of subsystemA-dataSource. The configuration metadata for subsystem B may refer to a DataSource by the name of subsystemB-dataSource. When composing the main application that uses both these subsystems, the main application refers to the DataSource by the name of myApp-dataSource. To have all three names refer to the same object, you can add the following alias definitions to the configuration metadata:
例如,子系统A的配置元数据可以使用子系统A-dataSource的名称引用一个DataSource。子系统B的配置元数据可以使用子系统B-dataSource的名称引用一个DataSource。当组合使用这两个子系统的主应用程序时,主应用程序可以使用myApp-dataSource的名称引用DataSource。为了使这三个名称都指向同一个对象,您可以将以下别名定义添加到配置元数据中:
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
Now each component and the main application can refer to the dataSource through a name that is unique and guaranteed not to clash with any other definition (effectively creating a namespace), yet they refer to the same bean.
现在,每个组件和主应用程序都可以通过一个唯一且保证不与任何其他定义冲突的名称引用dataSource(有效地创建一个命名空间),但它们都指向同一个bean。
Java-configuration
If you use Java Configuration, the @Bean annotation can be used to provide aliases. See Using the @Bean Annotation for details.
如果您使用Java配置,可以使用@Bean注解来提供别名。有关详细信息,请参阅使用@Bean注解。
1.3.2 实例化beans
Instantiating Beans
A bean definition is essentially a recipe for creating one or more objects. The container looks at the recipe for a named bean when asked and uses the configuration metadata encapsulated by that bean definition to create (or acquire) an actual object.
一个bean定义本质上是创建一个或多个对象的配方。当被要求时,容器会查看命名bean的配方,并使用由该bean定义封装的配置元数据来创建(或获取)实际对象。
If you use XML-based configuration metadata, you specify the type (or class) of object that is to be instantiated in the class attribute of the element. This class attribute (which, internally, is a Class property on a BeanDefinition instance) is usually mandatory. (For exceptions, see Instantiation by Using an Instance Factory Method and Bean Definition Inheritance.) You can use the Class property in one of two ways:
如果您使用基于XML的配置元数据,您可以在元素的class属性中指定要实例化的对象的类型(或类)。这个class属性(在BeanDefinition实例上是一个Class属性)通常是必需的。(有例外情况,请参见通过使用实例工厂方法进行实例化和bean定义继承。)您可以以两种方式使用Class属性:
- Typically, to specify the bean class to be constructed in the case where the container itself directly creates the bean by calling its constructor reflectively, somewhat equivalent to Java code with the new operator.
通常,在容器自身通过调用其构造函数进行反射创建bean的情况下,指定要构造的bean类,类似于使用new运算符的Java代码。
- To specify the actual class containing the static factory method that is invoked to create the object, in the less common case where the container invokes a static factory method on a class to create the bean. The object type returned from the invocation of the static factory method may be the same class or another class entirely.
在较不常见的情况下,指定实际包含要调用以创建对象的静态工厂方法的类。从调用静态工厂方法返回的对象类型可以是相同的类,也可以是完全不同的类。
1.3.2.1 嵌套类名
Nested class names
If you want to configure a bean definition for a nested class, you may use either the binary name or the source name of the nested class.
如果要为嵌套类配置一个bean定义,可以使用嵌套类的二进制名称或源名称。
For example, if you have a class called SomeThing in the com.example package, and this SomeThing class has a static nested class called OtherThing, they can be separated by a dollar sign or a dot (.). So the value of the class attribute in a bean definition would be com.example.SomeThing$OtherThing or com.example.SomeThing.OtherThing.
例如,如果您有一个名为SomeThing的类在com.example包中,并且这个SomeThing类有一个名为OtherThing的静态嵌套类,它们可以用美元符号dollar(此处不能显示美元符号...)或点号(.)分隔。因此,在bean定义中,class属性的值可以是com.example.SomeThing$OtherThing或com.example.SomeThing.OtherThing。
1.3.2.2 通过一个构造函数实例化
Instantiation with a Constructor
When you create a bean by the constructor approach, all normal classes are usable by and compatible with Spring. That is, the class being developed does not need to implement any specific interfaces or to be coded in a specific fashion. Simply specifying the bean class should suffice. However, depending on what type of IoC you use for that specific bean, you may need a default (empty) constructor.
当您通过构造函数方式创建一个bean时,所有普通类都可以被Spring使用和兼容。也就是说,正在开发的类不需要实现任何特定的接口或按照特定的方式编码。只需指定bean类即可。然而,根据您为该特定bean使用的IoC类型,您可能需要一个默认(空)构造函数。
The Spring IoC container can manage virtually any class you want it to manage. It is not limited to managing true JavaBeans. Most Spring users prefer actual JavaBeans with only a default (no-argument) constructor and appropriate setters and getters modeled after the properties in the container. You can also have more exotic non-bean-style classes in your container. If, for example, you need to use a legacy connection pool that absolutely does not adhere to the JavaBean specification, Spring can manage it as well.
Spring IoC容器可以管理几乎任何您想要管理的类。它不仅限于管理真正的JavaBean。大多数Spring用户更喜欢实际的JavaBean,只包含一个默认(无参数)构造函数和根据容器中的属性建模的适当的setter和getter方法。您还可以在容器中使用更奇特的非bean风格的类。例如,如果您需要使用一个绝对不符合JavaBean规范的传统连接池,Spring也可以管理它。
With XML-based configuration metadata you can specify your bean class as follows:
通过基于XML的配置元数据,您可以按以下方式指定您的bean类:
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>
For details about the mechanism for supplying arguments to the constructor (if required) and setting object instance properties after the object is constructed, see Injecting Dependencies.
有关向构造函数提供参数(如果需要)以及在对象构造后设置对象实例属性的机制的详细信息,请参阅"注入依赖"。
1.3.2.3 通过一个静态工厂方法实例化
Instantiation with a Static Factory Method
When defining a bean that you create with a static factory method, use the class attribute to specify the class that contains the static factory method and an attribute named factory-method to specify the name of the factory method itself. You should be able to call this method (with optional arguments, as described later) and return a live object, which subsequently is treated as if it had been created through a constructor. One use for such a bean definition is to call static factories in legacy code.
当定义一个使用静态工厂方法创建的bean时,可以使用class属性指定包含静态工厂方法的类,并使用名为factory-method的属性指定工厂方法的名称。您应该能够调用此方法(后面再描述,可以选择使用参数)并返回一个实例对象,随后该对象将被视为通过构造函数创建的对象。这样的bean定义的一个用途是调用遗留代码中的静态工厂方法。
The following bean definition specifies that the bean will be created by calling a factory method. The definition does not specify the type (class) of the returned object, but rather the class containing the factory method. In this example, the createInstance() method must be a static method. The following example shows how to specify a factory method:
以下bean定义指定了通过调用工厂方法来创建bean。该定义没有指定返回对象的类型(类),而是指定包含工厂方法的类。在这个例子中,createInstance()方法必须是一个静态方法。以下示例展示了如何指定一个工厂方法:
<bean id="clientService" class="examples.ClientService" factory-method="createInstance"/>
The following example shows a class that would work with the preceding bean definition:
以下示例展示了一个与前面的bean定义配合使用的类:
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
For details about the mechanism for supplying (optional) arguments to the factory method and setting object instance properties after the object is returned from the factory, see Dependencies and Configuration in Detail.
有关向工厂方法提供(可选)参数以及在对象从工厂返回后设置对象实例属性的机制的详细信息,请参阅《依赖和配置详解》。
1.3.2.4 通过一个实例工厂方法实例化
Instantiation by Using an Instance Factory Method
Similar to instantiation through a static factory method , instantiation with an instance factory method invokes a non-static method of an existing bean from the container to create a new bean. To use this mechanism, leave the class attribute empty and, in the factory-bean attribute, specify the name of a bean in the current (or parent or ancestor) container that contains the instance method that is to be invoked to create the object. Set the name of the factory method itself with the factory-method attribute. The following example shows how to configure such a bean:
与通过静态工厂方法实例化类似,通过实例工厂方法实例化是调用容器中现有bean的非静态方法来创建新bean的方式。要使用这种机制,将class属性留空,并在factory-bean属性中指定当前(或父级或祖先)容器中包含要调用以创建对象的实例方法的bean的名称。使用factory-method属性设置工厂方法本身的名称。以下示例显示了如何配置此类bean:
<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- the bean to be created via the factory bean -->
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
The following example shows the corresponding class:
下面的示例显示了相应的类:
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}
One factory class can also hold more than one factory method, as the following example shows:
一个工厂类也可以包含多个工厂方法,如下面的示例所示:
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
<bean id="accountService"
factory-bean="serviceLocator"
factory-method="createAccountServiceInstance"/>
The following example shows the corresponding class:
下面的示例显示了相应的类:
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
private static AccountService accountService = new AccountServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
public AccountService createAccountServiceInstance() {
return accountService;
}
}
This approach shows that the factory bean itself can be managed and configured through dependency injection (DI). See Dependencies and Configuration in Detail .
这种方法表明工厂bean本身可以通过依赖注入(DI)进行管理和配置。请参见详细的依赖关系和配置。
1.3.2.5 注意
note
In Spring documentation, "factory bean" refers to a bean that is configured in the Spring container and that creates objects through an instance or static factory method. By contrast, FactoryBean (notice the capitalization) refers to a Spring-specific FactoryBean implementation class.
在Spring文档中,“factory bean”指的是在Spring容器中进行配置并通过实例或静态工厂方法创建对象的bean。相比之下,FactoryBean(注意大写)指的是Spring特定的FactoryBean实现类。
1.3.2.6 确定Bean的运行时类型
Determining a Bean’s Runtime Type
在Java中,我们可以使用 `getClass()` 方法来确定对象的运行时类型。对于Spring中的Bean,我们可以使用 `getClass()` 方法来获取Bean的实际类型。
例如,假设我们有一个名为 `myBean` 的Bean。我们可以使用以下代码来确定 `myBean` 的运行时类型:Class<?> beanType = myBean.getClass();通过这个代码,我们可以获取 `myBean` 的实际类型,并将其存储在 `beanType` 变量中。 需要注意的是, `getClass()` 方法返回的是对象的实际类型,而不是声明类型。这意味着如果 `myBean` 是通过继承或接口实现创建的,那么 `beanType` 将反映其实际的子类或实现类。
The runtime type of a specific bean is non-trivial to determine. A specified class in the bean metadata definition is just an initial class reference, potentially combined with a declared factory method or being a FactoryBean class which may lead to a different runtime type of the bean, or not being set at all in case of an instance-level factory method (which is resolved via the specified factory-bean name instead). Additionally, AOP proxying may wrap a bean instance with an interface-based proxy with limited exposure of the target bean’s actual type (just its implemented interfaces).
特定bean的运行时类型很难确定。在bean元数据定义中指定的类只是一个初始类引用,可能与声明的工厂方法结合使用,或者是一个FactoryBean类,这可能导致bean的运行时类型不同,或者在实例级别工厂方法的情况下根本没有设置(这是通过指定的工厂bean名称来解析的)。此外,AOP代理可能会使用基于接口的代理包装一个bean实例,对目标bean的实际类型的暴露有限(只有它实现的接口)。
The recommended way to find out about the actual runtime type of a particular bean is a BeanFactory.getType call for the specified bean name. This takes all of the above cases into account and returns the type of object that a BeanFactory.getBean call is going to return for the same bean name.
获取特定bean的实际运行时类型的推荐方法是使用BeanFactory.getType调用指定的bean名称。它考虑了上述所有情况,并返回BeanFactory.getBean调用将为相同的bean名称返回的对象类型。
1.4 依赖关系
Dependencies
A typical enterprise application does not consist of a single object (or bean in the Spring parlance). Even the simplest application has a few objects that work together to present what the end-user sees as a coherent application. This next section explains how you go from defining a number of bean definitions that stand alone to a fully realized application where objects collaborate to achieve a goal.
一个典型的企业应用程序不仅仅由一个对象(或者在Spring中称为bean)组成。即使是最简单的应用程序也有几个对象共同工作,以呈现给最终用户一个完整的应用程序。下一节将解释如何从定义一些独立的bean定义转变为一个完全实现的应用程序,其中对象协作以实现一个目标。
1.4.1 章节摘要
Section Summary
Dependency Injection:依赖注入
Dependencies and Configuration in Detail:详细的依赖项和配置
Using depends-on
Lazy-initialized Beans:延迟加载beans (beans懒加载)
Autowiring Collaborators:自动装配协作者
Method Injection:方法注入
1.4.2 依赖注入
Dependency Injection
Dependency injection (DI) is a process whereby objects define their dependencies (that is, the other objects with which they work) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies on its own by using direct construction of classes or the Service Locator pattern.
依赖注入(DI)是一种过程,在这个过程中,对象仅通过构造函数参数、工厂方法的参数或在对象实例构造完成后或从工厂方法返回后设置的属性来定义它们的依赖关系(即与其一起工作的其他对象)。容器在创建bean时注入这些依赖关系。这个过程基本上是bean本身通过直接构造类或使用服务定位器模式来控制其依赖项的实例化或定位的逆过程(因此称为控制反转)。
Code is cleaner with the DI principle, and decoupling is more effective when objects are provided with their dependencies. The object does not look up its dependencies and does not know the location or class of the dependencies. As a result, your classes become easier to test, particularly when the dependencies are on interfaces or abstract base classes, which allow for stub or mock implementations to be used in unit tests.
使用DI原则,代码更清晰,当对象提供其依赖项时,解耦效果更好。对象不会查找其依赖项,也不知道依赖项的位置或类。因此,您的类在进行单元测试时变得更容易,特别是当依赖项是接口或抽象基类时,可以在单元测试中使用存根或模拟实现。
DI exists in two major variants: Constructor-based dependency injection and Setter-based dependency injection.
DI存在两种主要的变体:基于构造函数的依赖注入和基于设置器(Setter 方法)的依赖注入。
1.4.2.1 基于构造器的依赖注入
Constructor-based Dependency Injection
Constructor-based DI is accomplished by the container invoking a constructor with a number of arguments, each representing a dependency. Calling a static factory method with specific arguments to construct the bean is nearly equivalent, and this discussion treats arguments to a constructor and to a static factory method similarly. The following example shows a class that can only be dependency-injected with constructor injection:
基于构造函数的依赖注入是通过容器调用具有多个参数的构造函数来实现的,每个参数表示一个依赖项。调用具有特定参数的静态工厂方法来构造bean几乎是等效的,本讨论将构造函数和静态工厂方法的参数视为相似。以下示例展示了一个只能通过构造函数注入依赖项的类:
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on a MovieFinder
private final MovieFinder movieFinder;
// a constructor so that the Spring container can inject a MovieFinder
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
Notice that there is nothing special about this class. It is a POJO that has no dependencies on container specific interfaces, base classes, or annotations.
请注意,这个类没有任何特殊之处。它是一个普通的POJO类,没有依赖于容器特定的接口、基类或注解。
1.4.2.1.1 构造函数参数解析
Constructor Argument Resolution
Constructor argument resolution matching occurs by using the argument’s type. If no potential ambiguity exists in the constructor arguments of a bean definition, the order in which the constructor arguments are defined in a bean definition is the order in which those arguments are supplied to the appropriate constructor when the bean is being instantiated. Consider the following class:
构造函数参数的解析匹配是通过使用参数的类型来进行的。如果在bean定义的构造函数参数中不存在潜在的歧义,那么在实例化bean时,构造函数参数在bean定义中的顺序就是将这些参数提供给适当的构造函数的顺序。考虑以下类:
package x.y;
public class ThingOne {
public ThingOne(ThingTwo thingTwo, ThingThree thingThree) {
// ...
}
}
1) 不用显式指定构造类型的参数解析
Assuming that the ThingTwo and ThingThree classes are not related by inheritance, no potential ambiguity exists. Thus, the following configuration works fine, and you do not need to specify the constructor argument indexes or types explicitly in the element.
假设ThingTwo和ThingThree类之间没有继承关系,那么就不存在潜在的歧义。因此,以下配置是有效的,您不需要在元素中显式指定构造函数参数的索引或类型。
<beans>
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg ref="beanTwo"/>
<constructor-arg ref="beanThree"/>
</bean>
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
When another bean is referenced, the type is known, and matching can occur (as was the case with the preceding example). When a simple type is used, such as true, Spring cannot determine the type of the value, and so cannot match by type without help. Consider the following class:
当引用另一个bean时,类型是已知的,可以进行匹配(就像前面的例子一样)。当使用简单类型时,例如true,Spring无法确定值的类型,因此在没有帮助的情况下无法按类型进行匹配。考虑以下类:
package examples;
public class ExampleBean {
// Number of years to calculate the Ultimate Answer
private final int years;
// The Answer to Life, the Universe, and Everything
private final String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
2) 通过属性字段type显式指定构造类型的参数解析
In the preceding scenario, the container can use type matching with simple types if you explicitly specify the type of the constructor argument by using the type attribute, as the following example shows:
在上述场景中,如果您使用type属性显式指定构造函数参数的类型,容器可以对简单类型进行类型匹配,示例如下:
3) 通过属性字段index 显式指定构造函数参数值的参数解析
You can use the index attribute to specify explicitly the index of constructor arguments, as the following example shows:
您可以使用index属性来显式指定构造函数参数的索引,如下面的示例所示:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
In addition to resolving the ambiguity of multiple simple values, specifying an index resolves ambiguity where a constructor has two arguments of the same type.
除了解决多个简单值的歧义外,指定索引还可以解决构造函数具有两个相同类型参数的歧义。
not
The index is 0-based.
4) 通过属性字段name 对应构造函数参数名的参数解析
You can also use the constructor parameter name for value disambiguation, as the following example shows:
您还可以使用构造函数参数的名称来消除值的歧义,如下面的示例所示:
Keep in mind that, to make this work out of the box, your code must be compiled with the debug flag enabled so that Spring can look up the parameter name from the constructor. If you cannot or do not want to compile your code with the debug flag, you can use the @ConstructorProperties JDK annotation to explicitly name your constructor arguments. The sample class would then have to look as follows:
请注意,为了使此功能开箱即用,您的代码必须使用启用了调试标志的方式进行编译,以便Spring可以从构造函数中查找参数名称。如果您无法或不想使用调试标志编译代码,您可以使用@ConstructorProperties JDK注解显式命名构造函数参数。然后,示例类应如下所示:
public class ExampleBean {
// Fields omitted
@ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
1.4.2.2 基于设置器的依赖注入
Setter-based Dependency Injection
Setter-based DI is accomplished by the container calling setter methods on your beans after invoking a no-argument constructor or a no-argument static factory method to instantiate your bean.
Setter-based DI是通过容器在调用无参构造函数或无参静态工厂方法实例化您的bean后,在bean上调用setter方法来实现的。
The following example shows a class that can only be dependency-injected by using pure setter injection. This class is conventional Java. It is a POJO that has no dependencies on container specific interfaces, base classes, or annotations.
以下示例展示了一个只能通过纯setter注入进行依赖注入的类。这个类是传统的Java类,它不依赖于容器特定的接口、基类或注解。
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on the MovieFinder
private MovieFinder movieFinder;
// a setter method so that the Spring container can inject a MovieFinder
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
The ApplicationContext supports constructor-based and setter-based DI for the beans it manages. It also supports setter-based DI after some dependencies have already been injected through the constructor approach. You configure the dependencies in the form of a BeanDefinition, which you use in conjunction with PropertyEditor instances to convert properties from one format to another. However, most Spring users do not work with these classes directly (that is, programmatically) but rather with XML bean definitions, annotated components (that is, classes annotated with @Component, @Controller, and so forth), or @Bean methods in Java-based @Configuration classes. These sources are then converted internally into instances of BeanDefinition and used to load an entire Spring IoC container instance.
ApplicationContext支持基于构造函数和基于setter的依赖注入(DI)来管理其管理的bean。它还支持在通过构造函数方法注入了一些依赖之后,使用基于setter的DI。您可以使用BeanDefinition来配置依赖项,并与PropertyEditor实例一起使用,将属性从一种格式转换为另一种格式。然而,大多数Spring用户不直接使用这些类(即以编程方式),而是使用XML bean定义、带有@Component、@Controller等注解的组件类,或者在基于Java的@Configuration类中使用@Bean方法。然后,这些源代码会在内部转换为BeanDefinition的实例,并用于加载整个Spring IoC容器实例。
1.4.2.3 基于构造函数还是基于 setter 的 DI? ?
Constructor-based or setter-based DI?
Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the @Autowired annotation on a setter method can be used to make the property be a required dependency; however, constructor injection with programmatic validation of arguments is preferable.
由于可以混合使用基于构造函数和基于setter的依赖注入(DI),一个好的经验法则是使用构造函数来处理必需的依赖项,而使用setter方法或配置方法来处理可选的依赖项。请注意,在setter方法上使用@Autowired注解可以将属性设置为必需的依赖项;然而,使用编程方式验证参数的构造函数注入更可取。
The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.
Spring团队通常推荐使用构造函数注入,因为它允许您将应用程序组件实现为不可变对象,并确保必需的依赖项不为null。此外,构造函数注入的组件始终以完全初始化的状态返回给客户端(调用)代码。另外,构造函数参数过多是一种不好的代码气味,意味着该类可能具有过多的责任,应进行重构以更好地处理关注点的分离。
Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is therefore a compelling use case for setter injection.
Setter注入主要应仅用于可以在类内部分配合理默认值的可选依赖项。否则,代码使用该依赖项的地方都必须执行非null检查。Setter注入的一个好处是,setter方法使该类的对象易于在稍后进行重新配置或重新注入。因此,通过JMX MBeans进行管理是使用setter注入的一个合理用例。
Use the DI style that makes the most sense for a particular class. Sometimes, when dealing with third-party classes for which you do not have the source, the choice is made for you. For example, if a third-party class does not expose any setter methods, then constructor injection may be the only available form of DI.
根据特定类选择最合适的DI风格。有时,在处理没有源代码的第三方类时,选择由它决定。例如,如果第三方类没有公开任何setter方法,则构造函数注入可能是唯一可用的DI形式。
1.4.2.4 依赖解析过程
## Dependency Resolution Process
The container performs bean dependency resolution as follows:
容器执行bean依赖关系解析的过程如下:
The ApplicationContext is created and initialized with configuration metadata that describes all the beans. Configuration metadata can be specified by XML, Java code, or annotations.
创建并初始化ApplicationContext,其中包含描述所有bean的配置元数据。配置元数据可以通过XML、Java代码或注解来指定。
For each bean, its dependencies are expressed in the form of properties, constructor arguments, or arguments to the static-factory method (if you use that instead of a normal constructor). These dependencies are provided to the bean, when the bean is actually created.
对于每个bean,其依赖关系以属性、构造函数参数或静态工厂方法的参数形式表达(如果您使用静态工厂方法而不是普通构造函数)。当实际创建bean时,这些依赖项将提供给bean。
Each property or constructor argument is an actual definition of the value to set, or a reference to another bean in the container.
每个属性或构造函数参数都是要设置的实际值的定义,或者是容器中另一个bean的引用。
Each property or constructor argument that is a value is converted from its specified format to the actual type of that property or constructor argument. By default, Spring can convert a value supplied in string format to all built-in types, such as int, long, String, boolean, and so forth.
每个属性或构造函数参数的值都会从其指定的格式转换为属性或构造函数参数的实际类型。默认情况下,Spring可以将以字符串格式提供的值转换为所有内置类型,例如int、long、String、boolean等。
The Spring container validates the configuration of each bean as the container is created. However, the bean properties themselves are not set until the bean is actually created. Beans that are singleton-scoped and set to be pre-instantiated (the default) are created when the container is created. Scopes are defined in Bean Scopes. Otherwise, the bean is created only when it is requested. Creation of a bean potentially causes a graph of beans to be created, as the bean’s dependencies and its dependencies' dependencies (and so on) are created and assigned. Note that resolution mismatches among those dependencies may show up late — that is, on first creation of the affected bean.
在容器创建的过程中,Spring容器会验证每个bean的配置。但是,直到实际创建bean之前,bean的属性本身不会被设置。单例作用域且设置为预实例化(默认情况下)的bean在容器创建时就会被创建。作用域在Bean作用域中定义。否则,只有在请求时才会创建bean。创建bean可能会导致一组bean被创建,因为创建并分配了bean的依赖项及其依赖项的依赖项(以此类推)。请注意,这些依赖项之间的解析不匹配可能会在较晚的时候出现,即在受影响的bean首次创建时。
1.4.2.5 依赖注入的一些例子
Examples of Dependency Injection
1) setter-based(基于设置器)依赖注入的例子
The following example uses XML-based configuration metadata for setter-based DI. A small part of a Spring XML configuration file specifies some bean definitions as follows:
以下示例使用基于XML的配置元数据进行基于setter的依赖注入。Spring XML配置文件的一小部分指定了一些bean定义,如下所示:
<bean id="exampleBean" class="examples.ExampleBean">
<!-- setter injection using the nested ref element -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<!-- setter injection using the neater ref attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
The following example shows the corresponding ExampleBean class:
以下示例展示了相应的ExampleBean类:
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
}
public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
}
public void setIntegerProperty(int i) {
this.i = i;
}
}
2) constructor-based(基于构造函数)依赖注入的例子
In the preceding example, setters are declared to match against the properties specified in the XML file. The following example uses constructor-based DI:
在上面的示例中,声明了setter方法以匹配XML文件中指定的属性。下面的示例使用基于构造函数的依赖注入:
<bean id="exampleBean" class="examples.ExampleBean">
<!-- constructor injection using the nested ref element -->
<constructor-arg>
<ref bean="anotherExampleBean"/>
</constructor-arg>
<!-- constructor injection using the neater ref attribute -->
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg type="int" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
The following example shows the corresponding ExampleBean class:
以下示例展示了相应的ExampleBean类:
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public ExampleBean(
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
this.beanOne = anotherBean;
this.beanTwo = yetAnotherBean;
this.i = i;
}
}
The constructor arguments specified in the bean definition are used as arguments to the constructor of the ExampleBean.
在bean定义中指定的构造函数参数被用作ExampleBean构造函数的参数。
3) static factory-method-based(基于静态工厂方法)依赖注入的例子
Now consider a variant of this example, where, instead of using a constructor, Spring is told to call a static factory method to return an instance of the object:
现在考虑这个示例的一个变体,其中,不是使用构造函数,而是告诉Spring调用一个静态工厂方法来返回对象的实例:
<bean id="exampleBean" class="examples.ExampleBean" factory-method="createInstance">
<constructor-arg ref="anotherExampleBean"/>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
The following example shows the corresponding ExampleBean class: 以下示例展示了相应的ExampleBean类:
public class ExampleBean {
// a private constructor
private ExampleBean(...) {
...
}
// a static factory method; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
public static ExampleBean createInstance (
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
ExampleBean eb = new ExampleBean (...);
// some other operations...
return eb;
}
}
Arguments to the static factory method are supplied by elements, exactly the same as if a constructor had actually been used. The type of the class being returned by the factory method does not have to be of the same type as the class that contains the static factory method (although, in this example, it is). An instance (non-static) factory method can be used in an essentially identical fashion (aside from the use of the factory-bean attribute instead of the class attribute), so we do not discuss those details here.
静态工厂方法的参数由元素提供,与实际使用构造函数时完全相同。工厂方法返回的类的类型不必与包含静态工厂方法的类相同(尽管在此示例中是相同的)。可以以基本相同的方式使用实例(非静态)工厂方法(除了使用factory-bean属性而不是class属性),因此我们在这里不讨论这些细节。
4) factory-method-based(基于非静态工厂方法)依赖注入的例子
1.4.3 详细的依赖项和配置
Dependencies and Configuration in Detail
As mentioned in the previous section, you can define bean properties and constructor arguments as references to other managed beans (collaborators) or as values defined inline. Spring’s XML-based configuration metadata supports sub-element types within its and elements for this purpose.
如前一节所述,您可以将bean属性和构造函数参数定义为对其他受管bean(协作者)的引用或内联定义的值。Spring基于XML的配置元数据支持和元素中的子元素类型,以实现这一目的。
1.4.3.1 直接值(原始类型、字符串等)
Straight Values (Primitives, Strings, and so on)
The value attribute of the element specifies a property or constructor argument as a human-readable string representation. Spring’s conversion service is used to convert these values from a String to the actual type of the property or argument. The following example shows various values being set:
元素的value属性将属性或构造函数参数指定为可读的字符串表示。Spring的转换服务用于将这些值从字符串转换为属性或参数的实际类型。以下示例展示了设置各种值的情况:
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- results in a setDriverClassName(String) call -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="misterkaoli"/>
The following example uses the p-namespace for even more succinct XML configuration:
以下示例使用p命名空间进行更简洁的XML配置:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/mydb"
p:username="root"
p:password="misterkaoli"/>
</beans>
The preceding XML is more succinct. However, typos are discovered at runtime rather than design time, unless you use an IDE (such as IntelliJ IDEA or the Spring Tools for Eclipse) that supports automatic property completion when you create bean definitions. Such IDE assistance is highly recommended.
上述XML更加简洁。然而,除非您使用支持在创建bean定义时自动属性完成的IDE(例如IntelliJ IDEA或Spring Tools for Eclipse),否则拼写错误将在运行时而不是设计时被发现。强烈建议使用此类IDE辅助功能。
You can also configure a java.util.Properties instance, as follows:
您还可以配置java.util.Properties实例,如下所示:
<bean id="mappings"
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<!-- typed as a java.util.Properties -->
<property name="properties">
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
</property>
The Spring container converts the text inside the element into a java.util.Properties instance by using the JavaBeans PropertyEditor mechanism. This is a nice shortcut, and is one of a few places where the Spring team do favor the use of the nested element over the value attribute style.
Spring容器通过使用JavaBeans PropertyEditor机制,将元素内的文本转换为java.util.Properties实例。这是一个很好的快捷方式,也是Spring团队在一些地方更倾向于使用嵌套的元素而不是value属性样式的地方之一。
1) idref 元素(传递字符串,不是引用)
idref element
The idref element is simply an error-proof way to pass the id (a string value - not a reference) of another bean in the container to a or element. The following example shows how to use it:
idref元素只是一种无误传递容器中另一个bean的id(一个字符串值,而不是引用)给或元素的方法。以下示例显示了如何使用它:
The preceding bean definition snippet is exactly equivalent (at runtime) to the following snippet:
前面的bean定义片段在运行时与以下片段完全等效:
<bean id="theTargetBean" class="..." />
<bean id="client" class="...">
<property name="targetName" value="theTargetBean"/>
</bean>
The first form is preferable to the second, because using the idref tag lets the container validate at deployment time that the referenced, named bean actually exists. In the second variation, no validation is performed on the value that is passed to the targetName property of the client bean. Typos are only discovered (with most likely fatal results) when the client bean is actually instantiated. If the client bean is a prototype bean, this typo and the resulting exception may only be discovered long after the container is deployed.
第一种形式比第二种更可取,因为使用idref标签可以让容器在部署时验证引用的命名bean是否存在。在第二种变体中,对传递给客户端bean的targetName属性的值不进行验证。只有在实际实例化客户端bean时才会发现拼写错误(可能导致致命结果)。如果客户端bean是原型bean,那么这种拼写错误和 resulting exception 可能在容器部署后很长时间才被发现。
注意
note
The local attribute on the idref element is no longer supported in the 4.0 beans XSD, since it does not provide value over a regular bean reference any more. Change your existing idref local references to idref bean when upgrading to the 4.0 schema.
在4.0版本的beans XSD中(XML(EXtensible Markup Language) Schema Definition(可扩展标记语言命名空间定义)),不再支持idref元素上的local属性,因为它不再提供与常规bean引用相比的价值。在升级到4.0模式时,请将现有的idref本地引用更改为idref bean引用。
A common place (at least in versions earlier than Spring 2.0) where the element brings value is in the configuration of AOP interceptors in a ProxyFactoryBean bean definition. Using elements when you specify the interceptor names prevents you from misspelling an interceptor ID.
在ProxyFactoryBean bean定义中,元素带来价值的一个常见场景(至少在Spring 2.0之前的版本中)是在配置AOP拦截器时。使用元素来指定拦截器名称可以防止拼写拦截器ID时出错。
1.4.3.2 对其他 bean 的引用(协作者)
References to Other Beans (Collaborators)
1) ref 对对象引用
ref element
The ref element is the final element inside a or definition element. Here, you set the value of the specified property of a bean to be a reference to another bean (a collaborator) managed by the container. The referenced bean is a dependency of the bean whose property is to be set, and it is initialized on demand as needed before the property is set. (If the collaborator is a singleton bean, it may already be initialized by the container.) All references are ultimately a reference to another object. Scoping and validation depend on whether you specify the ID or name of the other object through the bean or parent attribute.
ref元素是或定义元素内的最后一个元素。在这里,您将一个bean的指定属性的值设置为对容器管理的另一个bean(协作者)的引用。被引用的bean是要设置属性的bean的依赖项,并且在设置属性之前根据需要按需初始化。(如果协作者是单例bean,它可能已经由容器初始化。)所有引用最终都是对另一个对象的引用。作用域和验证取决于您是通过bean属性还是通过parent属性指定了另一个对象的ID或名称。
Specifying the target bean through the bean attribute of the tag is the most general form and allows creation of a reference to any bean in the same container or parent container, regardless of whether it is in the same XML file. The value of the bean attribute may be the same as the id attribute of the target bean or be the same as one of the values in the name attribute of the target bean. The following example shows how to use a ref element:
通过标签的bean属性来指定目标bean是最常见的形式,它允许创建对同一容器或父容器中的任何bean的引用,无论它是否在同一个XML文件中。 bean属性的值可以与目标bean的id属性相同,也可以与目标bean的name属性中的某个值相同。以下示例显示了如何使用ref元素:
<ref bean="someBean"/>
Specifying the target bean through the parent attribute creates a reference to a bean that is in a parent container of the current container. The value of the parent attribute may be the same as either the id attribute of the target bean or one of the values in the name attribute of the target bean. The target bean must be in a parent container of the current one. You should use this bean reference variant mainly when you have a hierarchy of containers and you want to wrap an existing bean in a parent container with a proxy that has the same name as the parent bean. The following pair of listings shows how to use the parent attribute:
通过 parent 属性指定目标 bean,可以创建对当前容器的父容器中的 bean 的引用。parent 属性的值可以是目标 bean 的 id 属性或者目标 bean 的 name 属性中的一个值。目标 bean 必须位于当前容器的父容器中。当您拥有容器层次结构并且想要在父容器中使用与父 bean 相同名称的代理包装现有 bean 时,应主要使用此 bean 引用变体。以下是如何使用 parent 属性的示例代码对:
<!-- in the parent context -->
<bean id="accountService" class="com.something.SimpleAccountService">
<!-- insert dependencies as required here -->
</bean>
<!-- in the child (descendant) context -->
<bean id="accountService" <!-- bean name is the same as the parent bean -->
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref parent="accountService"/> <!-- notice how we refer to the parent bean -->
</property>
<!-- insert other configuration and dependencies as required here -->
</bean>
注意
The local attribute on the ref element is no longer supported in the 4.0 beans XSD, since it does not provide value over a regular bean reference any more. Change your existing ref local references to ref bean when upgrading to the 4.0 schema.
在4.0版本的beans XSD中,不再支持ref元素上的local属性,因为它不再提供与常规bean引用相比的价值。在升级到4.0模式时,请将现有的ref local引用更改为ref bean。
1.4.3.3 内部 bean
Inner Beans
A <bean/> element inside the <property/> or <constructor-arg/> elements defines an inner bean, as the following example shows:
<property/> 或 <constructor-arg/> 元素内部的 <bean/> 元素定义了一个内部 bean,如下面的示例所示:
<bean id="outer" class="...">
<!-- instead of using a reference to a target bean, simply define the target bean inline -->
<property name="target">
<bean class="com.example.Person"> <!-- this is the inner bean -->
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
An inner bean definition does not require a defined ID or name. If specified, the container does not use such a value as an identifier. The container also ignores the scope flag on creation, because inner beans are always anonymous and are always created with the outer bean. It is not possible to access inner beans independently or to inject them into collaborating beans other than into the enclosing bean.
内部 bean 定义不需要一个已定义的 ID 或名称。如果指定了,容器不会将此值用作标识符。容器在创建时也会忽略作用域标志,因为内部 bean 总是匿名的,并且始终与外部 bean 一起创建。无法独立访问内部 bean,也无法将其注入到除封闭 bean 之外的协作 bean 中。
As a corner case, it is possible to receive destruction callbacks from a custom scope — for example, for a request-scoped inner bean contained within a singleton bean. The creation of the inner bean instance is tied to its containing bean, but destruction callbacks let it participate in the request scope’s lifecycle. This is not a common scenario. Inner beans typically simply share their containing bean’s scope.
作为一个特殊情况,可以从自定义作用域接收销毁回调 - 例如,对于包含在单例 bean 中的请求作用域内部 bean。内部 bean 实例的创建与其包含的 bean 相关联,但销毁回调使其参与到请求作用域的生命周期中。这不是常见的情况。内部 bean 通常只是共享其包含 bean 的作用域。
1.4.3.4 集合
Collections
The list>/, set>/, map/>, and props/> elements set the properties and arguments of the Java Collection types List, Set, Map, and Properties, respectively. The following example shows how to use them:
list/>、set/>、map/> 和 props/> 元素分别设置 Java 集合类型 List、Set、Map 和 Properties 的属性和参数。以下示例展示了如何使用它们:
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key="a ref" value-ref="myDataSource"/>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
The value of a map key or value, or a set value, can also be any of the following elements:
bean | ref | idref | list | set | map | props | value | null
1) 集合合并
Collection Merging
The Spring container also supports merging collections. An application developer can define a parent <list/>, <map/>, <set/> or <props/> element and have child <list/>, <map/>, <set/> or <props/> elements inherit and override values from the parent collection. That is, the child collection’s values are the result of merging the elements of the parent and child collections, with the child’s collection elements overriding values specified in the parent collection.
Spring 容器还支持集合的合并。应用程序开发人员可以定义一个父级 <list/>、<map/>、<set/> 或 <props/> 元素,并使子级 <list/>、<map/>、<set/> 或 <props/> 元素继承和覆盖父级集合中的值。也就是说,子级集合的值是父级集合和子级集合元素合并的结果,子级集合元素会覆盖父级集合中指定的值。
This section on merging discusses the parent-child bean mechanism. Readers unfamiliar with parent and child bean definitions may wish to read the relevant section before continuing.
本节讨论了父子 bean 机制的合并。对于不熟悉父子 bean 定义的读者,建议先阅读相关部分后再继续。
The following example demonstrates collection merging: 以下示例演示了集合的合并:
<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.com</prop>
<prop key="support">support@example.com</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="adminEmails">
<!-- the merge is specified on the child collection definition -->
<props merge="true">
<prop key="sales">sales@example.com</prop>
<prop key="support">support@example.co.uk</prop>
</props>
</property>
</bean>
Notice the use of the merge=true attribute on the element of the adminEmails property of the child bean definition. When the child bean is resolved and instantiated by the container, the resulting instance has an adminEmails Properties collection that contains the result of merging the child’s adminEmails collection with the parent’s adminEmails collection. The following listing shows the result:
请注意在子 bean 定义的 adminEmails 属性的 元素中使用了 merge=true 属性。当容器解析和实例化子 bean 时,生成的实例具有一个 adminEmails Properties 集合,其中包含子级 adminEmails 集合与父级 adminEmails 集合合并的结果。以下列表显示了结果:
administrator=administrator@example.com
sales=sales@example.com
support=support@example.co.uk
The child Properties collection’s value set inherits all property elements from the parent , and the child’s value for the support value overrides the value in the parent collection.
子级 Properties 集合的值集从父级 继承所有属性元素,并且子级对 support 值的设定会覆盖父级集合中的值。
This merging behavior applies similarly to the <list/>, <map/>, and <set/> collection types. In the specific case of the <list/> element, the semantics associated with the List collection type (that is, the notion of an ordered collection of values) is maintained. The parent’s values precede all of the child list’s values. In the case of the Map, Set, and Properties collection types, no ordering exists. Hence, no ordering semantics are in effect for the collection types that underlie the associated Map, Set, and Properties implementation types that the container uses internally.
这种合并行为同样适用于 <list/>、<map/> 和 <set/> 集合类型。在 <list/> 元素的特定情况下,维护了与 List 集合类型相关的语义(即有序值集合的概念)。父级的值位于所有子级列表的值之前。对于 Map、Set 和 Properties 集合类型,不存在排序。因此,对于容器在内部使用的关联 Map、Set 和 Properties 实现类型的集合类型,不会产生排序语义。
2) 集合合并的局限性
Limitations of Collection Merging
You cannot merge different collection types (such as a Map and a List). If you do attempt to do so, an appropriate Exception is thrown. The merge attribute must be specified on the lower, inherited, child definition. Specifying the merge attribute on a parent collection definition is redundant and does not result in the desired merging.
您不能合并不同的集合类型(例如 Map 和 List)。如果尝试这样做,会抛出适当的异常。merge 属性必须在较低、继承的子级定义上指定。在父级集合定义上指定 merge 属性是多余的,不会导致所需的合并。
3) 强类型集合
Strongly-typed collection
Thanks to Java’s support for generic types, you can use strongly typed collections. That is, it is possible to declare a Collection type such that it can only contain (for example) String elements. If you use Spring to dependency-inject a strongly-typed Collection into a bean, you can take advantage of Spring’s type-conversion support such that the elements of your strongly-typed Collection instances are converted to the appropriate type prior to being added to the Collection. The following Java class and bean definition show how to do so:
由于Java对泛型类型的支持,您可以使用强类型集合。也就是说,可以声明一个只能包含(例如)String元素的Collection类型。如果您使用Spring将强类型集合注入到一个bean中,您可以利用Spring的类型转换支持,将强类型集合实例的元素在添加到集合之前转换为适当的类型。以下是Java类和bean定义的示例,展示了如何实现这一点:
public class SomeClass {
private Map<String, Float> accounts;
public void setAccounts(Map<String, Float> accounts) {
this.accounts = accounts;
}
}
<beans>
<bean id="something" class="x.y.SomeClass">
<property name="accounts">
<map>
<entry key="one" value="9.99"/>
<entry key="two" value="2.75"/>
<entry key="six" value="3.99"/>
</map>
</property>
</bean>
When the accounts property of the something bean is prepared for injection, the generics information about the element type of the strongly-typed Map<String, Float> is available by reflection. Thus, Spring’s type conversion infrastructure recognizes the various value elements as being of type Float, and the string values (9.99, 2.75, and 3.99) are converted into an actual Float type.
当 something bean 的 accounts 属性准备进行注入时,通过反射可以获取关于强类型 Map<String, Float> 元素类型的泛型信息。因此,Spring 的类型转换基础设施将各个 value 元素识别为 Float 类型,并将字符串值(9.99、2.75 和 3.99)转换为实际的 Float 类型。
1.4.3.5 Null 和 “” 字符串值
Null and Empty String Values
Spring treats empty arguments for properties and the like as empty Strings. The following XML-based configuration metadata snippet sets the email property to the empty String value ("").
Spring将属性等的空参数视为空字符串。以下基于XML的配置元数据片段将email属性设置为空字符串值("")。
<bean class="ExampleBean">
<property name="email" value=""/>
</bean>
the preceding example is equivalent to the following Java code:
前面的示例等同于以下的Java代码:
exampleBean.setEmail("");
The <null/> element handles null values. The following listing shows an example:
<null/> 元素用于处理空值。以下代码示例:
<bean class="ExampleBean">
<property name="email">
<null/>
</property>
</bean>
The preceding configuration is equivalent to the following Java code:
exampleBean.setEmail(null);
1.4.3.6 使用p-命名空间的XML快捷方式:
XML Shortcut with the p-namespace
The p-namespace lets you use the bean element’s attributes (instead of nested elements) to describe your property values collaborating beans, or both.
使用p-命名空间,您可以使用bean元素的属性(而不是嵌套的元素)来描述属性值、协作bean,或者两者兼而有之。
Spring supports extensible configuration formats with namespaces, which are based on an XML Schema definition. The beans configuration format discussed in this chapter is defined in an XML Schema document. However, the p-namespace is not defined in an XSD file and exists only in the core of Spring.
Spring支持具有命名空间的可扩展配置格式,这些格式基于XML Schema定义。本章讨论的beans配置格式在一个XML Schema文档中定义。然而,p-命名空间没有在XSD文件中定义,只存在于Spring的核心中。
The following example shows two XML snippets (the first uses standard XML format and the second uses the p-namespace) that resolve to the same result:
以下示例展示了两个XML片段(第一个使用标准的XML格式,第二个使用p-命名空间),它们解析为相同的结果:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="classic" class="com.example.ExampleBean">
<property name="email" value="someone@somewhere.com"/>
</bean>
<bean name="p-namespace" class="com.example.ExampleBean"
p:email="someone@somewhere.com"/>
</beans>
The example shows an attribute in the p-namespace called email in the bean definition. This tells Spring to include a property declaration. As previously mentioned, the p-namespace does not have a schema definition, so you can set the name of the attribute to the property name.
示例中显示了bean定义中的p-命名空间中的属性email。这告诉Spring包含一个属性声明。如前所述,p-命名空间没有模式定义,因此您可以将属性名称设置为属性的名称。
This next example includes two more bean definitions that both have a reference to another bean:
以下是另一个示例,其中包含两个bean定义,它们都引用了另一个bean:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="john-classic" class="com.example.Person">
<property name="name" value="John Doe"/>
<property name="spouse" ref="jane"/>
</bean>
<bean name="john-modern"
class="com.example.Person"
p:name="John Doe"
p:spouse-ref="jane"/>
<bean name="jane" class="com.example.Person">
<property name="name" value="Jane Doe"/>
</bean>
This example includes not only a property value using the p-namespace but also uses a special format to declare property references. Whereas the first bean definition uses to create a reference from bean john to bean jane, the second bean definition uses p:spouse-ref="jane" as an attribute to do the exact same thing. In this case, spouse is the property name, whereas the -ref part indicates that this is not a straight value but rather a reference to another bean.
这个示例不仅包括使用 p-命名空间的属性值,还使用了一种特殊的格式来声明属性引用。第一个 bean 定义使用 来创建从 bean john 到 bean jane 的引用,而第二个 bean 定义使用 p:spouse-ref="jane" 作为属性来完成同样的事情。在这种情况下,spouse 是属性名称,而 -ref 部分表示这不是一个简单的值,而是对另一个 bean 的引用。
注意
note
The p-namespace is not as flexible as the standard XML format. For example, the format for declaring property references clashes with properties that end in Ref, whereas the standard XML format does not. We recommend that you choose your approach carefully and communicate this to your team members to avoid producing XML documents that use all three approaches at the same time.
p-命名空间不如标准的XML格式灵活。例如,声明属性引用的格式与以Ref结尾的属性冲突,而标准的XML格式则没有这个问题。我们建议您仔细选择您的方法,并将其与团队成员沟通,以避免同时在XML文档中使用三种方法。
1.4.3.7 使用c-命名空间的XML快捷方式:
XML Shortcut with the c-namespace
Similar to the XML Shortcut with the p-namespace, the c-namespace, introduced in Spring 3.1, allows inlined attributes for configuring the constructor arguments rather then nested constructor-arg elements.
与使用 p-命名空间的 XML 快捷方式类似,c-命名空间在 Spring 3.1 中引入,允许使用内联属性来配置构造函数参数,而不是嵌套的 constructor-arg 元素。
The following example uses the c: namespace to do the same thing as the from Constructor-based Dependency Injection:
以下示例使用 c: 命名空间来实现与基于构造函数的依赖注入中的 from 相同的功能:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
<!-- traditional declaration with optional argument names -->
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg name="thingTwo" ref="beanTwo"/>
<constructor-arg name="thingThree" ref="beanThree"/>
<constructor-arg name="email" value="something@somewhere.com"/>
</bean>
<!-- c-namespace declaration with argument names -->
<bean id="beanOne" class="x.y.ThingOne"
c:thingTwo-ref="beanTwo"
c:thingThree-ref="beanThree"
c:email="something@somewhere.com"/>
</beans>
The c: namespace uses the same conventions as the p: one (a trailing -ref for bean references) for setting the constructor arguments by their names. Similarly, it needs to be declared in the XML file even though it is not defined in an XSD schema (it exists inside the Spring core).
c: 命名空间使用与 p: 命名空间相同的约定(对于设置构造函数参数,使用 bean 引用的尾部 -ref)按名称设置构造函数参数。同样,即使在 XSD 模式中没有定义它(它存在于 Spring 核心中),也需要在 XML 文件中声明它。
For the rare cases where the constructor argument names are not available (usually if the bytecode was compiled without debugging information), you can use fallback to the argument indexes, as follows:
对于罕见的情况,如果构造函数参数名称不可用(通常是如果字节码编译时没有调试信息),您可以使用参数索引作为备选方案,如下所示:
<!-- c-namespace index declaration -->
<bean id="beanOne" class="x.y.ThingOne" c:_0-ref="beanTwo" c:_1-ref="beanThree"
c:_2="something@somewhere.com"/>
注意
note
Due to the XML grammar, the index notation requires the presence of the leading _, as XML attribute names cannot start with a number (even though some IDEs allow it). A corresponding index notation is also available for <constructor-arg> elements but not commonly used since the plain order of declaration is usually sufficient there.
由于XML语法的限制,索引表示法要求前面有下划线 _,因为XML属性名称不能以数字开头(尽管一些IDE允许这样)。<constructor-arg>元素也可以使用相应的索引表示法,但通常不常用,因为通常只需按照声明的顺序即可。
In practice, the constructor resolution mechanism is quite efficient in matching arguments, so unless you really need to, we recommend using the name notation throughout your configuration.
在实践中,构造函数解析机制非常有效地匹配参数,因此除非您真的需要,否则我们建议在整个配置中使用名称表示法。
1.4.3.8 复合属性名称
Compound Property Names
You can use compound or nested property names when you set bean properties, as long as all components of the path except the final property name are not null. Consider the following bean definition:
在设置bean属性时,您可以使用复合或嵌套的属性名称,只要路径的所有组件(除了最后一个属性名称)都不为null。考虑以下的bean定义:
<bean id="something" class="things.ThingOne">
<property name="fred.bob.sammy" value="123" />
</bean>
The something bean has a fred property, which has a bob property, which has a sammy property, and that final sammy property is being set to a value of 123. In order for this to work, the fred property of something and the bob property of fred must not be null after the bean is constructed. Otherwise, a NullPointerException is thrown.
something bean具有一个fred属性,该属性具有一个bob属性,该属性又具有一个sammy属性,最终的sammy属性被设置为123的值。为了使其正常工作,在构建bean之后,something的fred属性和fred的bob属性不能为null。否则,将抛出NullPointerException异常。
1.4.4 使用 depends-on (在 <bean/> 中使用 属性字段 depends-on)
Using depends-on
作用:提前加载需要的依赖项
If a bean is a dependency of another bean, that usually means that one bean is set as a property of another. Typically you accomplish this with the <ref/> element in XML-based configuration metadata. However, sometimes dependencies between beans are less direct. An example is when a static initializer in a class needs to be triggered, such as for database driver registration. The depends-on attribute can explicitly force one or more beans to be initialized before the bean using this element is initialized. The following example uses the depends-on attribute to express a dependency on a single bean:
如果一个bean是另一个bean的依赖项,通常意味着一个bean被设置为另一个bean的属性。通常,您可以使用XML配置元数据中的<ref/>元素来完成此操作。但是,有时bean之间的依赖关系不太直接。例如,当类中的静态初始化程序需要被触发时(例如数据库驱动程序注册),就需要使用depends-on属性来明确地强制初始化一个或多个bean,以便在使用此元素的bean被初始化之前进行初始化。以下示例使用depends-on属性来表示对单个bean的依赖关系:
<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />
To express a dependency on multiple beans, supply a list of bean names as the value of the depends-on attribute (commas, whitespace, and semicolons are valid delimiters):
表示对多个beans的依赖,可以提供一系列bean的名称作用 depends-on 属性字段的值(逗号,空格,分号都是有效的分隔符):
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
注意
note
The depends-on attribute can specify both an initialization-time dependency and, in the case of singleton beans only, a corresponding destruction-time dependency. Dependent beans that define a depends-on relationship with a given bean are destroyed first, prior to the given bean itself being destroyed. Thus, depends-on can also control shutdown order.
depends-on属性可以同时指定初始化时的依赖关系,以及仅适用于单例bean的相应销毁时的依赖关系。与给定bean建立depends-on关系的依赖bean将首先被销毁,然后才销毁给定的bean本身。因此,depends-on还可以控制关闭顺序。
1.4.5 延迟初始化 beans
# Lazy-initialized Beans
By default, ApplicationContext implementations eagerly create and configure all singleton beans as part of the initialization process. Generally, this pre-instantiation is desirable, because errors in the configuration or surrounding environment are discovered immediately, as opposed to hours or even days later. When this behavior is not desirable, you can prevent pre-instantiation of a singleton bean by marking the bean definition as being lazy-initialized. A lazy-initialized bean tells the IoC container to create a bean instance when it is first requested, rather than at startup.
默认情况下,ApplicationContext实现在初始化过程中会急切地创建和配置所有的单例bean。通常情况下,这种预实例化是可取的,因为可以立即发现配置或环境中的错误,而不是在几个小时甚至几天之后。当不希望出现这种行为时,可以通过将bean定义标记为延迟初始化来阻止单例bean的预实例化。延迟初始化的bean告诉IoC容器在首次请求时创建bean实例,而不是在启动时。
In XML, this behavior is controlled by the lazy-init attribute on the element, as the following example shows:
在XML中,可以通过<bean/>元素上的lazy-init属性来控制此行为,如下面的示例所示:
<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.something.AnotherBean"/>
When the preceding configuration is consumed by an ApplicationContext, the lazy bean is not eagerly pre-instantiated when the ApplicationContext starts, whereas the not.lazy bean is eagerly pre-instantiated.
当上述配置被ApplicationContext使用时,当ApplicationContext启动时,延迟初始化的bean不会被急切地预实例化,而不是延迟初始化的bean会被急切地预实例化。
However, when a lazy-initialized bean is a dependency of a singleton bean that is not lazy-initialized, the ApplicationContext creates the lazy-initialized bean at startup, because it must satisfy the singleton’s dependencies. The lazy-initialized bean is injected into a singleton bean elsewhere that is not lazy-initialized.
然而,当延迟初始化的bean是一个非延迟初始化的单例bean的依赖项时,ApplicationContext会在启动时创建延迟初始化的bean,因为它必须满足单例bean的依赖关系。延迟初始化的bean被注入到其他地方的非延迟初始化的单例bean中。
You can also control lazy-initialization at the container level by using the default-lazy-init attribute on the element, as the following example shows:
您还可以通过在<beans/>元素上使用default-lazy-init属性来控制容器级别的延迟初始化,如下面的示例所示:
<beans default-lazy-init="true">
<!-- no beans will be pre-instantiated... -->
</beans>
1.4.6 自动装配协作者(自动装配其他beans)
# Autowiring Collaborators
The Spring container can autowire relationships between collaborating beans. You can let Spring resolve collaborators (other beans) automatically for your bean by inspecting the contents of the ApplicationContext. Autowiring has the following advantages:
Spring容器可以自动解决协作bean之间的关系。您可以通过检查ApplicationContext的内容,让Spring自动为您的bean解析协作对象(其他bean)。自动装配具有以下优点:
Autowiring can significantly reduce the need to specify properties or constructor arguments. (Other mechanisms such as a bean template discussed elsewhere in this chapter are also valuable in this regard.)
自动装配可以显著减少指定属性或构造函数参数的需求。(本章其他地方讨论的bean模板等机制在这方面也很有价值。)
Autowiring can update a configuration as your objects evolve. For example, if you need to add a dependency to a class, that dependency can be satisfied automatically without you needing to modify the configuration. Thus autowiring can be especially useful during development, without negating the option of switching to explicit wiring when the code base becomes more stable.
随着对象的演变,自动装配可以更新配置。例如,如果您需要向一个类添加依赖关系,该依赖关系可以自动满足,而无需修改配置。因此,在开发过程中,自动装配特别有用,而不排除在代码基础更加稳定时切换到显式装配的选项。
When using XML-based configuration metadata (see Dependency Injection), you can specify the autowire mode for a bean definition with the autowire attribute of the <bean/> element. The autowiring functionality has four modes. You specify autowiring per bean and can thus choose which ones to autowire. The following table describes the four autowiring modes:
在使用基于XML的配置元数据(参见依赖注入)时,您可以使用<bean/>元素的autowire属性为bean定义指定自动装配模式。自动装配功能有四种模式。您可以为每个bean指定自动装配,因此可以选择要自动装配的bean。以下表格描述了四种自动装配模式:
1.4.6.1四种自动装配模式:
1) 不使用自动装配(默认)
no
(Default) No autowiring. Bean references must be defined by ref elements. Changing the default setting is not recommended for larger deployments, because specifying collaborators explicitly gives greater control and clarity. To some extent, it documents the structure of a system.
不使用自动装配。Bean引用必须通过ref元素来定义。不建议在较大的部署中更改默认设置,因为明确指定协作者可以提供更大的控制和清晰度。在一定程度上,它记录了系统的结构。
2) 按属性名称进行自动装配
byName
Autowiring by property name. Spring looks for a bean with the same name as the property that needs to be autowired. For example, if a bean definition is set to autowire by name and it contains a master property (that is, it has a setMaster(..) method), Spring looks for a bean definition named master and uses it to set the property.
按属性名称进行自动装配。Spring会寻找与需要自动装配的属性同名的bean。例如,如果一个bean定义被设置为按名称自动装配,并且它包含一个master属性(即具有setMaster(..)方法),Spring会寻找名为master的bean定义,并使用它来设置该属性。
3) 按属性类型进行自动装配
byType
Lets a property be autowired if exactly one bean of the property type exists in the container. If more than one exists, a fatal exception is thrown, which indicates that you may not use byType autowiring for that bean. If there are no matching beans, nothing happens (the property is not set).
如果容器中存在与属性类型完全匹配的唯一bean,则自动装配该属性。如果存在多个bean,则会抛出致命异常,表示您不能对该bean使用按类型自动装配。如果没有匹配的bean,则不会发生任何操作(属性不会被设置)。
4) 按构造函数进行自动装配
constructor
Analogous to byType but applies to constructor arguments. If there is not exactly one bean of the constructor argument type in the container, a fatal error is raised.
类似于按类型自动装配,适用于构造函数参数。如果容器中不存在恰好一个与构造函数参数类型匹配的bean,则会引发致命错误。
With byType or constructor autowiring mode, you can wire arrays and typed collections. In such cases, all autowire candidates within the container that match the expected type are provided to satisfy the dependency. You can autowire strongly-typed Map instances if the expected key type is String. An autowired Map instance’s values consist of all bean instances that match the expected type, and the Map instance’s keys contain the corresponding bean names.
使用按类型或构造函数自动装配模式,您可以连接数组和类型化集合。在这种情况下,容器中与期望类型匹配的所有自动装配候选项都会被提供以满足依赖关系。如果期望的键类型是String,您可以自动装配强类型的Map实例。自动装配的Map实例的值由与期望类型匹配的所有bean实例组成,而Map实例的键包含相应的bean名称。
1.4.6.2自动装配的局限性与缺点
Limitations and Disadvantages of Autowiring
Autowiring works best when it is used consistently across a project. If autowiring is not used in general, it might be confusing to developers to use it to wire only one or two bean definitions.
自动装配在整个项目中一贯使用时效果最佳。如果通常不使用自动装配,仅在一个或两个bean定义中使用它可能会让开发人员感到困惑。
Consider the limitations and disadvantages of autowiring:
- Explicit dependencies in property and constructor-arg settings always override autowiring. You cannot autowire simple properties such as primitives, Strings, and Classes (and arrays of such simple properties). This limitation is by-design.
属性和构造函数参数设置中的显式依赖始终会覆盖自动装配。您无法自动装配简单的属性,例如基本类型、字符串和类(以及这些简单属性的数组)。这是一种有意设计的限制。
- Autowiring is less exact than explicit wiring. Although, as noted in the earlier table, Spring is careful to avoid guessing in case of ambiguity that might have unexpected results. The relationships between your Spring-managed objects are no longer documented explicitly.
自动装配比显式装配不够精确。尽管如前面的表格所指出的,Spring在可能产生歧义且可能导致意外结果的情况下会小心避免猜测。你的Spring管理的对象之间的关系不再被明确地记录。
- Wiring information may not be available to tools that may generate documentation from a Spring container.
从Spring容器生成文档的工具可能无法获得有关装配信息。
- Multiple bean definitions within the container may match the type specified by the setter method or constructor argument to be autowired. For arrays, collections, or Map instances, this is not necessarily a problem. However, for dependencies that expect a single value, this ambiguity is not arbitrarily resolved. If no unique bean definition is available, an exception is thrown.
容器中的多个bean定义可能与要自动装配的setter方法或构造函数参数指定的类型匹配。对于数组、集合或Map实例,这通常不是一个问题。然而,对于期望单个值的依赖项,这种歧义不能任意解决。如果没有唯一的bean定义可用,将抛出异常。
In the latter scenario, you have several options:
在后一种情况下,你有几个选择:
-
Abandon autowiring in favor of explicit wiring.
放弃自动装配,改用显式装配。
-
Avoid autowiring for a bean definition by setting its autowire-candidate attributes to false, as described in the next section.
将bean定义的autowire-candidate属性设置为false,以避免自动装配,具体描述在下一节中。
-
Designate a single bean definition as the primary candidate by setting the primary attribute of its <bean/> element to true.
将单个bean定义指定为主要候选项,通过将其<bean/>元素的primary属性设置为true。(primary="true")
-
Implement the more fine-grained control available with annotation-based configuration, as described in Annotation-based Container Configuration.
根据《基于注解的容器配置》中所述,实现更精细的控制,使用基于注解的配置方式。
1.4.6.3 在自动装配中排除指定bean
Excluding a Bean from Autowiring
On a per-bean basis, you can exclude a bean from autowiring. In Spring’s XML format, set the autowire-candidate attribute of the element to false. The container makes that specific bean definition unavailable to the autowiring infrastructure (including annotation style configurations such as @Autowired ).
对于每个bean,您可以将其排除在自动装配之外。在Spring的XML格式中,将元素的autowire-candidate属性设置为false。容器将使该特定bean定义对自动装配基础设施不可用(包括注解样式配置,如@Autowired)。
注意
note
The autowire-candidate attribute is designed to only affect type-based autowiring. It does not affect explicit references by name, which get resolved even if the specified bean is not marked as an autowire candidate. As a consequence, autowiring by name nevertheless injects a bean if the name matches.
autowire-candidate属性仅影响基于类型的自动装配。它不会影响通过名称进行的显式引用,即使指定的bean未标记为自动装配候选项,也会被解析。因此,通过名称进行的自动装配仍然会注入一个bean,如果名称匹配的话。
You can also limit autowire candidates based on pattern-matching against bean names. The top-level <beans/> element accepts one or more patterns within its default-autowire-candidates attribute. For example, to limit autowire candidate status to any bean whose name ends with Repository, provide a value of *Repository. To provide multiple patterns, define them in a comma-separated list. An explicit value of true or false for a bean definition’s autowire-candidate attribute always takes precedence. For such beans, the pattern matching rules do not apply.
您还可以根据与bean名称的模式匹配来限制自动装配候选项。顶层的元素在其default-autowire-candidates属性中接受一个或多个模式。例如,要将自动装配候选状态限制为名称以Repository结尾的任何bean,提供一个值为*Repository。要提供多个模式,请以逗号分隔的列表形式定义它们。对于bean定义的autowire-candidate属性,显式的true或false值始终优先。对于这样的bean,模式匹配规则不适用。
These techniques are useful for beans that you never want to be injected into other beans by autowiring. It does not mean that an excluded bean cannot itself be configured by using autowiring. Rather, the bean itself is not a candidate for autowiring other beans.
未完待续.........