【Spring】Spring Framework Reference Documentation中文版3

来源:互联网 发布:开发者没有网络adb调试 编辑:程序博客网 时间:2024/04/20 02:48

Part III. Core Technologies

核心技术

 

This part of the reference documentation covers all of those technologies that are absolutely integral to the Spring Framework.

文档的这个部分包含所有这些技术,是spring框架的最重要的部分。

 

Foremost amongst these is the Spring Frameworks Inversion of Control (IoC) container. A thorough treatment of the Spring Frameworks IoC container is closely followed by comprehensive coverage of Springs 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容器近乎覆盖了SpringAOP编程技术。Spring框架有自己的AOP框架,从概念上比较容易理解,在Java企业级编程中有百分之八十的企业从中受益。

 

Coverage of Springs 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(当前最好的-依据其特性-是当前最成熟的AOP实现在Java企业领域)也是支持的。

 

7. The IoC container

IOC容器

7.1 Introduction to the Spring IoC container and beans

Spring IOC容器和bean的介绍

 

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 (IoC), 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作为依赖注入广为人知。这其实是一个过程,object定义他们的依赖,就是需要其他object才能工作。通过构造器参数、工厂方法的参数或者对objectset,当在构造器调用之后或工厂方法中返回。当创建bean后容器然后注入这些依赖。这个过程是反过来的,因此名字叫控制反转。对于bean自身控制实例化或定位通过直接使用类的构造或服务定位模式的原理。

 

The org.springframework.beans and org.springframework.context packages are the basis for Spring Frameworks 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 Springs AOP features; message resource handling (for use in internationalization), event publication; and application-layer specific contexts such as the WebApplicationContext for use in web applications.

org.springframework.beans包和org.springframework.context包是spring框架IOC容器的基础。BeanFactory接口提供了一个高级的可配置的机制用于管理任意类型的objectApplicationContextBeanFactory的子接口。添加了一些简单的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 Springs IoC container. For more information on using the BeanFactory instead of the ApplicationContext, refer to Section 7.16,The BeanFactory.

简而言之,BeanFactory提供了对框架的配置和基本的功能,ApplicationContext增加了更加符合企业化的功能。ApplicationContextBeanFactory的一个超集,而且仅仅用于本章描述的IOC容器中。更多有关使用BeanFactory代替ApplicationContext的内容,见7.16章节。

 

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 otherwise 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中,objects组成了你应用的骨架,并且有springIOC容器管理,叫做beans。一个bean就是一个被spring ioc容器管理的已经实例化、组装好的object。其他方面,一个bean就是你应用很多object中其中的一个。Beans和他们之间的依赖关系映射在容器使用的配置元信息中。

 

7.2 Container overview

容器概览

 

The interface org.springframework.context.ApplicationContext represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the aforementioned 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 allows you to express the objects that compose your application and the rich interdependencies between such objects.

org.springframework.context.ApplicationContext接口代表springIOC容器,任务时实例化、配置和组装成前面提到的beans。容器通过读取配置元信息获得他的构造器,用于object的实例化、配置和组装。配置元数据可以在XML中、Java注解中或Java代码中。他允许你描述组成你的应用的objectsobjects之间的依赖联系。

 

Several implementations of the ApplicationContext interface are supplied out-of-the-box with Spring. In standalone 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.

一些ApplicationContext接口的实现在spring中可以直接使用。在一个独立的应用中,通常会建立一个ClassPathXmlApplicationContextFileSystemXmlApplicationContext的实例。当XML应经成为传统的描述信息的方法时,你可以使用Java的注解或则提供一个简单的XML配置文件来定义一些额外的元数据信息。

 

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 will typically suffice (see Section 7.15.4, Convenient ApplicationContext instantiation for web applications). If you are using the Spring Tool Suite Eclipse-powered development environment this boilerplate configuration can be easily created with few mouse clicks or keystrokes.

在大部分应用场景中,不需要用户代码显式的实例化spring IOC容器中的一个或多个实例。例如,在一个web应用场景中,一个大约八行左右的web描述xml文件在web.xml中就可以实现这个功能。(见7.15.4章节 方便的ApplicationContext实例化用于web应用)。如果你使用Eclipse这样强大的开发环境中的spring工具,通过鼠标的几次点击和键盘输入就可以实现。

 

The following diagram is 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创建和初始化以后,你就可以完全操控和执行系统和应用了。

 

Figure 7.1. The Spring IoC container

sping IOC容器

 

7.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容器来初始化实例、配置和集合应用的object

 

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容器中关键的信息和特性。

 

[Note]

注意

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.

基于xml的元数据不只允许配置元数据。spring IOC容器本身已经从配置元数据中分离。最近很多开发者选择使用基于java的配置为他们的spring应用。

 

For information about using other forms of metadata with the Spring container, see:

使用spring容器的其他形式的元数据,见

 

    Annotation-based configuration: Spring 2.5 introduced support for annotation-based configuration metadata.

基于注解的配置:spring2.5支持注解配置元数据。

    Java-based configuration: Starting with Spring 3.0, many features provided by the Spring JavaConfig project became part of the core Spring Framework. Thus you can define beans external to your application classes by using Java rather than XML files. To use these new features, see the @Configuration, @Bean, @Import and @DependsOn annotations.

基于java的配置:从spring3.0开始,许多spring JavaConfig工程中的特性已经加入了spring框架的核心包。以方便你在应用中通过java来定义bean而不是使用xml文件。如果需要使用这些新特性,见@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 shows these beans configured as <bean/> elements inside a top-level <beans/> element. Java configuration typically uses @Bean annotated methods within a @Configuration class.

spring的配置中至少有一个或多个bean的定义需要容器来管理。基于xml的配置元数据显示bean需要使用<bean>元素,并且顶层元素是<beans>java配置通常使用在@Configuration的类中定义@Bean修饰的方法。

 

These bean definitions correspond to the actual objects that make up your application. Typically you define service layer objects, data access objects (DAOs), presentation objects such as Struts Action instances, infrastructure objects such as Hibernate SessionFactories, JMS Queues, and so forth. Typically one does not configure fine-grained domain objects in the container, because it is usually the responsibility of DAOs and business logic to create and load domain objects. However, you can use Springs integration with AspectJ to configure objects that have been created outside the control of an IoC container. See Using AspectJ to dependency-inject domain objects with Spring.

bean的定义取决组成你应用的实际object。通常你会定于服务层object、数据访问objectDAOs)、类似于Struts Action的表现层object和类似于Hibernate SessionFactoryJMS队列等的基础设置object。通常不会定义所有的object,一般将与DAO或业务逻辑有关的object定义为bean。然而你可以使用AspectJ来控制没有被IOC容器包含的外部bean。见在spring中使用AspectJ来依赖注入object

 

The following example shows the basic structure of XML-based configuration metadata:

下面的例子展示了基于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

        http://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>

The id attribute is a string that you use to identify the individual bean definition. The class attribute defines the type of the bean and uses the fully qualified classname. The value of the id attribute refers 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的类型并且需要使用全限定的类名。value属性定义了bean包含的object。在xml并没有说明如何引用外部bean。详见依赖。

 

7.2.2 Instantiating a container

实例化一个容器

 

Instantiating a Spring IoC container is straightforward. The location path or paths supplied to an ApplicationContext constructor are actually resource strings that allow the container to load configuration metadata from a variety of external resources such as the local file system, from the Java CLASSPATH, and so on.

实例化一个spirng IOC容器是简单的。提供给ApplicationContext构造器的实际的资源字符串允许容器可以在本地文件系统或java classpath或其他中定位配置元数据。

 

ApplicationContext context =

    new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});

 

[Note]

注意

 

After you learn about Springs IoC container, you may want to know more about Springs Resource abstraction, as described in Chapter 8, 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 Section 8.7,Application contexts and Resource paths.

学习到现在,你或许想更深入知道spring的资源抽象,可以看第8章节的描述,提供了方便的方法从定义的URI表达式中读取输入流。另外,使用在构造器的使用说明可以看8.7章节,“应用上下文和资源路径”。

 

The following example shows the service layer objects (services.xml) configuration file:

下面的例子展示了服务层objectservices.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

        http://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>

The following example shows the data access objects daos.xml file:

下面的例子展示了数据访问objcetdaos.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

        http://www.springframework.org/schema/beans/spring-beans.xsd">

 

    <bean id="accountDao"

        class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">

        <!-- additional collaborators and configuration for this bean go here -->

    </bean>

 

    <bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">

        <!-- additional collaborators and configuration for this bean go here -->

    </bean>

 

    <!-- more bean definitions for data access objects go here -->

 

</beans>

 

In the preceding example, the service layer consists of the class PetStoreServiceImpl, and two data access objects of the type 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 objects dependencies, see Dependencies.

在上面的例子中,服务层包含PetStoreServiceImpl类和两个数据访问object,类型是JpaAccountDaoJpaItemDao(基于独立的JPA ORM标准)。name元素指向JavaBean属性的名字,ref元素指向另一个bean的定义。idref元素之间的关联表达了相关object的合作。配置object依赖的详情见依赖。

 

Composing XML-based configuration metadata

排版基于xml的配置元数据

 

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.

将定义分开到多个xml文件是有用的。每一个独立的xml配置文件代表你应用架构中的一个逻辑或模块。

 

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 <import/> element to load bean definitions from another file or files. For example:

你可以通过构造器从所有的xml片段中读取bean的定义。构造器支持多个资源的路径就像前面的那个例子。或者你也可以使用<import/>标签来从其他文件中引入作为代替。例如:

 

<beans>

    <import resource="services.xml"/>

    <import resource="resources/messageSource.xml"/>

    <import resource="/resources/themeSource.xml"/>

 

    <bean id="bean1" class="..."/>

    <bean id="bean2" class="..."/>

</beans>

 

In the preceding example, external bean definitions are loaded from three files: services.xml, messageSource.xml, and themeSource.xml. All location paths are relative to the definition file doing the importing, so services.xml must be in the same directory or classpath location as the file doing the importing, while messageSource.xml and themeSource.xml must be in a resources location below the location of the importing file. As you can see, a leading slash is ignored, but given that these paths are relative, it is better form not to use the slash at all. The contents of the files being imported, including the top level <beans/> element, must be valid XML bean definitions according to the Spring Schema.

在前面的例子中,外部的bean定义加载自三个文件:services.xmlmessageSource.xmlthemeSource.xml中。所有的路径依赖于定义的引入的文件。因此因此service.xml文件必须和引入的文件在同一个目录或classpath中。当messageSource.xmlthemeSource.xml的资源位置必须是在引入文件的下面。你也看到了,看是的斜线被忽略了,但是但是这三个路径是相关的,但是最好不要是用那个斜线。被引入的文件的内容,包括顶层的<beans>元素,必须是一个符合spring schema的文件定义。

 

[Note]

注意

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:"URL中也是不推荐的(例如:"classpath:../services.xml"),当运行时资源进程会先选择最近的classpath,然后在寻找上一级的路径。classpath配置的改变将会导致选择的不同,从而产生错误的路径。

 

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 applications 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的系统属性在运行时确定。

 

7.2.3 Using the container

使用容器

 

The ApplicationContext is the interface for an advanced factory capable of maintaining a registry of different beans and their dependencies. Using the method T getBean(String name, Class<T> requiredType) you can retrieve instances of your beans.

ApplicationContext是一个接口用于高级的工厂保持不同bean和他们的依赖。使用方法T getBean(String name, Class<T> requiredType)你可以取回你bean的实例对象。

 

The ApplicationContext enables you to read bean definitions and access them as follows:

ApplicationContext允许你通过下面的方式读取bean的定义和访问他们:

 

// create and configure beans 创建和配置beans

ApplicationContext context =

    new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});

 

// retrieve configured instance 取得配置的实例

PetStoreService service = context.getBean("petStore", PetStoreService.class);

 

// use configured instance 使用取得的配置的实例

List<String> userList = service.getUsernameList();

 

You 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 no dependency on Spring APIs at all. For example, Springs integration with web frameworks provides for dependency injection for various web framework classes such as controllers and JSF-managed beans.

你可以使用getBean()用来取得beans的实例。ApplicationContext接口也提供了一些其他方法来取得beans,但是理想中你的应用应该永远不会使用他们。的确,你的应用代码不应该调用getBean()方法,对springAPI也应该保持这个原则。例如,springweb框架的集成提供了依赖注入用于不同的web框架类例如控制器和JSF管理的bean

 

7.3 Bean overview

bean的概览

 

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.

springIOC框架管理一个或多个bean。这些bean由你提供给容器的配置元数据创建,例如,在xmlbean的定义。

 

Within the container itself, these bean definitions are represented as BeanDefinition objects, which contain (among other information) the following metadata:

在容器中,这些bean的定义被作为BeanDefinition object,包括以下的元数据(包括其他的信息)

 

    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).

bean行为配置元素,显示bean在容器中的类型(范围、生命周期、回调等等)。

    References to other beans that are needed for the bean to do its work; these references are also called collaborators or dependencies.

指向其他bean的引用,为了使得bean可以工作,这些引用被叫做协作或依赖。

    Other configuration settings to set in the newly created object, for example, the number of connections to use in a bean that manages a connection pool, or the size limit of the pool.

其他的配置在刚刚创建的object中,例如,用在bean上的连接数用于管理连接池或池的限制数目。

 

This metadata translates to a set of properties that make up each bean definition.

元数据转化为一系列的属性用于完成bean的定义

Table7.1.The bean definition

属性

说明位置

class

Section7.3.2,Instantiating beans

name

Section7.3.1,Naming beans

scope

Section7.5,Bean scopes

constructor arguments

Section7.4.1,Dependency Injection

properties

Section7.4.1,Dependency Injection

autowiring mode

Section7.4.5,Autowiring collaborators

lazy-initialization mode

Section7.4.4,Lazy-initialized beans

initialization method

the section calledInitialization callbacks

destruction method

the section calledDestruction 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 ApplicationContexts BeanFactory via the method getBeanFactory() which returns the BeanFactory implementation DefaultListableBeanFactory. DefaultListableBeanFactory supports this registration through the methods registerSingleton(..) and registerBeanDefinition(..). However, typical applications work solely with beans defined through metadata bean definitions.

除此之外,bean的信息中包括创建一个特殊的beanApplicationContext的实现也允许将用户在容器外已经创建的对象注册为bean。他的实现是通过getBeanFactory方法返回的BeanFactory的实现DefaultListableBeanFactory来访问ApplicationContextBeanFactoryDefaultListableBeanFactory支持通过registerSingletonregisterBeanDefinition来注册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 of existing metadata and existing singleton instances is supported to some degree, the registration of new beans at runtime (concurrently with live access to factory) is not officially supported and may lead to concurrent access exceptions and/or inconsistent state in the bean container.

Bean的元数据和手动添加的单例实例需要尽早注册,为了使容器正确推断它们在自动装配和其他内省的步骤。覆盖已经存在的元数据和已经存在的单例实例在一定程度上是支持的,在运行时注册新的bean(并发的访问工厂)在官方上是不支持的,或许会导致并发访问的异常或不一致的状态在bean的容器中。

 

7.3.1 Naming beans

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, but 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 and/or name attributes to specify the bean identifier(s). The id attribute allows you to specify exactly one id. Conventionally these names are alphanumeric ('myBean', 'fooService', etc.), but may contain special characters as well. If you want to introduce other aliases to the bean, you can also specify them in the name attribute, separated by a comma (,), semicolon (;), or white space. As a historical note, in versions prior to Spring 3.1, the id attribute was defined as an xsd:ID type, which constrained possible characters. As of 3.1, it is defined as an xsd:string type. Note that bean id uniqueness is still enforced by the container, though no longer by XML parsers.

基于xml配置的元数据,你可以使用idname属性来定义一个beanid属性允许你指定恰当的id。通常他们的名字应该是英文('myBean', 'fooService'等等),或许也会包含特殊的字符。如果你想给你的bean起一个别名,你可以在name属性中定义,用逗号或分号或者空格隔开。在spring3.1之前,id属性是作为一个xsd:ID类型的,并且包含合适的字符。在3.1版本中,他是一个xsd:string的类型。id是唯一的仍然作为容器的强制要求,尽管不会被xml解析。

 

You are not required to supply a name or id for a bean. If no name or id is supplied 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 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起一个idname。如果一个bean没有idname,容器会为id生成一个唯一的name。然而,如果你想通过名字来引用bean,或者通过ref标签来引用bean或者使用Service Locator style lookup,你必须为bean提供一个name

 

Bean Naming Conventions

bean的命名规范

 

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 then on. Examples of such names would be (without quotes) 'accountManager', 'accountService', 'userDao', 'loginController', and so forth.

规范和标准java对实例属性的命名规范相同。那就是,bean的名字由小写字母开头,然后采用驼峰式。例如这样的名字'accountManager''accountService''userDao''loginController'等等。

 

Naming beans consistently makes your configuration easier to read and understand, and if you are using Spring AOP it helps a lot when applying advice to a set of beans related by name.

bean命名的一致性使得你的配置更容易阅读和理解,如果你在使用springaop,这会对你有益,当你应用advice对一系列的bean通过name的时候。

 

[Note]

注意

 

With component scanning in the classpath, Spring generates bean names for unnamed components, following the rules above: 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 is using here).

当使用classpath下的组件扫描时,spring会为每个未命名的组件生成名字,规则是:将类名的首字母小写。然而,有一些特殊情况,比如第一个和第二个字符都是大写,则保留原有的名字。这和java.beans.Introspector.decapitalize的规则是一样的(spring在这里使用)。

 

Aliasing a bean outside the bean definition

为外部定义的bean起别名

 

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 allowing each component in an application to refer to a common dependency by using a bean name that is specific to that component itself.

在定义bean的时候,你可以提供多个name,通过id指定唯一的一个name,然后通过name指定多个name。这些name可以别名为相同的bean,并且在很多场景中有用,比如允许一个应用引用这个依赖通过使用组件定义的name

 

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, each subsystem having its own set of object definitions. In XML-based configuration metadata, you can use the <alias/> element to accomplish this.

指定bean已经定义的别名是不够的。然而介绍一个别名的定义是有意义的。在一个大型的系统中,配置被切分通过子系统,每个子系统有其自己的object的定义。在基于xml的元数据配置中,你可以使用<alias/>标签来完成别名的定义。

 

<alias name="fromName" alias="toName"/>

 

In this case, a bean in the same container which is named fromName, may also, after the use of this alias definition, be referred to as toName.

在这种情况下,在同一个容器中叫fromName,但是在使用了别名之后,toName指向了bean

 

For example, the configuration metadata for subsystem A may refer to a DataSource via the name subsystemA-dataSource. The configuration metadata for subsystem B may refer to a DataSource via the name subsystemB-dataSource. When composing the main application that uses both these subsystems the main application refers to the DataSource via the name myApp-dataSource. To have all three names refer to the same object you add to the MyApp configuration metadata the following aliases definitions:

例如,子系统A的配置元数据指向数据源通过subsystemA-dataSource。子系统B的配置元数据指向数据源通过subsystemB-dataSource。主应用集成两个子系统,并且通过myApp-dataSource来指向DataSource。为了让这三个source指向同一个配置元数据,你可以如下所示定义配置元属性。

 

<alias name="subsystemA-dataSource" alias="subsystemB-dataSource"/>

<alias name="subsystemA-dataSource" alias="myApp-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.

现在主应用可以指向DataSources通过一个唯一的名字,并且保证不会产生冲突,(更加有效地创建命名空间)指向相同的bean

 

Java-configuration

java配置

 

If you are using Java-configuration, the @Bean annotation can be used to provide aliases see Section 7.12.3,Using the @Bean annotationfor details.

如果你使用代码配置,@Bean注解可以被使用用于提供别名,详见7.12.3章节,使用@Bean注解。

 

7.3.2 Instantiating beans

bean的实例化

 

A bean definition essentially is 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的定义用于实例化一个或多个object。容器根据bean的要求,使用配置元数据封装bean的定义创建(或获得)一个实际的object

 

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 <bean/> element. This class attribute, which internally is a Class property on a BeanDefinition instance, is usually mandatory. (For exceptions, see the section called Instantiation using an instance factory methodand Section 7.7,Bean definition inheritance.) You use the Class property in one of two ways:

如果你使用基于xml的配置元数据,你在bean标签定义的class属性将会是object实例化的类型(或class)。这个class属性中必须强制定义一个class用于一个bean定义的实体。(例如,见使用实例工厂方法实例化和7.7bean定义的继承)

 

    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 using the new operator.

通常,定义bean的类用于构造以方便容器自身通过反射调用它的构造器创建实例,有时可java代码使用new操作符类似。

    To specify the actual class containing the static factory method that will be 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.

声明包含静态工厂方法的实际类用于创建object,在很少的情况下容器会调用类的静态工厂方法用于创建bean。调用静态工厂方法的返回值可能是相同的类或完全是另外一个类。

 

Inner class names.  If you want to configure a bean definition for a static nested class, you have to use the binary name of the nested class.

内部类的name。如果你想为静态内部类配置bean的定义,你必须使用内部类的binary name

 

For example, if you have a class called Foo in the com.example package, and this Foo class has a static nested class called Bar, the value of the 'class' attribute on a bean definition would be?

例如,如果在com.example包下有个类叫Foo,并且Foo有个内部类叫Bar,那么class属性的值应该是?

 

com.example.Foo$Bar

 

Notice the use of the $ character in the name to separate the nested class name from the outer class name.

注意,在name中使用$符号用于区分内部类和外部类。

 

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,所有的normal类将会适合spring。这样,class不需要实现任何接口或需要特定的编码风格。只要正常定义类就可以。然而,依赖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.

springioc容器可以管理你需要让他管理的任何类,并不只限于管理JavaBean。大部分spring的用户为容器中的JavaBean提供一个默认无参构造器、setget方法。你也可以在容器中包含exotic non-bean-style的类。例如,你需要使用一个连接池并且很明显这个和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.

如果想了解向构造器提供参数的机理或在构造之后设置object,详见依赖注入。

 

Instantiation with a static factory method

使用静态工厂方法实现实例化

 

When defining a bean that you create with a static factory method, you use the class attribute to specify the class containing 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来定义工厂方法自身的名字。你应该可以调用这个方法(使用后续描述的可选参数)并且返回一个liveobject,这个object和用构造器创建的没有什么区别。这样的用法通常是为了调用静态工厂在legacy的代码中。

 

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, only the class containing the factory method. In this example, the createInstance() method must be a static method.

下面的bean定义了这个bean将会被工厂方法来创建。这个定义没有定义返回object的类型,只有这个类包含工厂方法。在这个例子中,createInstance方法必须是静态方法。

 

<bean id="clientService"

    class="examples.ClientService"

    factory-method="createInstance"/>

 

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.

如果想了解向工厂方法提供参数的机理或在构造之后设置object,详见依赖和配置。

 

Instantiation 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/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.

和使用静态工厂方法初始化类似,使用实例化工厂方法调用一个已经存在的bean的非静态方法从构造器中创建一个新的bean。使用这样的特性,需要将class属性设置为空,并且在factory-bean属性中定义当前容器或父容器中包含创建object的方法的类。然后在factory-method的属性中设置工厂方法的名字。

 

<!-- the factory bean, which contains a method called createInstance() -->

工厂bean,包含一个方法名为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通过工厂bean来创建

<bean id="clientService"

    factory-bean="serviceLocator"

    factory-method="createClientServiceInstance"/>

 

public class DefaultServiceLocator {

 

    private static ClientService clientService = new ClientServiceImpl();

    private DefaultServiceLocator() {}

 

    public ClientService createClientServiceInstance() {

        return clientService;

    }

}

 

One factory class can also hold more than one factory method as shown here:

一个工厂类也可以有多个工厂方法如下

 

<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"/>

 

public class DefaultServiceLocator {

 

    private static ClientService clientService = new ClientServiceImpl();

    private static AccountService accountService = new AccountServiceImpl();

 

    private DefaultServiceLocator() {}

 

    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自身也可以通过依赖注入来管理和配置。详见依赖和配置。

 

[Note]

注意

 

In Spring documentation, factory bean refers to a bean that is configured in the Spring container that will create objects through an instance or static factory method. By contrast, FactoryBean (notice the capitalization) refers to a Spring-specific FactoryBean.

spring文档中,工厂beanspring容器配置的一个bean可以用来创建object或通过静态工厂方法。FactoryBean(注意大小写)就是spring的特殊的FactoryBean

 

7.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.

一个典型的企业应用不可能只包含单一的object(或者beanspring中)。甚至是最简单的应用都有几个object一起工作使得终端用户得到一个一致的应用。下一个章节解释你应该如何定义bean独立于一个已经实现的很多object一起工作的应用中。

 

7.4.1 Dependency Injection

依赖注入

 

Dependency injection (DI) 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 (IoC), 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.

依赖注入是一个过程,当object定义他们的依赖也就是和其他object的合作关系,通过构造器参数、工厂方法的参数或他们在object中定义的属性、或者一个object被构造返回或通过工厂方法返回的object。容器在创建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 such, your classes become easier to test, in particular when the dependencies are on interfaces or abstract base classes, which allow for stub or mock implementations to be used in unit tests.

使用依赖注入会是代码变得简单并且更加有效当object是通过依赖提供的。object不需要寻找依赖并且代码也无须知道依赖类的位置。因此,你的类将更加容易测试,特别的当对接口或抽象类依赖时,允许在单元测试中屏蔽或模拟实现。

 

DI exists in two major variants, Constructor-based dependency injection and Setter-based dependency injection.

依赖注入有两种主要的方式,构造注入和基于setter方法的注入。

 

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. 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.

基于构造器的注入是通过容器调用带有参数的构造方法来实现的,每个参数代表一个依赖。调用一个有参数的静态工厂方法来构建bean和这个有些类似,而且和静态工厂方法对待参数的形式类似。下面的例子展示了一个类使用构造器的依赖注入。注意这个类并没有什么特殊,只是一个POJO而且和容器的任何接口、类和注解绑定。

 

public class SimpleMovieLister {

 

    // the SimpleMovieLister has a dependency on a MovieFinder

// SimpleMovieLister依赖于MovieFinder

    private MovieFinder movieFinder;

 

    // a constructor so that the Spring container can inject a MovieFinder

// 一个构造器允许spring用来注入一个MovieFinder

    public SimpleMovieLister(MovieFinder movieFinder) {

        this.movieFinder = movieFinder;

    }

 

    // business logic that actually uses the injected MovieFinder is omitted...

 

}

 

Constructor argument resolution

构造器参数的解析

 

Constructor argument resolution matching occurs using the arguments type. If no potential ambiguity exists in the constructor arguments of a bean definition, then 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定义没有潜在的歧义存在,那么构造器中参数的位置和提供给构造的参数依赖必须是相同的顺序。考虑下面的例子。

 

package x.y;

 

public class Foo {

 

    public Foo(Bar bar, Baz baz) {

        // ...

    }

 

}

 

No potential ambiguity exists, assuming that Bar and Baz classes are not related by inheritance. Thus the following configuration works fine, and you do not need to specify the constructor argument indexes and/or types explicitly in the <constructor-arg/> element.

没有歧义存在,假设BarBaz没有直接的继承关系。那么下面的配置是没有问题,而且你不需要在<constructor-arg/>元素中定义构造器参数的index或者明确的类型。

 

<beans>

    <bean id="foo" class="x.y.Foo">

        <constructor-arg ref="bar"/>

        <constructor-arg ref="baz"/>

    </bean>

 

    <bean id="bar" class="x.y.Bar"/>

 

    <bean id="baz" class="x.y.Baz"/>

</beans>

 

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 <value>true</value>, Spring cannot determine the type of the value, and so cannot match by type without help. Consider the following class:

如果有另一个bean被引用,类型是未知的,并且可以匹配(就像前面的例子)。当一个简单的类型被使用,例如<value>true</value>spring不能决定值的类型,因此就无法匹配。考虑下面的这个类:

 

package examples;

 

public class ExampleBean {

 

    // Number of years to calculate the Ultimate Answer

    private int years;

 

    // The Answer to Life, the Universe, and Everything

    private String ultimateAnswer;

 

    public ExampleBean(int years, String ultimateAnswer) {

        this.years = years;

        this.ultimateAnswer = ultimateAnswer;

    }

 

}

 

In the preceding scenario, the container can use type matching with simple types if you explicitly specify the type of the constructor argument using the type attribute. For example:

在上面的例子中,如果你可以在构造器的参数声明中指定type属性,那么容器的类型匹配会很容易。

 

<bean id="exampleBean" class="examples.ExampleBean">

    <constructor-arg type="int" value="7500000"/>

    <constructor-arg type="java.lang.String" value="42"/>

</bean>

 

Use the index attribute to specify explicitly the index of constructor arguments. For example:

使用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. Note that the index is 0 based.

此外解决了多个简单类型的歧义,定义index当构造器的有两个相似类型的参数时。注意index是从0开始的。

 

You can also use the constructor parameter name for value disambiguation:

你也可以使用构造器参数的name来消除value的歧义。

 

<bean id="exampleBean" class="examples.ExampleBean">

    <constructor-arg name="years" value="7500000"/>

    <constructor-arg name="ultimateAnswer" value="42"/>

</bean>

 

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 cant compile your code with debug flag (or dont want to) you can use @ConstructorProperties JDK annotation to explicitly name your constructor arguments. The sample class would then have to look as follows:

注意,为了让这种方式可以起作用,你必须用debug标志来编译你的代码,以便spring可以根据参数名找到构造器。如果你不能使用debug的模式编译代码(或者你不想)你可以使用JDK提供的@ConstructorProperties注解来声明你的构造器参数的名字。下面有个简单的类可供参考:

 

package examples;

 

public class ExampleBean {

 

    // Fields omitted

 

    @ConstructorProperties({"years", "ultimateAnswer"})

    public ExampleBean(int years, String ultimateAnswer) {

        this.years = years;

        this.ultimateAnswer = ultimateAnswer;

    }

 

}

 

Setter-based dependency injection

基于setter方法的依赖注入

 

Setter-based DI is accomplished by the container calling setter methods on your beans after invoking a no-argument constructor or no-argument static factory method to instantiate your bean.

基于setter方法的依赖注入,是容器首先调用无参数的构造方法或无参数的静态工厂方法实例bean之后调用setter方法来最终完成bean的初始化。

 

The following example shows a class that can only be dependency-injected 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的。这是一个POJO并且没有依赖容器特定的接口、基准类或注解。

 

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 (i.e., programmatically) but rather with XML bean definitions, annotated components (i.e., classes annotated with @Component, @Controller, etc.), 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对于他管理的bean支持构造器注入和setter方法注入。基于setter的依赖注入也支持和构造器注入一同使用。你使用BeanDefinition的形式来配置依赖,配合PropertyEditor一同使用来转化属性从一种形式到另一种。然而,大部分spring的用户不会直接这样操作这些类(例如:编程的方式)而是使用xml定义bean、或使用注解修饰组件(例如:修饰类的@Component@Controller等等)、或使用甲鱼Java的注解类@Bean。这些资源会在内部转换为BeanDefinition的实体被springIOC容器全部加载。

 

Constructor-based or setter-based DI?

基于构造器还是基于setter方法更好?

 

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 @Required annotation on a setter method can be used to make the property a required dependency.

如果你混合使用了构造器注入和setter方法的注入,这是一个很不错的习惯,如果你将构造器注入作为主、setter方法或配置方法作为可选项依赖。在set方法上使用@Required注解会使得这个属性成为必要的依赖。

 

The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null. Furthermore constructor-injected components are always returned to 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的小组成员建议使用构造器注入,因为这样可以使得组件成为不可变object,并且可以确保依赖不为null。而且构造器注入返回给客户端代码的总是一个已经初始化好的状态。附注,如果构造器的参数过多也不是很好,这样一个class的压力会很大,建议将属性拆分重构。

 

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.

建议如果可以提供默认值的话可以考虑使用set方法的注入。另外,在使用依赖的时候必要的非空检查是需要的。一种使用set方法注入的好处就是可以在晚些的时候注入属性。JMXBean就是在编译时使用set方法注入的好例子。

 

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.

使用依赖注入的方式依赖于特殊的类。有时,有时,处理第三方的类时,如何处理由你来选择。例如,一个第三方类并未提供set方法,那么构造器注入就是唯一可用的依赖注入方法。

 

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 via XML, Java code, or annotations.

ApplicationContext根据配置元数据对所有的bean的描述进行初始化。配置元数据可以通过XMLJava代码或注解方式提供。

    For each bean, its dependencies are expressed in the form of properties, constructor arguments, or arguments to the static-factory method if you are using that instead of a normal constructor. These dependencies are provided to the bean, when the bean is actually created.

对于每一个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 which 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, etc.

每一个属性或构造器参数会从他指定的形式转换为其实际的类型。默认情况下,spring有能力将string类型的值转换为所有内置的类型,如intlongStringboolean等等。

 

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 Section 7.5, 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 beans dependencies and its dependencies' dependencies (and so on) are created and assigned. Note that resolution mismatches among those dependencies may show up late, i.e. on first creation of the affected bean.

spring容器被创建时,容器就会校验每一个bean的配置合法性。然而,有些bean的属性直到bean被创建才会被设置。单例模式下的bean默认情况下会在容器被创建时先被初始化。范围的定义见7.5章节“Bean的范围”。另外,bean只有被需要的时候才会被创建。一个bean的创建可能会导致他依赖的bean被创建。在依赖中不匹配的resolution将会在后面展示,例如受影响的bean第一次被创建。

 

Circular dependencies

循环依赖

 

If you use predominantly constructor injection, it is possible to create an unresolvable circular dependency scenario.

如果你使用构造器依赖,可能会出现无法处理的循环依赖的情况。

 

For example: Class A requires an instance of class B through constructor injection, and class B requires an instance of class A through constructor injection. If you configure beans for classes A and B to be injected into each other, the Spring IoC container detects this circular reference at runtime, and throws a BeanCurrentlyInCreationException.

例如,Class A依赖于Class B的实例通过构造器注入,并且Class B也需要Class A的实例,通过构造器注入。如果你这样配置A类和B类,spring IOC容器在运行时会发现循环注入,然后抛出BeanCurrentlyInCreationException

 

One possible solution is to edit the source code of some classes to be configured by setters rather than constructors. Alternatively, avoid constructor injection and use setter injection only. In other words, although it is not recommended, you can configure circular dependencies with setter injection.

一种可行的解决方案是在一些类的源代码中通过使用set方法来实现而不是使用构造器。或者避免构造器注入而只是使用set方法注入。换句话说,尽管不推荐,但是你可以使用set方法注入来处理循环依赖的问题。

 

Unlike the typical case (with no circular dependencies), a circular dependency between bean A and bean B forces one of the beans to be injected into the other prior to being fully initialized itself (a classic chicken/egg scenario).

不像典型的例子(没有循环依赖的情况),AB的循环依赖才能完全初始化就像(一个典型的鸡和鸡蛋的故事)。

 

You can generally trust Spring to do the right thing. It detects configuration problems, such as references to non-existent beans and circular dependencies, at container load-time. Spring sets properties and resolves dependencies as late as possible, when the bean is actually created. This means that a Spring container which has loaded correctly can later generate an exception when you request an object if there is a problem creating that object or one of its dependencies. For example, the bean throws an exception as a result of a missing or invalid property. This potentially delayed visibility of some configuration issues is why ApplicationContext implementations by default pre-instantiate singleton beans. At the cost of some upfront time and memory to create these beans before they are actually needed, you discover configuration issues when the ApplicationContext is created, not later. You can still override this default behavior so that singleton beans will lazy-initialize, rather than be pre-instantiated.

你可以相信spring用来做对的事。他可以检测配置问题,例如依赖一个不存在的bean或循环依赖在容器加载的时候。当bean被创建时,spring尽可能晚的设置属性和处理依赖。这就意味着一个已经成功加载的spring容器可以在创建bean时发现一个问题的情况下产生一个异常。例如,抛出一个丢失或非法属性的异常。一些配置问题的潜在的延迟可见就是为什么ApplicationContext由默认提前初始化的单例bean实现。在bean实际被需要之前,创建这些bean花费的时间和内存的时候,你会发现配置问题是在ApplicationContext创建的时候出现,而不是创建之后。你仍然可以覆盖默认的行为,使得单例的bean可以延迟初始化, 而不是提前初始化。

 

If no circular dependencies exist, when one or more collaborating beans are being injected into a dependent bean, each collaborating bean is totally configured prior to being injected into the dependent bean. This means that if bean A has a dependency on bean B, the Spring IoC container completely configures bean B prior to invoking the setter method on bean A. In other words, the bean is instantiated (if not a pre-instantiated singleton), its dependencies are set, and the relevant lifecycle methods (such as a configured init method or the InitializingBean callback method) are invoked.

如果没有循环注入的存在,当一个组合bean被注入一个依赖bean时,每一个组合bean被注入的时间都晚于依赖bean。这就意味着如果bean A依赖于bean BspringIOC容器将先配置bean B,然后在调用bean Aset方法。也就是说,bean被创建(如果不是提前初始化的单例bean),他的依赖被设置,然后生命周期方法被调用(如配置的init方法或InitializingBean的回调方法)

 

Examples of dependency injection

依赖注入的例子

 

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:

下面的例子使用了基于xml的配置元数据用于set方法的注入。下面是一部分springxml配置文件声明了一些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"/>

 

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;

    }

 

}

 

In the preceding example, setters are declared to match against the properties specified in the XML file. The following example uses constructor-based DI:

在前面的例子中,定义在xml文件中的属性和set方法相匹配。下面的例子使用了构造器的依赖注入:

 

<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"/>

 

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 will be used as arguments to the constructor of the ExampleBean.

bean定义中定义的构造器参数将会作为ExampleBean构造器的参数使用。

 

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:

现在考虑这样一个例子,不使用构造器,使用静态工厂方法来返回一个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"/>

 

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 via <constructor-arg/> 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 would be used in an essentially identical fashion (aside from the use of the factory-bean attribute instead of the class attribute), so details will not be discussed here.

静态工厂方法的参数由<constructor-arg/>元素提供,和使用构造器是差不多的。使用工厂方法返回的类型并不一样要和包含静态方法的类相同,上面的例子是个特例。实例工厂方法(非静态)的使用方法和这个例子差不多(区别只是在class属性中使用了factory-bean),因此我们不在这里在讨论他的细节。

 

7.4.2 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. Springs XML-based configuration metadata supports sub-element types within its <property/> and <constructor-arg/> elements for this purpose.

在前面的章节提到,你可定义bean的属性和构造器参数用于被其他的bean使用或者作为内联的值。spring基于xml的配置元数据支持子元素的形式,通过<property/><constructor-arg/>用于支持这一点。

 

Straight values (primitives, Strings, and so on)

直接值(基本类型,String等等)

 

The value attribute of the <property/> element specifies a property or constructor argument as a human-readable string representation. Springs conversion service is used to convert these values from a String to the actual type of the property or argument.

<property/>元素定义的内容或构造器参数定义的内容都是方便阅读的string形式。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="masterkaoli"/>

</bean>

 

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

    http://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="masterkaoli"/>

 

</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 Tool Suite (STS) that support automatic property completion when you create bean definitions. Such IDE assistance is highly recommended.

前面的例子更加简洁,打字错误会在运行时出现而不是编码的时候,除非你使用类似于IntelliJ IDEASTSIDE工具来支持创建bean定义的自动属性不全。这样的IDE是强烈推荐的。

 

You can also configure a java.util.Properties instance as:

你也可以这样定义一个java.util.Properties实例:

 

<bean id="mappings"

    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

 

    <!-- 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>

</bean>

 

The Spring container converts the text inside the <value/> 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 <value/> element over the value attribute style.

spring容器通过使用JavaBeans PropertyEditor策略将<value/>元素中的文本内容加载到java.util.Properties的实例中。这是一个捷径,spring的小组特别喜欢使用这种内置的value元素。

 

The idref element

IDREF元素

 

The idref element is simply an error-proof way to pass the id (string value - not a reference) of another bean in the container to a <constructor-arg/> or <property/> element.

idref元素提供了一个简单的错误检查的方式来传递id(字符串类型,不是一个引用)在容器的<constructor-arg/><property/>元素中。

 

<bean id="theTargetBean" class="..."/>

 

<bean id="theClientBean" class="...">

    <property name="targetName">

        <idref bean="theTargetBean" />

    </property>

</bean>

 

The above 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 allows the container to 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提供对值的校验机制。拼写错误只能在客户端bean被实际初始化时才被发现(可能会导致致命的问题)。如果客户端的bean是一个原型模式,这个拼写错误或许只能在容器已经被部署后才被发现。

 

[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 anymore. Simply change your existing idref local references to idref bean when upgrading to the 4.0 schema.

idref元素的local属性在4.0beans xsd中不在被支持。升级到4.0时请修改idref local的指向到idref bean

 

A common place (at least in versions earlier than Spring 2.0) where the <idref/> element brings value is in the configuration of AOP interceptors in a ProxyFactoryBean bean definition. Using <idref/> elements when you specify the interceptor names prevents you from misspelling an interceptor id.

(在spring2.0之前),idref元素的值对于在ProxyFactoryBeanAOP的拦截器的定义是有好处的。使用idref元素可以使得你在定义拦截器名的时候不会漏掉拦截器的id

 

References to other beans (collaborators)

对于其他bean的引用

 

The ref element is the final element inside a <constructor-arg/> or <property/> 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 will be set, and it is initialized on demand as needed before the property is set. (If the collaborator is a singleton bean, it may be initialized already by the container.) All references are ultimately a reference to another object. Scoping and validation depend on whether you specify the id/name of the other object through the bean, local, or parent attributes.

<constructor-arg/><property/>元素中,ref是一个final元素。这里你可以设置来引用容器中里一个被管理的bean。被引用的bean是一个beanset方法的依赖,并且会在被需要的类之前被初始化。(如果需要的是一个单例的bean,或许已经被容器初始化了)。所有的引用都指向一个object。范围和校验依赖于你设置的另一个objectidname,在beanlocal或父属性的定义中。

 

Specifying the target bean through the bean attribute of the <ref/> 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 as one of the values in the name attribute of the target bean.

使用ref来定义引用的bean是最常见的形式,可以引用同一个容器或父容器的任意一个bean,不管有没有在相同的xml文件中配置。beanvalue属性和目标beanid属性是一样的,或是目标beanname属性。

 

<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, and the target bean must be in a parent container of the current one. You 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 will have the same name as the parent bean.

通过parent属性定义目标bean,创建了一个对中心容器的父容器的一个bean的引用。parent属性的value属性和目标beanid属性是一样的,或是目标beanname属性,并且目标bean必须在当前容器的父容器中。你使用这个bean引用,主要是当你有一个层次结构的容器,并且你想包装现有的bean在一个父容器的代理中,将具有相同的名称作为父bean

 

<!-- in the parent context -->

<bean id="accountService" class="com.foo.SimpleAccountService">

    <!-- insert dependencies as required as 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>

 

[Note]

注意

 

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 anymore. Simply change your existing ref local references to ref bean when upgrading to the 4.0 schema.

idref元素的local属性在4.0beans xsd中不在被支持。升级到4.0时请修改idref local的指向到idref bean

 

Inner beans

内部bean

 

A <bean/> element inside the <property/> or <constructor-arg/> elements defines a so-called inner bean.

<property/><constructor-arg/>元素中的bean元素可以叫做内部bean

 

<bean id="outer" class="...">

    <!-- instead of using a reference to a target bean, simply define the target bean inline -->

<!-- 不在使用引用的方式来指向bean,可以简单在内部定义bean -->

    <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>

</bean>

 

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: Inner beans are always anonymous and they are always created with the outer bean. It is not possible to inject inner beans into collaborating beans other than into the enclosing bean or to access them independently.

一个内部bean的定义不需要idname,即使指定了,容器也不会使用它作为一个标识符。容器也会忽略scope的标志。内部bean总是匿名的而且和其他外部bean一起创建。内部bean不可能注入到一个组合的bean中,像其他的非内部的bean,而且也不能独立访问内部bean

 

As a corner case, it is possible to receive destruction callbacks from a custom scope, e.g. for a request-scoped inner bean contained within a singleton bean: The creation of the inner bean instance will be tied to its containing bean, but destruction callbacks allow it to participate in the request scopes lifecycle. This is not a common scenario; inner beans typically simply share their containing beans scope.

在极端的情况下,他可能会破话自定义范围的回调。例如,对于一个单例bean包含的request范围的bean,内部bean会作为容器bean的绑定来处理,但是破坏性回调允许他参与request范围的生命周期。这种情况并不常见,内部bean和他的容器bean共享同一个范围。

 

Collections

集合

 

In the <list/>, <set/>, <map/>, and <props/> elements, you set the properties and arguments of the Java Collection types List, Set, Map, and Properties, respectively.

<list/><set/><map/><props/>元素中,你可以设置java集合类型的属性和参数,例如ListSetMapProperties

 

<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 again be any of the following elements:

mapkeyvaluesetvalue可以使用以下的元素来标识:

 

bean | ref | idref | list | set | map | props | value | null

 

Collection merging

集合的合并

 

The Spring container also supports the merging of collections. An application developer can define a parent-style <list/>, <map/>, <set/> or <props/> element, and have child-style <list/>, <map/>, <set/> or <props/> elements inherit and override values from the parent collection. That is, the child collections values are the result of merging the elements of the parent and child collections, with the childs collection elements overriding values specified in the parent collection.

spring容器也支持集合的合并。应用开发者可以定义parent-stylelistmapsetprops元素,并且也可定义listmapsetprops元素从父集合中继承或覆盖。子集合的值是子集合和父集合的合并,其中子集合会覆盖父集合的内容。

 

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可以先阅读后续的7.7节。

 

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>

<beans>

 

Notice the use of the merge=true attribute on the <props/> 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 the merging of the childs adminEmails collection with the parents adminEmails collection.

注意在props属性中使用了merge=true属性对于adminEmails属性,在子bean定义中。当子bean被解析然后被容器初始化,adminEmails属性的结果是父beanadminEmails和子beanadminEmails的合并,如下:

 

administrator=administrator@example.com

sales=sales@example.com

support=support@example.co.uk

 

The child Properties collections value set inherits all property elements from the parent <props/>, and the childs value for the support value overrides the value in the parent collection.

子属性从父属性中继承了所有的属性内容,并且子beansupport的值覆盖了父bean中同名的值。

 

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 parents values precede all of the child lists 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.

合并这个属性对于listmapset集合类型是相似的。特别是在list元素中,根据list的语义,会维护list的顺序,父bean中内容在所有子bean内容之前。在mapsetproperties中没有顺序的概念。因此容器在合并mapsetproperties时不会考虑顺序的问题。

 

Limitations of collection merging

集合合并的限制

 

You cannot merge different collection types (such as a Map and a List), and 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 will not result in the desired merging.

你不可以合并不同类型的集合类型(如一个map和一个list合并),并且如何你试图这么做会抛出一个异常。合并的元素必须是低级、继承的子定义。如果将merge定义在父bean中是没有什么用的。

 

Strongly-typed collection

强类型的集合

 

With the introduction of generic types in Java 5, you can use strongly typed collections. That is, it is possible to declare a Collection type such that it can only contain String elements (for example). If you are using Spring to dependency-inject a strongly-typed Collection into a bean, you can take advantage of Springs 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.

java5中引入的泛型,你可以使用这种强类型的集合。这意味着你可以定义一个只包含字符串元素的集合类型(举个例子而已)。如果你使用spring来依赖注入一个强类型的集合到一个bean中,你可以使用spring的类型转换支持以至于你定义的强类型集合中的元素可以转化为你之前添加到集合中的内容。

 

public class Foo {

 

    private Map<String, Float> accounts;

 

    public void setAccounts(Map<String, Float> accounts) {

        this.accounts = accounts;

    }

}

 

<beans>

    <bean id="foo" class="x.y.Foo">

        <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>

</beans>

 

When the accounts property of the foo bean is prepared for injection, the generics information about the element type of the strongly-typed Map<String, Float> is available by reflection. Thus Springs 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.

foobeanaccounts属性准备注入时,元素强类型Map<String, Float>的泛型信息将会通过反射获得。spring的类型转换组件会意识到这是Float类型,然后字符串类型的9.992.753.99会转换成Float类型。

 

Null and empty string values

Null和空的字符串值

 

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. For example:

null元素用于处理null值,如下

 

<bean class="ExampleBean">

    <property name="email">

        <null/>

    </property>

</bean>

 

The above configuration is equivalent to the following Java code:

前面的例子和下面的java代码是一样的

 

exampleBean.setEmail(null)

 

XML shortcut with the p-namespace

使用p命名空间的xml简写

 

The p-namespace enables you to use the bean elements attributes, instead of nested <property/> elements, to describe your property values and/or collaborating beans.

p命名空间允许你使用bean的元素属性,而不是使用内置的property元素来描述组合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.

通过xmlschema定义,spring允许使用命名空间支持外部的定义。bean的配置形式讨论在xmlschema文档中。然而,p命名空间不再xsd文件中而在spring的核心中。

 

The following example shows two XML snippets that resolve to the same result: The first uses standard XML format and the second uses the p-namespace.

下面的例子是两个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

        http://www.springframework.org/schema/beans/spring-beans.xsd">

 

    <bean name="classic" class="com.example.ExampleBean">

        <property name="email" value="foo@bar.com"/>

    </bean>

 

    <bean name="p-namespace" class="com.example.ExampleBean"

        p:email="foo@bar.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命名空间没有schema的定义,因此你可以设置属性的名字对于属性名。

 

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

        http://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>

</beans>

 

As you can see, 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 <property name="spouse" ref="jane"/> 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的定义使用了<property name="spouse" ref="jane"/>来创建一个到john bean的指向,在到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文档中同时使用所有三个途径。

 

XML shortcut with the c-namespace

使用c命名空间的xml简写

 

Similar to the the section called XML shortcut with the p-namespace, the c-namespace, newly introduced in Spring 3.1, allows usage of inlined attributes for configuring the constructor arguments rather then nested constructor-arg elements.

和“使用p命名空间的xml简写”类似,c命名空间是spring3.1的新特性,允许使用你不的属性用于配置构造器参数而不是使用constructor-arg元素

 

Lets review the examples from the section calledConstructor-based dependency injectionwith the c: namespace:

现在回顾一下“基于构造器注入”的那个使用c命名空间的例子:

 

<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

        http://www.springframework.org/schema/beans/spring-beans.xsd">

 

    <bean id="bar" class="x.y.Bar"/>

    <bean id="baz" class="x.y.Baz"/>

 

    <!-- traditional declaration -->

    <bean id="foo" class="x.y.Foo">

        <constructor-arg ref="bar"/>

        <constructor-arg ref="baz"/>

        <constructor-arg value="foo@bar.com"/>

    </bean>

 

    <!-- c-namespace declaration -->

    <bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com"/>

 

</beans>

 

The c: namespace uses the same conventions as the p: one (trailing -ref for bean references) for setting the constructor arguments by their names. And just as well, it needs to be declared even though it is not defined in an XSD schema (but it exists inside the Spring core).

c命名空间使用相同的规范和p命名空间(后面使用ref作为bean的引用)来通过名字设置构造器的参数。并且他们不再xsdschema中,而在spring的核心代码中。

 

For the rare cases where the constructor argument names are not available (usually if the bytecode was compiled without debugging information), one can use fallback to the argument indexes:

极少数情况下,构造器的参数名不是可见的(二进制代码没有调试信息的编译),这样可以使用index来标识。

 

<!-- c-namespace index declaration -->

<bean id="foo" class="x.y.Foo" c:_0-ref="bar" c:_1-ref="baz"/>

 

[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 IDE allow it).

遵循xml的羽凡,index的表示前需要_作为xml的属性名而不能以数字开头(尽管某些ide支持这种写法)

 

In practice, the constructor resolution mechanism is quite efficient in matching arguments so unless one really needs to, we recommend using the name notation through-out your configuration.

在实际中,构造器注入是很有的匹配参数至少确实很需要他,我们推荐使用name符号在你的配置中。

 

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属性时可以使用组合或内嵌的属性名,并且保证每个组件的属性名都是非空的。考虑下面的bean定义

 

<bean id="foo" class="foo.Bar">

    <property name="fred.bob.sammy" value="123" />

</bean>

 

The foo bean has a fred property, which has a bob property, which has a sammy property, and that final sammy property is being set to the value 123. In order for this to work, the fred property of foo, and the bob property of fred must not be null after the bean is constructed, or a NullPointerException is thrown.

foo bean有一个fred属性,fred有一个bob属性,bob哟一个samy属性,并且最后的属性值是123。为了保证可以运行,必须保证每一项都不为null。否则将会抛出空指针异常。

 

7.4.3 Using depends-on

使用depends-on

 

If a bean is a dependency of another 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; for example, a static initializer in a class needs to be triggered, such as 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。通常你在基于xml的配置中使用ref来完成这件事。然而,有些时候bean之间的联系是less direct的。例如,一个类中静态初始化器需要被触发,例如数据库驱动注册。depends-on属性可以明确强制一个或多个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, with commas, whitespace and semicolons, used as valid delimiters:

如果依赖多个bean,可以提供一个list来设置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 in the bean definition can specify both an initialization time dependency and, in the case of singleton beans only, a corresponding destroy 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.

bean定义中的depends-on属性,可以指明依赖的初始化时间,在单例情况下会破坏销毁时的依赖时间。定义depends-onbean会先销毁。因此depends-on可以控制关闭的顺序。

 

7.4.4 Lazy-initialized beans

延迟初始化的bean

 

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 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会通知容器在第一次使用的时候创建实例而不是初始化的时候。

 

In XML, this behavior is controlled by the lazy-init attribute on the <bean/> element; for example:

xml中,该特性由bean元素中的lazy-init属性控制,如下:

 

<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/>

<bean name="not.lazy" class="com.foo.AnotherBean"/>

 

When the preceding configuration is consumed by an ApplicationContext, the bean named lazy is not eagerly pre-instantiated when the ApplicationContext is starting up, whereas the not.lazy bean is eagerly pre-instantiated.

当定义了前面这样的设置,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 singletons dependencies. The lazy-initialized bean is injected into a singleton bean elsewhere that is not lazy-initialized.

然而,当一个延迟初始化的bean是一个非延迟初始化的单例bean的依赖,ApplicationContext还是会在启动时对他进行初始化,因为必须保证单例bean的依赖关系。延迟加载的bean会注入到非延迟加载的单例bean中。

 

You can also control lazy-initialization at the container level by using the default-lazy-init attribute on the <beans/> element; for example:

你也可以通过beans中的default-lazy-init属性来控制容器中延迟初始化的等级。

 

<beans default-lazy-init="true">

<!-- no beans will be pre-instantiated... -->

<!-- 没有bean会被提前初始化-->

</beans>

 

7.4.5 Autowiring collaborators

自动装配的合作者

 

The Spring container can autowire relationships between collaborating beans. You can allow Spring to 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处理合作关系。自动装配有以下的优点:

 

    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模板在7.7中讨论也是有价值的)

    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.

自动装配可以和根据你的bean的发展来升级配置。例如,你需要为一个类增加依赖,你不需要修改配置就可以自动装配。自动装配在开发中很有用,不需要你来通过切换来否定选项使得你的代码更加稳定。

 

When using XML-based configuration metadata [2], you specify 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 thus can choose which ones to autowire.

当你使用基于xml的注解配置,你可以在bean元素中通过autowire属性来配置自动装配的模式。自动装配有四种模式。你可以为每个bean指定模式货值可以选择其中一种模式来装配。

 

Table 7.2. Autowiring modes

自动装配模式

Mode

模式

Explanation

说明

no

(Default) No autowiring. Bean references must be defined via a ref element. 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来进行注入。在大型开发中不建议使用默认选项,因为组合需要更加清晰可控。在某种情况,这取决于系统的架构。

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被声明为通过名字来自动装配,并且他包含一个master属性(当然也包含一个setMaster方法),spring将会查找一个叫masterbean然后用这个bean来设置属性。

byType

通过类型

Allows a property to 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则什么都不会发生,属性也没有被设置。

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.

和通过类型模式相似,区别是通过构造器参数来匹配。如果没有相应的匹配会抛出一个致命的错误。

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 Maps if the expected key type is String. An autowired Maps values will consist of all bean instances that match the expected type, and the Maps keys will contain the corresponding bean names.

通过类型或构造器的匹配模式,你可以装配数组或类型集合。在这种情况下,在容器中所有的自动匹配候选者只有匹配类型才能安全注入。你可以注入强类型的map并且期望他的key是字符串。一个自动注入的map将会包含所有bean的实例匹配类型,并且mapkey将会包含相关的bean的名称。

 

You can combine autowire behavior with dependency checking, which is performed after autowiring completes.

你可以在自动注入完成后合并自动注入和依赖检查功能。

 

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 so-called 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 above 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对你配置的bean管理不再那么明确。

    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 Maps, 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匹配set方法或构造器参数可以被自动装配。对于数组、集合或者map,这不在是一个问题。然而依赖明确的一个value,歧义并没有被简单的解决。如果没有唯一的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中定义primary属性为true来指定单个bean的定义。

    Implement the more fine-grained control available with annotation-based configuration, as described in Section 7.9,Annotation-based container configuration.

通过基于注解的配置实现更加细粒度的控制,在7.9章节“基于注解的容器配置”

 

Excluding a bean from autowiring

将一个bean从自动装配中排除

 

On a per-bean basis, you can exclude a bean from autowiring. In Springs XML format, set the autowire-candidate attribute of the <bean/> element to false; the container makes that specific bean definition unavailable to the autowiring infrastructure (including annotation style configurations such as @Autowired).

在每个bean中,你可以将他从自动装配中排除。在springxml形式中,在bean元素中指定autowire-candidate属性为false,容器会认为这是一个特殊的bean并不对他使用自动装配(包括注解形式的配置,例如@Autowired

 

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 definitions autowire-candidate attribute always takes precedence, and for such beans, the pattern matching rules do not apply.

你可以通过模式匹配bean的名字来限制自动装配的候选者。在顶级的beans元素中接受一个或多个模式在default-autowire-candidates属性中。例如,通过限制自动装配候选者的状态对每个beanRepository结尾的bean,提供一个值*Repository。如果需要指定多个值,则设定逗号分隔的list。对于明确指定autowire-candidate属性的值,模式匹配将不起作用。

 

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 using autowiring. Rather, the bean itself is not a candidate for autowiring other beans.

如果你不想通过自动装配注入某些bean时,这些功能将会很有用。这并不意味着被排除的bean不能通过自动装配来配置。这些bean在装配其他bean时不会作为候选者。

 

7.4.6 Method injection

方法注入

 

In most application scenarios, most beans in the container are singletons. When a singleton bean needs to collaborate with another singleton bean, or a non-singleton bean needs to collaborate with another non-singleton bean, you typically handle the dependency by defining one bean as a property of the other. A problem arises when the bean lifecycles are different. Suppose singleton bean A needs to use non-singleton (prototype) bean B, perhaps on each method invocation on A. The container only creates the singleton bean A once, and thus only gets one opportunity to set the properties. The container cannot provide bean A with a new instance of bean B every time one is needed.

在大部分应用的场景中,大部分容器中的bean都是单例的。当一个单例的bean需要和其他的单例bean组合或一个非单例bean需要和另一个非单例bean组合,你可以通过定义另一个bean的属性来处理依赖。但是由于生命周期的不同会产生问题。假设单例bean A需要使用非单例(原型)bean B,或许在每个在A中的方法里调用。容器只会创建一次A,并且只有一次设置属性的机会。容器不可能在每次需要时提供一个bean的实例。

 

A solution is to forego some inversion of control. You can make bean A aware of the container by implementing the ApplicationContextAware interface, and by making a getBean("B") call to the container ask for (a typically new) bean B instance every time bean A needs it. The following is an example of this approach:

一个解决方案时放弃使用反向控制。你可以是bean A通过实现ApplicationContextAware接口来被容器知晓,并且在每次需要的使用通过一个getBean("B")方法来向容器所要一个bean B的实例。下面的例子介绍了这种使用方法

 

// a class that uses a stateful Command-style class to perform some processing

// 一个使用了有状态的命令模式的类来体现一些过程

package fiona.apple;

 

// Spring-API imports

// spring api的导入

import org.springframework.beans.BeansException;

import org.springframework.context.ApplicationContext;

import org.springframework.context.ApplicationContextAware;

 

public class CommandManager implements ApplicationContextAware {

 

    private ApplicationContext applicationContext;

 

    public Object process(Map commandState) {

        // grab a new instance of the appropriate Command

// 抓取一个合适的Command实例

        Command command = createCommand();

        // set the state on the (hopefully brand new) Command instance

// 设置state为新的Command实例

        command.setState(commandState);

        return command.execute();

    }

 

    protected Command createCommand() {

        // notice the Spring API dependency!

// 通知spring api的依赖

        return this.applicationContext.getBean("command", Command.class);

    }

 

    public void setApplicationContext(

            ApplicationContext applicationContext) throws BeansException {

        this.applicationContext = applicationContext;

    }

}

 

The preceding is not desirable, because the business code is aware of and coupled to the Spring Framework. Method Injection, a somewhat advanced feature of the Spring IoC container, allows this use case to be handled in a clean fashion.

前面是例子是不被期望的,因为业务代码和spring框架相互融合了。方法注入,是spring IOC容器的高级特性,允许你使用来实现干净的逻辑。

 

You can read more about the motivation for Method Injection in this blog entry.

你可以在博客中了解更多有关方法注入的机制。

 

Lookup method injection

Lookup方法注入

 

Lookup method injection is the ability of the container to override methods on container managed beans, to return the lookup result for another named bean in the container. The lookup typically involves a prototype bean as in the scenario described in the preceding section. The Spring Framework implements this method injection by using bytecode generation from the CGLIB library to generate dynamically a subclass that overrides the method.

Lookup方法注入是容器的一种特性来覆盖容器管理bean的方法,对另一个在容器中命名的bean返回一个lookup结果。lookup通常用在原型的bean上面作为上面描述的场景中。spring框架实现这种方法注入通过使用二进制代码,二进制代码由cglib库生成,cglib库用于动态生成子类覆盖了这个方法。

 

[Note]

注意

 

    For this dynamic subclassing to work, the class that the Spring bean container will subclass cannot be final, and the method to be overridden cannot be final either.

为了这样的子类可以工作,springbean容器中包含的类不能是final的,并且方法也不可以是final的。

    Unit-testing a class that has an abstract method requires you to subclass the class yourself and to supply a stub implementation of the abstract method.

单元测试一个有抽象方法的类需要你提供一个子类并实现抽象的方法。

    Concrete methods are also necessary for component scanning which requires concrete classes to pick up.

组件扫描下的具体方法也需要具体的实现类。

    A further key limitation is that lookup methods wont work with factory methods and in particular not with @Bean methods in configuration classes, since the container is not in charge of creating the instance in that case and therefore cannot create a runtime-generated subclass on the fly.

一个更进一步的限制对于lookup方法不会正常工作在工厂方法上,特别是在配置class时没有使用@Bean的方法,因为容器在这种情况下不会创建实例也不能在创建运行时子类。

 

Looking at the CommandManager class in the previous code snippet, you see that the Spring container will dynamically override the implementation of the createCommand() method. Your CommandManager class will not have any Spring dependencies, as can be seen in the reworked example:

看前面代码片段中CommandManager的类,你看见spring容器动态的实现覆盖了createCommand方法。你的CommandManager类可以不需要任何spring的依赖,你可以看下面改进的例子:

 

package fiona.apple;

 

// no more Spring imports!

 

public abstract class CommandManager {

 

    public Object process(Object commandState) {

        // grab a new instance of the appropriate Command interface

        Command command = createCommand();

        // set the state on the (hopefully brand new) Command instance

        command.setState(commandState);

        return command.execute();

    }

 

    // okay... but where is the implementation of this method?

    protected abstract Command createCommand();

}

 

In the client class containing the method to be injected (the CommandManager in this case), the method to be injected requires a signature of the following form:

在客户端的class包含需要被注入的方法(在这个例子中是CommandManager),需要被注入的方法需要满足下面这样的形式

 

<public|protected> [abstract] <return-type> theMethodName(no-arguments);

 

If the method is abstract, the dynamically-generated subclass implements the method. Otherwise, the dynamically-generated subclass overrides the concrete method defined in the original class. For example:

如果方法是抽象的,可以动态生成子类来实现这个方法。另外,动态生成的子类覆盖了原有类中的创建方法。例如:

 

<!-- a stateful bean deployed as a prototype (non-singleton) -->

<bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype">

    <!-- inject dependencies here as required -->

</bean>

 

<!-- commandProcessor uses statefulCommandHelper -->

<bean id="commandManager" class="fiona.apple.CommandManager">

    <lookup-method name="createCommand" bean="myCommand"/>

</bean>

 

The bean identified as commandManager calls its own method createCommand() whenever it needs a new instance of the myCommand bean. You must be careful to deploy the myCommand bean as a prototype, if that is actually what is needed. If it is as a singleton, the same instance of the myCommand bean is returned each time.

commandManagerbean定义调用了自己的createCommand方法当他需要myCommandbean时。你必须将myCommandbean开发成原型模式,如果需要的话。如果是单例模式的话,那么每次返回的都将是同一个实例。

 

Alternatively, within the annotation-based component model, you may declare a lookup method through the @Lookup annotation:

另外,如果是基于注解的配置模式,你可以在lookup方法上定义@Lookup注解:

 

public abstract class CommandManager {

 

    public Object process(Object commandState) {

        Command command = createCommand();

        command.setState(commandState);

        return command.execute();

    }

 

    @Lookup("myCommand")

    protected abstract Command createCommand();

}

 

Or, more idiomatically, you may rely on the target bean getting resolved against the declared return type of the lookup method:

或者更常见的是,你也可以根据lookup方法的返回类型来查找匹配的bean

 

public abstract class CommandManager {

 

    public Object process(Object commandState) {

        MyCommand command = createCommand();

        command.setState(commandState);

        return command.execute();

    }

 

    @Lookup

    protected abstract MyCommand createCommand();

}

 

Note that you will typically declare such annotated lookup methods with a concrete stub implementation, in order for them to be compatible with Springs component scanning rules where abstract classes get ignored by default. This limitation does not apply in case of explicitly registered or explicitly imported bean classes.

注意你可以实现lookup方法通过创建一个子类实现,以配合spring的组件扫描默认会忽略抽象类。这种限制不适用于明确注册bean或明确导入bean

 

[Tip]

提示

 

Another way of accessing differently scoped target beans is an ObjectFactory/ Provider injection point. Check out the section calledScoped beans as dependencies.

另一种可以访问不同生命周期的方法是ObjectFactory/ Provider注入。见章节“有范围的bean的依赖”

 

The interested reader may also find the ServiceLocatorFactoryBean (in the org.springframework.beans.factory.config package) to be of use.

感兴趣的读者也可以查找ServiceLocatorFactoryBean(在org.springframework.beans.factory.config包中)的用法。

 

Arbitrary method replacement

任意的方法替换

 

A less useful form of method injection than lookup method injection is the ability to replace arbitrary methods in a managed bean with another method implementation. Users may safely skip the rest of this section until the functionality is actually needed.

一个比lookup方法注入更好形式的方法注入就是可以通过另一个方法实现来替换一个被管理bean的任意方法。

 

With XML-based configuration metadata, you can use the replaced-method element to replace an existing method implementation with another, for a deployed bean. Consider the following class, with a method computeValue, which we want to override:

基于xml的配置元数据,你可以使用replaced-method元素来使得另一个方法来替换一个已经部署的bean的已有方法实现。考虑下面的这个类,有一个我们希望覆盖的computeValue方法:

 

public class MyValueCalculator {

 

    public String computeValue(String input) {

        // some real code...

    }

 

    // some other methods...

 

}

 

A class implementing the org.springframework.beans.factory.support.MethodReplacer interface provides the new method definition.

一个类只要实现org.springframework.beans.factory.support.MethodReplacer接口就可以提供新的方法实现。

 

/**

 * meant to be used to override the existing computeValue(String)

 * implementation in MyValueCalculator

 */

public class ReplacementComputeValue implements MethodReplacer {

 

    public Object reimplement(Object o, Method m, Object[] args) throws Throwable {

        // get the input value, work with it, and return a computed result

        String input = (String) args[0];

        ...

        return ...;

    }

}

 

The bean definition to deploy the original class and specify the method override would look like this:

原有类的bean定义和替换方法的定义是这样的:

 

<bean id="myValueCalculator" class="x.y.z.MyValueCalculator">

    <!-- arbitrary method replacement -->

    <replaced-method name="computeValue" replacer="replacementComputeValue">

        <arg-type>String</arg-type>

    </replaced-method>

</bean>

 

<bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>

 

You can use one or more contained <arg-type/> elements within the <replaced-method/> element to indicate the method signature of the method being overridden. The signature for the arguments is necessary only if the method is overloaded and multiple variants exist within the class. For convenience, the type string for an argument may be a substring of the fully qualified type name. For example, the following all match java.lang.String:

你可以在<replaced-method/>元素中使用一个或多个<arg-type/>元素来声明需要被覆盖的方法签名。在覆盖的方法有重载或多个参数时是必须的。为了方便,字符串类型可以使用全限定名的简写。例如下面的写法都是字符串类型:

 

java.lang.String

String

Str

 

Because the number of arguments is often enough to distinguish between each possible choice, this shortcut can save a lot of typing, by allowing you to type only the shortest string that will match an argument type.

因为参数的个数通常足够可以区分不同的方法,所以这样的简写可以减少输入,并且允许你输入简写就可以匹配参数。

0 0