spring官网在线学习文档翻译
Core Technologies (核心技术)
Version 5.0.8.RELEASE
- 版本5.0.8RELEASE
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 Framework’s Inversion of Control (IoC) container. A thorough treatment of the Spring Framework’s IoC container is closely followed by comprehensive coverage of Spring’s Aspect-Oriented Programming (AOP) technologies. The Spring Framework has its own AOP framework, which is conceptually easy to understand, and which successfully addresses the 80% sweet spot of AOP requirements in Java enterprise programming.
- 其中最重要的是Spring框架的控制反转(IoC)容器。在全面介绍了Spring框架的IoC容器之后,紧接着是对Spring的面向切面编程(AOP)技术的全面介绍。Spring框架有自己的AOP框架,它在概念上很容易理解,并且成功地解决了Java企业编程中80%的AOP需求的最佳点。
Coverage of Spring’s integration with AspectJ (currently the richest - in terms of features - and certainly most mature AOP implementation in the Java enterprise space) is also provided.
- 还介绍了Spring与AspectJ的集成(就特性而言,这是目前最丰富的,也是Java企业领域中最成熟的AOP实现)
- AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。
1. The IoC container (IoC容器)
1.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) [1] 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.
- 本章涵盖了控制反转(IoC)原理的Spring框架实现。IoC中包含依赖注入(DI)。这是一个过程,对象通过构造函数参数、工厂方法的参数或在对象实例被构造或从工厂方法返回后在对象实例上设置的属性来定义它们的依赖项,也就是它们使用的其他对象。然后,容器在创建bean时注入这些依赖项。这个过程基本上是bean的逆过程,因此称为控制反转(IoC)
The
org.springframework.beans
andorg.springframework.context
packages are the basis for Spring Framework’s IoC container. TheBeanFactory
interface provides an advanced configuration mechanism capable of managing any type of object.ApplicationContext
is a sub-interface ofBeanFactory
. It adds easier integration with Spring’s AOP features; message resource handling (for use in internationalization), event publication; and application-layer specific contexts such as theWebApplicationContext
for use in web applications.- org.springframework.beans和org.springframework.context包是Spring框架的IoC容器的基础。BeanFactory(Bean工厂)接口提供了一种高级配置机制,能够管理任何类型的对象。ApplicationContext是BeanFactory的子接口。它更容易与Spring的AOP特性集成;消息资源处理(用于国际化)、事件发布;和应用程序层特定的上下文,如web应用程序中使用的WebApplicationContext
In short, the
BeanFactory
provides the configuration framework and basic functionality, and theApplicationContext
adds more enterprise-specific functionality. TheApplicationContext
is a complete superset of theBeanFactory
, and is used exclusively in this chapter in descriptions of Spring’s IoC container. For more information on using theBeanFactory
instead of theApplicationContext,
refer to The BeanFactory.- 简而言之,BeanFactory提供了配置框架和基本功能,而ApplicationContext添加了更多特定于企业的功能。ApplicationContext是BeanFactory的一个完整超集,在本章描述Spring的IoC容器时只使用它。有关使用BeanFactory而不是ApplicationContext的更多信息,请参考>The BeanFactory
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中,构成应用程序主干并且由Spring IoC容器管理的对象称为beans.一个bean是由Spring IoC容器实例化、组装和管理的对象。否则,bean只是应用程序中许多对象中的一个。bean及其之间的依赖关系反映在容器使用的配置元数据中。
1.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表示Spring IoC容器,并负责实例化、配置和组装前面提到的bean。容器通过读取配置元数据获得关于要实例化、配置和组装哪些对象的指令。配置元数据用XML、Java注释或Java代码表示。它允许您表达组成应用程序的对象以及这些对象之间丰富的相互依赖关系。
Several implementations of the
ApplicationContext
interface are supplied out-of-the-box with Spring. In standalone applications it is common to create an instance ofClassPathXmlApplicationContext
orFileSystemXmlApplicationContext
. While XML has been the traditional format for defining configuration metadata you can instruct the container to use Java annotations or code as the metadata format by providing a small amount of XML configuration to declaratively enable support for these additional metadata formats.Spring提供了ApplicationContext接口的几个现成实现。在独立应用程序中,通常创建ClassPathXmlApplicationContext或FileSystemXmlApplicationContext的实例。虽然XML是定义配置元数据的传统格式,但您可以通过提供少量XML配置以声明方式启用对这些附加元数据格式的支持,来指示容器使用Java注释或代码作为元数据格式。
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 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.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 IoC容器的一个或多个实例。例如,在web应用程序场景中,应用程序的web. XML文件中简单的8行(大约)样板web描述符XML通常就足够了(请参阅web应用程序的方便ApplicationContext实例化)。如果您使用的是Spring Tool Suite eclipse驱动的开发环境,那么只需单击几下鼠标或击键,就可以轻松地创建这个样板配置。
下面的图表是Spring如何运行的高级视图
1.2.1. Configuration metadata (配置元数据)
As the preceding diagram shows, the Spring IoC container consumes a form of configuration metadata; this configuration metadata represents how you as an application developer tell the Spring container to instantiate, configure, and assemble the objects in your application.
- 正如前面的图表所示,Spring IoC容器消耗一种配置元数据;此配置元数据表示您作为应用程序开发人员如何告诉Spring容器在应用程序中实例化、配置和组装对象。
Configuration metadata is traditionally supplied in a simple and intuitive XML format, which is what most of this chapter uses to convey key concepts and features of the Spring IoC container.
- 配置元数据传统上是以简单直观的XML格式提供的,本章的大部分内容都使用它来传达Spring IoC容器的关键概念和特性。
XML-based metadata is not the only allowed form of configuration metadata. The Spring IoC container itself is totally decoupled from the format in which this configuration metadata is actually written. These days many developers choose Java-based configuration for their Spring applications.
- 基于xml的元数据并不是唯一允许的配置元数据形式。Spring IoC容器本身与实际编写配置元数据的格式完全解耦。现在,许多开发人员为他们的Spring应用程序选择基于java的配置。
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.
- 基于注释的配置:Spring 2.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的配置](https://docs.springing.io/spring/docs/5.0.8.release/springing-frameworkreference/core.html #beans-java):从Spring 3.0开始,Spring JavaConfig项目提供的许多特性成为了核心Spring框架的一部分。因此,您可以使用Java而不是XML文件来定义应用程序类的外部bean。要使用这些新特性,请参阅' @Configuration '、' @Bean '、' @Import '和' @DependsOn '注释。
Spring configuration consists of at least one and typically more than one bean definition that the container must manage. XML-based configuration metadata 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被配置为顶级元素中的元素。Java配置通常在@Configuration类中使用@Bean注释的方法。
这些bean定义对应于组成应用程序的实际对象。通常需要定义服务层对象、数据访问对象(dao)、表示对象(如Struts Action实例)、基础设施对象(如Hibernate SessionFactories)、JMS队列等等。通常不需要在容器中配置细粒度的域对象,因为创建和加载域对象通常是dao和业务逻辑的职责。但是,您可以使用Spring与AspectJ的集成来配置在IoC容器控制之外创建的对象。参见用Spring使用AspectJ来依赖注入域对象。
- 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. Theclass
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的类型,并使用完全限定的类名。id属性的值引用协作对象。在这个例子中没有显示用于引用协作对象的XML;有关更多信息,请参见依赖项。
1.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 JavaCLASSPATH
, and so on.- 实例化Spring IoC容器非常简单。提供给ApplicationContext构造函数的位置路径实际上是资源字符串,允许容器从各种外部资源(如本地文件系统、Java类路径等)加载配置元数据。
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
After you learn about Spring’s IoC container, you may want to know more about Spring’s
Resource
abstraction, as described in Resources, which provides a convenient mechanism for reading an InputStream from locations defined in a URI syntax. In particular,Resource
paths are used to construct applications contexts as described in Application contexts and Resource paths.- 在了解了Spring的IoC容器之后,您可能想了解更多关于Spring的资源抽象的信息,如参考资料中所述,它提供了一种方便的机制,可以从URI语法中定义的位置读取InputStream。特别地,资源路径用于构建应用程序上下文(如应用程序上下文和资源路径中所述)。
The following example shows the service layer objects
(services.xml)
configuration file:- 下面的例子显示了服务层对象(services.xml)配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
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:- 下面的例子显示了数据访问对象dao .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 typeJpaAccountDao
andJpaItemDao
(based on the JPA Object/Relational mapping standard). Theproperty name
element refers to the name of the JavaBean property, and theref
element refers to the name of another bean definition. This linkage betweenid
andref
elements expresses the dependency between collaborating objects. For details of configuring an object’s dependencies, see Dependencies.- 在前面的示例中,服务层由类PetStoreServiceImpl和类型为JpaAccountDao和JpaItemDao的两个数据访问对象(基于JPA对象/关系映射标准)组成。property name元素引用JavaBean属性的名称,ref元素引用另一个bean定义的名称。id和ref元素之间的链接表示了协作对象之间的依赖关系。有关配置对象依赖项的详细信息,请参见依赖项。
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.
- 让bean定义跨越多个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定义。此构造函数接受多个资源位置,如前一节所示。或者,使用元素的一次或多次出现来从另一个或多个文件加载bean定义。例如:
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>
In the preceding example, external bean definitions are loaded from three files:
services.xml
,messageSource.xml
, andthemeSource.xml
. All location paths are relative to the definition file doing the importing, soservices.xml
must be in the same directory or classpath location as the file doing the importing, whilemessageSource.xml
andthemeSource.xml
must be in aresources
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定义是从三个文件加载的:服务。xml, messageSource。xml和themeSource.xml。所有位置路径都相对于执行导入的定义文件,因此services.xml必须与执行导入的文件位于相同的目录或类路径位置,而messageSource.xml和themeSource.xml必须位于导入文件位置下方的资源位置。正如您所看到的,前面的斜杠被忽略了,但是考虑到这些路径是相对的,最好完全不使用斜杠。正在导入的文件内容
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”)引用此引用,其中运行时解析过程选择“最近的”类路径根,然后查看其父目录。类路径配置更改可能导致选择不同的、不正确的目录。
You can always use fully qualified resource locations instead of relative paths: for example, "file:C:/config/services.xml" or "classpath:/config/services.xml". However, be aware that you are coupling your application’s configuration to specific absolute locations. It is generally preferable to keep an indirection for such absolute locations, for example, through "${…}" placeholders that are resolved against JVM system properties at runtime.
- 您可以始终使用完全限定的资源位置,而不是相对路径:例如,“file:C:/config/services”。xml”或“类路径:/配置/ services . xml”。但是,请注意,您正在将应用程序的配置耦合到特定的绝对位置。通常最好为这样的绝对位置保留一个间接性,例如,通过在运行时根据JVM系统属性解析的“${…}”占位符。
The import directive is a feature provided by the beans namespace itself. Further configuration features beyond plain bean definitions are available in a selection of XML namespaces provided by Spring, e.g. the "context" and the "util" namespace.
- 导入指令是bean名称空间本身提供的特性。除了普通bean定义之外,Spring提供的XML名称空间还提供了更多的配置特性,例如“context”和“util”名称空间。
The Groovy Bean Definition DSL (Groovy Bean定义DSL)
- As a further example for externalized configuration metadata, bean definitions can also be expressed in Spring’s Groovy Bean Definition DSL, as known from the Grails framework. Typically, such configuration will live in a ".groovy" file with a structure as follows:
- 作为外部化配置元数据的进一步示例,bean定义也可以在Spring的Groovy bean定义DSL中表示,正如Grails框架中所知道的那样。通常,这样的配置将存在于“。文件的结构如下:
beans {
dataSource(BasicDataSource) {
driverClassName = "org.hsqldb.jdbcDriver"
url = "jdbc:hsqldb:mem:grailsDB"
username = "sa"
password = ""
settings = [mynew:"setting"]
}
sessionFactory(SessionFactory) {
dataSource = dataSource
}
myService(MyService) {
nestedBean = { AnotherBean bean ->
dataSource = dataSource
}
}
}
- This configuration style is largely equivalent to XML bean definitions and even supports Spring’s XML configuration namespaces. It also allows for importing XML bean definition files through an "importBeans" directive.
- 这种配置风格在很大程度上等同于XML bean定义,甚至支持Spring的XML配置名称空间。它还允许通过“importBeans”指令导入XML bean定义文件。
1.2.3. Using the container (使用容器[spring])
The
ApplicationContext
is the interface for an advanced factory capable of maintaining a registry of different beans and their dependencies. Using the methodT getBean(String name, Class<T> requiredType)
you can retrieve instances of your bean- ApplicationContext是一个高级工厂的接口,该工厂能够维护不同bean及其依赖项的注册表。使用方法T getBean(字符串名,类 requiredType),您可以检索bean的实例
The
ApplicationContext
enables you to read bean definitions and access them as follows:- ApplicationContext允许您读取bean定义并访问它们,如下所示:
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// use configured instance
List<String> userList = service.getUsernameList();
- With Groovy configuration, bootstrapping looks very similar, just a different context implementation class which is Groovy-aware (but also understands XML bean definitions):
- 使用Groovy配置,bootstrapping看起来非常相似,只是一个不同的上下文实现类,它支持Groovy(但也理解XML bean定义):
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
- The most flexible variant is
GenericApplicationContext
in combination with reader delegates, e.g. withXmlBeanDefinitionReader
for XML files:- 最灵活的变体是GenericApplicationContext与reader委托的结合,例如XmlBeanDefinitionReader用于XML文件:
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
- Or with
GroovyBeanDefinitionReader
for Groovy files:- 或者对Groovy文件使用GroovyBeanDefinitionReader:
GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
context.refresh();
Such reader delegates can be mixed and matched on the same
ApplicationContext
, reading bean definitions from diverse configuration sources, if desired.- 这样的阅读器委托可以在相同的ApplicationContext上混合和匹配,如果需要,可以从不同的配置源读取bean定义
You can then use
getBean
to retrieve instances of your beans. TheApplicationContext
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 thegetBean()
method at all, and thus no dependency on Spring APIs at all. For example, Spring’s integration with web frameworks provides dependency injection for various web framework components such as controllers and JSF-managed beans, allowing you to declare a dependency on a specific bean through metadata (e.g. an autowiring annotation).- 然后可以使用getBean检索bean的实例。ApplicationContext接口有一些其他检索bean的方法,但理想情况下,应用程序代码不应该使用它们。实际上,您的应用程序代码根本不应该调用getBean()方法,因此根本不依赖于Spring api。例如,Spring与web框架的集成为各种web框架组件(如控制器和jsf管理的bean)提供依赖注入,允许您通过元数据(例如自动装配注释)声明对特定bean的依赖。
1.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.- Spring IoC容器管理一个或多个bean。这些bean是使用您提供给容器的配置元数据创建的,例如,以XML 定义的形式
Within the container itself, these bean definitions are represented as
BeanDefinition
objects, which contain (among other information) the following metadata:- 在容器本身内,这些bean定义被表示为BeanDefinition对象,其中包含(以及其他信息)以下元数据:
- A package-qualified class name: typically the actual implementation class of the bean being defined.
- 一个包限定的类名:通常是被定义的bean的实际实现类。
- 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.
- 在新创建的对象中要设置的其他配置设置,例如,在管理连接池的bean中要使用的连接数,或者池的大小限制。
- A package-qualified class name: typically the actual implementation class of the bean being defined.
- 在容器本身内,这些bean定义被表示为BeanDefinition对象,其中包含(以及其他信息)以下元数据:
This metadata translates to a set of properties that make up each bean definition.
- 该元数据转换为组成每个bean定义的一组属性。
Table 1. The bean definition
- bean定义
Property(属性) | Explained in…(解释...) |
---|---|
class(类) | Instantiating beans (实例化bean) |
name(名字) | Naming beans (命名bean) |
scope(范围) | Bean scopes (bean范围) |
constructor arguments(构造函数参数) | Dependency Injection (依赖注入) |
properties(属性) | Dependency Injection |
autowiring mode(自动装配模式) | Autowiring collaborators (自动装配的合作者) |
lazy-initialization mode(延迟初始化模式) | Lazy-initialized beans (延迟初始化的bean) |
initialization method(初始化方法) | Initialization callbacks (初始化方法的回调) |
destruction method(破坏的方法) | Destruction callbacks (破坏方法的回调) |
In addition to bean definitions that contain information on how to create a specific bean, the
ApplicationContext
implementations also permit the registration of existing objects that are created outside the container, by users. This is done by accessing the ApplicationContext’s BeanFactory via the methodgetBeanFactory()
which returns the BeanFactory implementationDefaultListableBeanFactory
.DefaultListableBeanFactory
supports this registration through the methodsregisterSingleton(..)
andregisterBeanDefinition(..)
. However, typical applications work solely with beans defined through metadata bean definitions.- 除了包含关于如何创建特定bean的信息的bean定义之外,ApplicationContext实现还允许注册由用户在容器外部创建的现有对象。这是通过getBeanFactory()方法访问ApplicationContext的BeanFactory来完成的,该方法返回BeanFactory实现DefaultListableBeanFactory。DefaultListableBeanFactory通过registerSingleton(..)和registerBeanDefinition(..)方法支持这种注册。但是,典型的应用程序只使用通过metada定义的bean
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容器中的并发访问异常和/或不一致状态。
1.3.1. Naming beans (命名bean)
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/orname
attributes to specify the bean identifier(s). Theid
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 thename
attribute, separated by a comma (,
), semicolon (;
), or white space. As a historical note, in versions prior to Spring 3.1, theid
attribute was defined as anxsd:ID
type, which constrained possible characters. As of 3.1, it is defined as anxsd:string
type. Note that beanid
uniqueness is still enforced by the container, though no longer by XML parsers.- 在基于xml的配置元数据中,您使用id和/或name属性来指定bean标识符。id属性允许您精确地指定一个id。通常这些名称是字母数字('myBean', 'fooService'等),但也可能包含特殊字符。如果希望为bean引入其他别名,还可以在name属性中指定它们,用逗号(,)、分号(;)或空格分隔。作为一个历史记录,在Spring 3.1之前的版本中,id属性被定义为xsd: id类型,它限制了可能的字符。在3.1版本中,it i
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提供名称或id。如果没有显式地提供名称或id,容器将为该bean生成惟一的名称。但是,如果您希望通过使用ref元素或服务定位器样式查找通过名称引用那个bean,那么您必须提供一个名称。不提供名称的动机与使用内部bean和自动装配协作者有关。
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.- 约定是在命名bean时对实例字段名使用标准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可以使您的配置更容易阅读和理解,如果您正在使用Spring AOP,那么在将通知应用到一组名称相关的bean时,它会有很大帮助。
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).- 通过在类路径中扫描组件,Spring为未命名的组件生成bean名称,遵循上面的规则:本质上,采用简单的类名并将其初始字符转换为小写。但是,在有多个字符并且第一个和第二个字符都是大写的(不寻常的)特殊情况下,原始的外壳将被保留。这些规则与java.bean .内省器.decapitalize(此处Spring使用的)定义的规则相同
Aliasing a bean outside the bean definition (在bean定义之外混叠一个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 thename
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定义本身中,您可以为bean提供多个名称,方法是使用由id属性指定的最多一个名称和name属性中任意数量的其他名称的组合。这些名称可以是相同bean的等价别名,并且在某些情况下非常有用,例如允许应用程序中的每个组件通过使用特定于该组件本身的bean名称来引用公共依赖项。
Specifying all aliases where the bean is actually defined is not always adequate, however. It is sometimes desirable to introduce an alias for a bean that is defined elsewhere. This is commonly the case in large systems where configuration is split amongst each subsystem, each subsystem having its own set of object definitions. In XML-based configuration metadata, you can use the
<alias/>
element to accomplish this.- 然而,指定实际定义bean的所有别名并不总是足够的。有时需要为在别处定义的bean引入别名。在大型系统中,配置在每个子系统之间分割,每个子系统都有自己的一组对象定义,这种情况很常见。在基于xml的配置元数据中,可以使用元素来完成此任务。
<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 astoName
.- 在这种情况下,在使用别名定义之后,同一个容器中名为fromName的bean也可以被称为toName。
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 namesubsystemB-dataSource
. When composing the main application that uses both these subsystems the main application refers to the DataSource via the namemyApp-dataSource
. To have all three names refer to the same object you add to the MyApp configuration metadata the following aliases definitions:- 例如,子系统A的配置元数据可以通过名称subsystem - DataSource引用数据源。子系统B的配置元数据可以通过名称subsystembl - DataSource引用数据源。在编写同时使用这两个子系统的主应用程序时,主应用程序通过名称myApp-dataSource引用数据源。为了让这三个名字都指向你添加到MyApp配置元数据中的同一个对象,下面的别名定义如下:
<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.
- 现在,每个组件和主应用程序都可以通过一个惟一的并且保证不会与任何其他定义冲突的名称(有效地创建了一个名称空间)引用数据源,但是它们引用的是同一个bean。
Java-configuration
- java配置
If you are using Java-configuration, the
@Bean
annotation can be used to provide aliases see Using the @Bean annotation for details.- 如果您正在使用Java-configuration,则可以使用@Bean注释来提供别名,详见使用@Bean注释获得的详细信息。
1.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定义本质上是创建一个或多个对象的配方。当请求时,容器查看已命名bean的配方,并使用该bean定义封装的配置元数据来创建(或获取)实际对象。
If you use XML-based configuration metadata, you specify the type (or class) of object that is to be instantiated in the
class
attribute of the<bean/>
element. Thisclass
attribute, which internally is aClass
property on aBeanDefinition
instance, is usually mandatory. (For exceptions, see Instantiation using an instance factory method and Bean definition inheritance.) You use theClass
property in one of two ways:- 如果使用基于xml的配置元数据,则指定要在元素的class属性中实例化的对象的类型(或类)。这个类属性在内部是BeanDefinition实例上的类属性,通常是必需的。(有关异常,请参阅使用实例工厂方法和Bean定义继承进行实例化。)使用Class属性有两种方式:
- Typically, to specify the bean class to be constructed in the case where the container itself directly creates the bean by calling its constructor reflectively, somewhat equivalent to Java code using the
new
operator.- 通常,在容器本身通过反射调用其构造函数直接创建bean的情况下,指定要构造的bean类,这在某种程度上等同于使用new操作符的Java代码。
- 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 astatic
factory method on a class to create the bean. The object type returned from the invocation of thestatic
factory method may be the same class or another class entirely.- 为了指定包含将被调用来创建对象的静态工厂方法的实际类,在容器调用类上的静态工厂方法来创建bean的不太常见的情况下。从静态工厂方法调用返回的对象类型可以是相同的类,也可以完全是另一个类。
- 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
- 如果使用基于xml的配置元数据,则指定要在元素的class属性中实例化的对象的类型(或类)。这个类属性在内部是BeanDefinition实例上的类属性,通常是必需的。(有关异常,请参阅使用实例工厂方法和Bean定义继承进行实例化。)使用Class属性有两种方式:
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.
如果希望为静态嵌套类配置bean定义,则必须使用嵌套类的二进制名称。
For example, if you have a class called
Foo
in thecom.example
package, and thisFoo
class has astatic
nested class calledBar
, the value of the'class'
attribute on a bean definition would be…com.example.Foo$Bar
例如,如果你在com中有一个叫做Foo的类。这个Foo类有一个静态嵌套的类,叫做Bar, bean定义上的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.
- 请注意名称中使用了$字符来分隔嵌套的类名和外部类名。
Instantiation with a constructor (用构造函数实例化)
When you create a bean by the constructor approach, all normal classes are usable by and compatible with Spring. That is, the class being developed does not need to implement any specific interfaces or to be coded in a specific fashion. Simply specifying the bean class should suffice. However, depending on what type of IoC you use for that specific bean, you may need a default (empty) constructor.
- 当您通过构造函数方法创建bean时,所有的普通类都可以通过Spring使用并与之兼容。也就是说,被开发的类不需要实现任何特定的接口,也不需要以特定的方式进行编码。简单地指定bean类就足够了。但是,根据您为特定bean使用的IoC类型,您可能需要一个默认的(空的)构造函数。
The Spring IoC container can manage virtually any class you want it to manage; it is not limited to managing true JavaBeans. Most Spring users prefer actual JavaBeans with only a default (no-argument) constructor and appropriate setters and getters modeled after the properties in the container. You can also have more exotic non-bean-style classes in your container. If, for example, you need to use a legacy connection pool that absolutely does not adhere to the JavaBean specification, Spring can manage it as well.
- Spring IoC容器实际上可以管理任何您希望它管理的类;它并不局限于管理真正的javabean。大多数Spring用户更喜欢实际的javabean,它只有一个默认的(无参数的)构造函数和适当的setter和getter方法,这些方法是根据容器中的属性建模的。您还可以在容器中使用更多奇异的非bean样式的类。例如,如果您需要使用绝对不符合JavaBean规范的遗留连接池,Spring也可以管理它。
With XML-based configuration metadata you can specify your bean class as follows:
- 使用基于xml的配置元数据,您可以指定您的bean类如下:
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>
- For details about the mechanism for supplying arguments to the constructor (if required) and setting object instance properties after the object is constructed, see Injecting Dependencies.
- 有关向构造函数提供参数(如果需要)和在构造对象后设置对象实例属性的机制的详细信息,请参见注入依赖项。
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 thestatic
factory method and an attribute namedfactory-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 callstatic
factories in legacy code.- 在定义使用静态工厂方法创建的bean时,您使用class属性来指定包含静态工厂方法的类,使用名为factory-method的属性来指定工厂方法本身的名称。您应该能够调用这个方法(后面将介绍可选参数)并返回一个活动对象,然后将其视为通过构造函数创建的。这种bean定义的一个用途是在遗留代码中调用静态工厂。
The following bean definition specifies that the bean will be created by calling a factory-method. The definition does not specify the type (class) of the returned object, only the class containing the factory method. In this example, the
createInstance()
method must be a static method.- 下面的bean定义指定该bean将通过调用工厂方法来创建。该定义没有指定返回对象的类型(类),只指定包含工厂方法的类。在本例中,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.
- 有关向工厂方法提供(可选)参数和在对象从工厂返回后设置对象实例属性的机制的详细信息,请参见依赖项和配置。
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 thefactory-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 thefactory-method
attribute.- 与通过静态工厂方法进行实例化类似,实例工厂方法的实例化从容器中调用现有bean的非静态方法来创建新bean。要使用这种机制,请将class属性保留为空,并在factory-bean属性中指定当前(或父/祖先)容器中bean的名称,该容器包含要调用来创建对象的实例方法。使用factory-method属性设置工厂方法本身的名称。
<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- the bean to be created via the factory bean -->
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}
- One factory class can also hold more than one factory method as 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();
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.
- 这种方法表明可以通过依赖项注入(DI)来管理和配置工厂bean本身。请详细查看依赖关系和配置。
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-specificFactoryBean
.- 在Spring文档中,工厂bean指的是在Spring容器中配置的bean,该bean将通过实例或静态工厂方法创建对象。相比之下,FactoryBean(注意大小写)指的是特定于spring的FactoryBean。
1.4. Dependencies (依赖)
- A typical enterprise application does not consist of a single object (or bean in the Spring parlance). Even the simplest application has a few objects that work together to present what the end-user sees as a coherent application. This next section explains how you go from defining a number of bean definitions that stand alone to a fully realized application where objects collaborate to achieve a goal.
- 典型的企业应用程序不包含单个对象(或者用Spring的说法就是bean)。即使是最简单的应用程序也有一些共同工作的对象来呈现最终用户所看到的一致的应用程序。下一节将解释如何从定义大量独立的bean定义到一个完全实现的应用程序,其中对象可以协作来实现目标。
1.4.1. 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.
- 依赖注入(Dependency injection, DI)是一个过程,对象通过构造函数参数、工厂方法的参数或在构造或从工厂方法返回后在对象实例上设置的属性来定义它们的依赖,也就是它们使用的其他对象。然后,容器在创建bean时注入这些依赖项。这个过程基本上是bean本身的逆过程,因此称为控制反转(IoC),它通过使用类的直接构造(S)来控制其依赖项的实例化或位置
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.
- 使用DI原则,代码会更清晰,并且当对象带有依赖项时,解耦会更有效。对象不查找其依赖项,也不知道依赖项的位置或类。因此,您的类变得更容易测试,特别是当依赖关系是在接口或抽象基类上时,它们允许在单元测试中使用存根或模拟实现。
DI exists in two major variants, Constructor-based dependency injection and Setter-based dependency injection.
- 依赖注入有两种主要的变体,即基于构造器的依赖注入和基于setter的依赖注入。
Constructor-based dependency injection (Constructor-based依赖注入)
- 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 astatic
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.- 基于构造器的DI是由容器调用带有许多参数的构造器来完成的,每个参数表示一个依赖项。调用带有特定参数的静态工厂方法来构造bean几乎是等效的,本讨论对构造函数的参数和静态工厂方法的处理是类似的。下面的示例显示了只能通过构造函数注入进行依赖注入的类。请注意,这个类没有什么特别之处,它是一个POJO,不依赖于容器特定的接口、基类或注释。
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on a MovieFinder
private MovieFinder movieFinder;
// a constructor so that the Spring container can inject a MovieFinder
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually uses the injected MovieFinder is omitted...
}
Constructor argument resolution
- 构造函数参数解析
Constructor argument resolution matching occurs using the argument’s 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定义的构造函数参数中不存在潜在的歧义,那么构造函数参数在bean定义中定义的顺序就是实例化bean时将这些参数提供给适当的构造函数的顺序。考虑以下类:
package x.y;
public class Foo {
public Foo(Bar bar, Baz baz) {
// ...
}
}
- No potential ambiguity exists, assuming that
Bar
andBaz
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.- 假设Bar和Baz类不通过继承关联,则不存在潜在的歧义。因此,以下配置可以很好地工作,您不需要在元素中显式地指定构造函数参数索引和/或类型。
<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时,类型是已知的,可以进行匹配(就像前面的例子一样)。当使用简单类型时,例如true, 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;
}
}
Constructor argument type matching
- 构造函数参数类型匹配
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>
Constructor argument index
- 构造函数参数指标
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
- 除了解决多个简单值的模糊性之外,指定索引还可以解决构造函数有两个相同类型的参数时的模糊性。注意,索引是基于0的。
Constructor argument name
- 构造函数参数的名字
You can also use the constructor parameter name for value disambiguation:
- 也可以使用构造函数参数名来消除值的歧义:
<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 can’t compile your code with debug flag (or don’t want to) you can use @ConstructorProperties JDK annotation to explicitly name your constructor arguments. The sample class would then have to look as follows:
- 请记住,要做到开箱即用,您的代码必须在启用调试标志的情况下进行编译,以便Spring可以从构造函数中查找参数名。如果不能使用调试标志(或不想这样做)编译代码,可以使用@ConstructorProperties JDK注释显式地命名构造函数参数。然后,样例类必须看起来像这样:
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-based依赖注入)
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的DI是由容器在调用无参数构造函数或无参数静态工厂方法来实例化bean之后调用bean上的setter方法来完成的。
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 aBeanDefinition
, which you use in conjunction withPropertyEditor
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 XMLbean
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 ofBeanDefinition
and used to load an entire Spring IoC container instance.- ApplicationContext为它管理的bean支持基于构造器和基于setter的DI。在已经通过构造函数方法注入了一些依赖项之后,它还支持基于setter的DI。您以BeanDefinition的形式配置依赖项,您将它与PropertyEditor实例一起使用,以将属性从一种格式转换为另一种格式。然而,大多数Spring用户并不直接使用这些类(即,通过编程),而是使用XML bean定义、带注释的组件(即,带@Component、@Controller等注释的类),
Constructor-based or setter-based DI?
Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the @Required annotation on a setter method can be used to make the property a required dependency.
- 由于可以混合使用基于构造器和基于setter的DI,对于强制依赖项使用构造器,而对于可选依赖项使用setter方法或配置方法,这是一个很好的经验法则。注意,在setter方法上使用@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团队通常提倡构造函数注入,因为它允许将应用程序组件实现为不可变对象,并确保所需的依赖关系不为空。此外,构造注入的组件总是以完全初始化的状态返回给客户端(调用)代码。顺便提一下,大量的构造函数参数是一种糟糕的代码味道,这意味着类可能有太多的责任,应该进行重构以更好地解决问题的适当分离
Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is therefore a compelling use case for setter injection.
- Setter注入应该主要用于可选的依赖项,这些依赖项可以在类中分配合理的默认值。否则,必须在代码使用依赖项的任何地方执行非空检查。setter注入的一个好处是,setter方法使该类的对象易于稍后重新配置或重新注入。因此,通过JMX mbean进行管理是setter注入的一个引人注目的用例。
Use the DI style that makes the most sense for a particular class. Sometimes, when dealing with third-party classes for which you do not have the source, the choice is made for you. For example, if a third-party class does not expose any setter methods, then constructor injection may be the only available form of DI.
- 使用对特定类最有意义的DI样式。有时,在处理没有源代码的第三方类时,需要自己做出选择。例如,如果第三方类不公开任何setter方法,那么构造函数注入可能是DI的唯一可用形式。
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- 用描述所有bean的配置元数据创建和初始化ApplicationContext。配置元数据可以通过XML、Java代码或注释指定。.
- For each bean, its dependencies are expressed in the form of properties, constructor arguments, or arguments to the static-factory method if you are using that instead of a normal constructor. These dependencies are provided to the bean, when the bean is actually created.
- 对于每个bean,其依赖关系以属性、构造函数参数或静态工厂方法参数(如果使用静态工厂方法而不是普通构造函数)的形式表示。当bean被实际创建时,这些依赖项被提供给bean。
- Each property or constructor argument is an actual definition of the value to set, or a reference to another bean in the container.
- 每个属性或构造函数参数都是要设置的值的实际定义,或者是对容器中另一个bean的引用。
- Each property or constructor argument 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可以将字符串格式提供的值转换为所有内置类型,如int、long、string、boolean等。
- The
- 容器执行如下的bean依赖项解析:
The Spring container validates the configuration of each bean as the container is created. However, the bean properties themselves are not set until the bean is actually created. Beans that are singleton-scoped and set to be pre-instantiated (the default) are created when the container is created. Scopes are defined in Bean scopes. Otherwise, the bean is created only when it is requested. Creation of a bean potentially causes a graph of beans to be created, as the bean’s dependencies and its dependencies' dependencies (and so on) are created and assigned. Note that resolution mismatches among those dependencies may show up late, i.e. on first creation of the affected bean.
- 在创建容器时,Spring容器验证每个bean的配置。但是,bean属性本身在实际创建bean之前是不会设置的。在创建容器时,将创建单例范围并设置为预实例化(缺省值)的bean。作用域在Bean作用域中定义。否则,只在请求bean时创建它。创建一个bean可能会导致创建一个bean图,因为创建和分配了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
.
- 例如:类A通过构造函数注入需要一个类B的实例,类B通过构造函数注入需要一个类A的实例。如果您为类A和类B配置了相互注入的bean,那么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.
- 一个可能的解决方案是编辑一些类的源代码,以便由setter而不是构造器配置。或者,避免构造函数注入,只使用setter注入。换句话说,尽管不建议这样做,但您可以使用setter注入配置循环依赖关系。
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).
- 与典型的情况不同(没有循环依赖关系),bean a和bean B之间的循环依赖关系迫使一个bean在完全初始化之前注入另一个bean(典型的先有鸡还是先有蛋的场景)。
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 theApplicationContext
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的引用和循环依赖关系。Spring尽可能晚地设置属性并解析依赖项,当bean实际创建时。这意味着,当您请求一个对象时,如果在创建该对象或其依赖项时出现问题,已正确加载的Spring容器可以稍后生成一个异常。例如,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依赖bean B, B Spring IoC容器完全配置bean之前调用bean的setter方法A。换句话说,bean实例化(如果不是一个单例预先实例化),其设置依赖项,相关的生命周期方法(如InitializingBean init方法或配置回调方法)调用
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:
- 下面的示例对基于setter的DI使用基于xml的配置元数据。Spring XML配置文件的一小部分指定了一些bean定义:
<bean id="exampleBean" class="examples.ExampleBean">
<!-- setter injection using the nested ref element -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<!-- setter injection using the neater ref attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
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:
- 在前面的示例中,将setter声明为与XML文件中指定的属性相匹配。下面的例子使用了基于构造器的DI:
<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:- 现在考虑这个例子的一个变体,这里不是使用构造函数,而是让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 thestatic
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 thefactory-bean
attribute instead of theclass
attribute), so details will not be discussed here.- 静态工厂方法的参数是通过元素提供的,就像实际使用了构造函数一样。由工厂方法返回的类的类型不必与包含静态工厂方法的类的类型相同,尽管在本例中它是相同的。实例(非静态)工厂方法将以基本相同的方式使用(除了使用factory-bean属性而不是class属性之外),因此这里不讨论细
1.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. Spring’s XML-based configuration metadata supports sub-element types within its
<property/>
and<constructor-arg/>
elements for this purpose.- 如前一节所述,可以将bean属性和构造函数参数定义为对其他托管bean(协作者)的引用,或者定义为内联定义的值。Spring基于xml的配置元数据支持其和元素中的子元素类型
Straight values (primitives, Strings, and so on) (直接值【原语、字符串等】)
- The
value
attribute of the<property/>
element specifies a property or constructor argument as a human-readable string representation. Spring’s conversion service is used to convert these values from aString
to the actual type of the property or argument.- 元素的value属性将属性或构造函数参数指定为人类可读的字符串表示形式。Spring的转换服务用于将这些值从字符串转换为属性或参数的实际类型
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- results in a setDriverClassName(String) call -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="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.
- 前面的XML更简洁;然而,拼写错误是在运行时而不是设计时发现的,除非您使用IDE,如IntelliJ IDEA或Spring工具套件(STS),这些IDE支持在创建bean定义时自动完成属性。强烈建议提供这样的IDE帮助。
You can also configure a
java.util.Properties
instance as:- 您还可以配置java.util。属性实例:
<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 ajava.util.Properties
instance by using the JavaBeansPropertyEditor
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 thevalue
attribute style.- Spring容器将元素中的文本转换为java.util。属性实例,通过使用JavaBeans的PropertyEditor机制。这是一个很好的快捷方式,也是Spring团队偏爱使用嵌套的元素而不是value属性styl的几个地方之一.
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元素只是将容器中另一个bean的id(字符串值——而不是引用)传递给或元素的一种防止错误的方法。
<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 thetargetName
property of theclient
bean. Typos are only discovered (with most likely fatal results) when theclient
bean is actually instantiated. If theclient
bean is a prototype bean, this typo and the resulting exception may only be discovered long after the container is deployed.- 第一种形式比第二种形式更好,因为使用idref标记允许容器在部署时验证引用的已命名bean确实存在。在第二个变体中,对传递给客户机bean的targetName属性的值不执行验证。只有在实际实例化客户机bean时才会发现拼写错误(最有可能导致致命的结果)。如果客户端bean是原型bean,则此类型和结果异常可能要在容器部署很久之后才会被发现。
The
local
attribute on theidref
element is no longer supported in the 4.0 beans xsd since it does not provide value over a regularbean
reference anymore. Simply change your existingidref local
references toidref bean
when upgrading to the 4.0 schema.- 在4.0 bean xsd中不再支持idref元素上的local属性,因为它不再提供常规bean引用上的值。只要在升级到4.0模式时将现有的idref本地引用更改为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 aProxyFactoryBean
bean definition. Using<idref/>
elements when you specify the interceptor names prevents you from misspelling an interceptor id.- 元素带来值的常见位置(至少在spring2.0之前的版本中)是在ProxyFactoryBean bean定义中的AOP拦截器配置中。在指定拦截器名称时使用元素可以防止拼写错误。
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 thebean
,local,
orparent
attributes.- ref元素是或定义元素中的最后一个元素。在这里,您将bean的指定属性的值设置为对容器管理的另一个bean(协作者)的引用。被引用的bean是将被设置其属性的bean的依赖项,并且在设置属性之前根据需要对其进行初始化(如果协作者是单例bean,它可能已经被容器初始化了)。所有引用最终都是对另一个对象的引用。范围和验证取决于是否指定id/名称o
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 thebean
attribute may be the same as theid
attribute of the target bean, or as one of the values in thename
attribute of the target bean.- 通过标记的bean属性指定目标bean是最通用的形式,它允许创建对同一容器或父容器中任何bean的引用,而不管它是否在同一XML文件中。bean属性的值可以与目标bean的id属性相同,或者与目标bean的name属性中的一个值相同。
<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 theparent
attribute may be the same as either theid
attribute of the target bean, or one of the values in thename
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.- 通过父属性指定目标bean,将创建对当前容器父容器中bean的引用。父属性的值可以与目标bean的id属性相同,或者与目标bean的name属性中的一个值相同,并且目标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>
- The
local
attribute on theref
element is no longer supported in the 4.0 beans xsd since it does not provide value over a regularbean
reference anymore. Simply change your existingref local
references toref bean
when upgrading to the 4.0 schema.- 在4.0 bean xsd中不再支持ref元素上的local属性,因为它不再提供常规bean引用上的值。只要在升级到4.0模式时将现有的ref本地引用更改为ref bean即可。
Inner beans (内部beans)
- A
<bean/>
element inside the<property/>
or<constructor-arg/>
elements defines a so-called inner bean.- 或元素中的元素定义了一个所谓的内部bean。
<bean id="outer" class="...">
<!-- instead of using a reference to a target bean, simply define the target bean inline -->
<property name="target">
<bean class="com.example.Person"> <!-- this is the inner bean -->
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</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定义不需要定义id或名称;如果指定,容器不使用这样的值作为标识符。容器在创建时还会忽略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 scope’s lifecycle. This is not a common scenario; inner beans typically simply share their containing bean’s scope.
- 角情况下,可以接收来自自定义范围的破坏回调,例如请求范围内内在bean包含在一个单例bean:内心的bean实例的创建将绑定到包含bean,但破坏回调允许它参与请求范围的生命周期。这不是常见的场景;内部bean通常只是共享包含它们的bean的作用域。
Collections (集合)
- In the
<list/>
,<set/>
,<map/>
, and<props/>
elements, you set the properties and arguments of the JavaCollection
typesList
,Set
,Map
, andProperties
, respectively.- 在、、和元素中,您可以分别设置Java集合类型列表、set、map和properties的属性和参数。
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key ="a ref" value-ref="myDataSource"/>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
- The value of a map key or value, or a set value, can also again be any of the following elements:
- 映射键或值的值,或设定值,也可以是以下任何元素:
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 , , or element, and have child-style , , or elements inherit and override values from the parent collection. That is, the child collection’s values are the result of merging the elements of the parent and child collections, with the child’s collection elements overriding values specified in the parent collection.
- Spring容器还支持集合的合并。应用开发者可以定义父样式、、或元素,让子样式、、或元素继承和覆盖父集合的值。也就是说,子集合的值是合并父集合和子集合的元素的结果,子集合元素覆盖父集合中指定的值。
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和子bean定义的读者可能希望在继续之前阅读相关部分。
The following example demonstrates collection merging:
- 下面的例子演示了集合合并:
<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.com</prop>
<prop key="support">support@example.com</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="adminEmails">
<!-- the merge is specified on the child collection definition -->
<props merge="true">
<prop key="sales">sales@example.com</prop>
<prop key="support">support@example.co.uk</prop>
</props>
</property>
</bean>
<beans>
- Notice the use of the
merge=true
attribute on the<props/>
element of theadminEmails
property of thechild
bean definition. When thechild
bean is resolved and instantiated by the container, the resulting instance has anadminEmails
Properties
collection that contains the result of the merging of the child’sadminEmails
collection with the parent’sadminEmails
collection.- 注意在子bean定义的adminEmails属性的元素上使用了merge=true属性。当容器解析并实例化子bean时,生成的实例具有一个adminEmails属性集合,其中包含子实例的adminEmails集合与父实例的adminEmails集合合并的结果。
administrator=administrator@example.com
sales=sales@example.com
support=support@example.co.uk
The child
Properties
collection’s value set inherits all property elements from the parent<props/>
, and the child’s value for thesupport
value overrides the value in the parent collection.- 子属性集合的值集继承父属性中的所有属性元素,子属性支持值的值覆盖父属性集合中的值。
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 theList
collection type, that is, the notion of anordered
collection of values, is maintained; the parent’s values precede all of the child list’s values. In the case of theMap
,Set
, andProperties
collection types, no ordering exists. Hence no ordering semantics are in effect for the collection types that underlie the associatedMap
,Set
, andProperties
implementation types that the container uses internally.- 这种合并行为类似地应用于、和集合类型。在元素的特定情况下,维护与列表集合类型相关的语义,即值的有序集合的概念;父元素的值位于所有子元素列表的值之前。对于Map、Set和Properties集合类型,不存在排序。因此,对于位于容器内部使用的关联映射、集合和属性实现类型下的集合类型,排序语义不起作用。
Limitations of collection merging
- 集合合并的限制
You cannot merge different collection types (such as a
Map
and aList
), and if you do attempt to do so an appropriateException
is thrown. Themerge
attribute must be specified on the lower, inherited, child definition; specifying themerge
attribute on a parent collection definition is redundant and will not result in the desired merging.- 您不能合并不同的集合类型(如映射和列表),如果您尝试这样做,将引发适当的异常。merge属性必须在较低的继承子定义中指定;在父集合定义上指定合并属性是多余的,不会导致所需的合并。
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 containString
elements (for example). If you are using Spring to dependency-inject a strongly-typedCollection
into a bean, you can take advantage of Spring’s type-conversion support such that the elements of your strongly-typedCollection
instances are converted to the appropriate type prior to being added to theCollection
.- 随着Java 5中泛型类型的引入,您可以使用强类型集合。也就是说,可以声明一个集合类型,使它只能包含字符串元素(例如)。如果您使用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 thefoo
bean is prepared for injection, the generics information about the element type of the strongly-typedMap<String, Float>
is available by reflection. Thus Spring’s type conversion infrastructure recognizes the various value elements as being of typeFloat
, and the string values9.99, 2.75
, and3.99
are converted into an actualFloat
type.- 当foo bean的accounts属性为注入做好准备时,关于强类型Map<String, Float>的元素类型的泛型信息可以通过反射获得。因此,Spring的类型转换基础设施将各种值元素识别为Float类型,并将字符串值9.99、2.75和3.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 emptyString
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 handlesnull
values. For example:- 元素的作用是:处理空值。为
<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
element’s attributes, instead of nested<property/>
elements, to describe your property values and/or collaborating beans.- p-名称空间使您能够使用bean元素的属性(而不是嵌套的元素)来描述您的属性值和/或协作bean。
Spring supports extensible configuration formats with namespaces, which are based on an XML Schema definition. The
beans
configuration format discussed in this chapter is defined in an XML Schema document. However, the p-namespace is not defined in an XSD file and exists only in the core of Spring.- Spring支持带有名称空间的可扩展配置格式,名称空间基于XML模式定义。本章中讨论的bean配置格式是在XML模式文档中定义的。但是,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-namespace没有模式定义,因此可以将属性名设置为属性名。
This next example includes two more bean definitions that both have a reference to another bean:
- 下一个示例包括另外两个bean定义,它们都引用了另一个be
<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 beanjohn
to beanjane
, the second bean definition usesp:spouse-ref="jane"
as an attribute to do the exact same thing. In this casespouse
is the property name, whereas the-ref
part indicates that this is not a straight value but rather a reference to another bean.- 如您所见,这个示例不仅包含使用p-名称空间的属性值,而且还使用一种特殊格式来声明属性引用。第一个bean定义使用来创建一个从bean john到bean jane的引用,第二个bean定义使用p:配偶-ref="jane"作为一个属性来完成完全相同的工作。在本例中,spouse是属性名,而-ref部分表明这不是一个直接的值,而是对另一个bean的引用。
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 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-namespace的XML快捷方式类似,Spring 3.1中新引入的c-namespace允许使用内联属性来配置构造函数参数,而不是使用嵌套的构造函数参数元素。
Let’s review the examples from Constructor-based dependency injection with 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 thep:
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).- 名称空间使用与p: one相同的约定(对于bean引用,尾随-ref)来按名称设置构造函数参数。同样,即使它没有在XSD模式中定义(但它存在于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:
- 对于构造函数参数名不可用的罕见情况(通常是在编译字节码时没有调试信息),可以使用回退到参数索引:
<!-- c-namespace index declaration -->
<bean id="foo" class="x.y.Foo" c:_0-ref="bar" c:_1-ref="baz"/>
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语法的原因,索引表示法要求出现前导_,因为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.
- 在实践中,构造函数解析机制在匹配参数方面非常有效,因此,除非确实需要,我们建议在整个配置中使用名称符号。
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 afred
property, which has abob
property, which has asammy
property, and that finalsammy
property is being set to the value123
. In order for this to work, thefred
property offoo
, and thebob
property offred
must not benull
after the bean is constructed, or aNullPointerException
is thrown.- foo bean有一个fred属性,这个fred属性有一个bob属性,这个bob属性又有一个sammy属性,最后一个sammy属性被设置为123。为了使其工作,在构造bean之后,foo的fred属性和fred的bob属性不能为空,或者抛出NullPointerException。
1.4.3. Using 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 `` 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 thedepends-on
attribute to express a dependency on a single bean:- 如果一个bean是另一个bean的依赖项,这通常意味着一个bean被设置为另一个bean的属性。通常使用基于xml的配置元数据中的元素来完成此任务。然而,有时bean之间的依赖关系并不那么直接;例如,类中的静态初始化器需要被触发,比如数据库驱动程序注册。depends-on属性可以显式地强制在初始化使用此元素的bean之前初始化一个或多个bean。下面的例子使用依赖属性来表示对单个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的依赖,提供一个bean名称列表作为depends-on属性的值,使用逗号、空格和分号作为有效的分隔符:
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
- 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 adepends-on
relationship with a given bean are destroyed first, prior to the given bean itself being destroyed. Thusdepends-on
can also control shutdown order.- bean定义中的depends-on属性既可以指定初始化时间依赖项,也可以指定对应的销毁时间依赖项(仅在单例bean中)。在销毁给定bean本身之前,首先销毁与给定bean定义依赖关系的依赖bean。因此,依赖还可以控制关机顺序。
1.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告诉IoC容器在第一次请求bean实例时(而不是在启动时)创建bean实例。
In XML, this behavior is controlled by the
lazy-init
attribute on the<bean/>
element; for example:- 在XML中,这种行为由元素的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 namedlazy
is not eagerly pre-instantiated when theApplicationContext
is starting up, whereas thenot.lazy
bean is eagerly pre-instantiated.- 当ApplicationContext使用前面的配置时,在ApplicationContext启动时,名为lazy的bean不会急于预实例化,而不是。惰性bean被急切地预实例化。
However, when a lazy-initialized bean is a dependency of a singleton bean that is not lazy-initialized, the
ApplicationContext
creates the lazy-initialized bean at startup, because it must satisfy the singleton’s dependencies. The lazy-initialized bean is injected into a singleton bean elsewhere that is not lazy-initialized.- 然而,当延迟初始化bean是未延迟初始化的单例bean的依赖项时,ApplicationContext在启动时创建延迟初始化bean,因为它必须满足单例的依赖项。惰性初始化的bean被注入到没有惰性初始化的其他地方的单例bean中。
You can also control lazy-initialization at the container level by using the
default-lazy-init
attribute on the<beans/>
element; for example:- 通过使用元素上的default-lazy-init属性,还可以在容器级别控制延迟初始化;例如:
<beans default-lazy-init="true">
<!-- no beans will be pre-instantiated... -->
</beans>
1.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自动解析协作者(其他bean)。自动装配有以下优点:
Autowiring can significantly reduce the need to specify properties or constructor arguments. (Other mechanisms such as a bean template discussed elsewhere in this chapter are also valuable in this regard.)
- 自动装配可以显著减少指定属性或构造函数参数的需要。(其他机制,比如本章其他地方讨论的bean模板,在这方面也很有价值。)
Autowiring can update a configuration as your objects evolve. For example, if you need to add a dependency to a class, that dependency can be satisfied automatically without you needing to modify the configuration. Thus autowiring can be especially useful during development, without negating the option of switching to explicit wiring when the code base becomes more stable.
- 自动装配可以随着对象的发展更新配置。例如,如果需要向类添加依赖项,则无需修改配置即可自动满足该依赖项。因此,自动装配在开发过程中特别有用,当代码库变得更加稳定时,无需切换到显式连接。
When using XML-based configuration metadata [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的配置元数据[2]时,您可以使用元素的autowire属性为bean定义指定自动装配模式。自动装配功能有四种模式。您可以为每个bean指定自动装配,因此可以选择要自动装配的bean。
Table 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元素定义。对于较大的部署,不建议更改默认设置,因为显式地指定collaborator可以提供更好的控制和清晰度。在某种程度上,它记录了系统的结构。) |
byName(按名称装配) | Autowiring by property name. Spring looks for a bean with the same name as the property that needs to be autowired. For example, if a bean definition is set to autowire by name, and it contains a master property (that is, it has a setMaster(..) method), Spring looks for a bean definition named master , and uses it to set the property.(按属性名称自动装配。Spring寻找与需要自动实现的属性同名的bean。例如,如果一个bean定义按名称设置为autowire,并且它包含一个master属性(也就是说,它有一个setMaster(..)方法),那么Spring将查找一个名为master的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使用byType自动装配。如果没有匹配的豆子,什么也不会发生;该属性未设置。) |
constructor(构造器装配) | Analogous to byType, but applies to constructor arguments. If there is not exactly one bean of the constructor argument ty(类似于byType,但适用于构造函数参数。如果容器中没有构造函数参数类型的确切bean,就会引发致命错误。) |
With byType or constructor autowiring mode, you can wire arrays and typed-collections. In such cases all autowire candidates within the container that match the expected type are provided to satisfy the dependency. You can autowire strongly-typed 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.使用byType或构造函数自动装配模式,您可以连接数组和类型集合。在这种情况下,将提供容器中与预期类型匹配的所有自动装配候选对象来满足依赖关系。如果期望的键类型是String,你可以自动连接强类型的映射。自动生成的Maps值将由与预期类型匹配的所有bean实例组成,Maps键将包含相应的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
andconstructor-arg
settings always override autowiring. You cannot autowire so-called simple properties such as primitives,Strings
, andClasses
(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管理对象之间的关系不再被明确地记录。
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定义可能与要自动实现的setter方法或构造函数参数指定的类型相匹配。对于数组、集合或映射,这不一定是个问题。但是,对于期望单个值的依赖项,这种模糊性不能任意解决。如果没有可用的唯一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 tofalse
as described in the next section.- 通过将一个bean定义的自动装配候选属性设置为false来避免自动装配,如下一节所述。
Designate a single bean definition as the primary candidate by setting the
primary
attribute of its<bean/>
element totrue
.- 通过将单个bean定义的元素的主属性设置为true,将其指定为主候选bean定义。
Implement the more fine-grained control available with annotation-based configuration, as described in Annotation-based container configuration.
- 使用基于注释的配置实现更细粒度的控制,如在基于注释的容器配置中所述。
Excluding a bean from autowiring(不包括自动装配的bean)
On a per-bean basis, you can exclude a bean from autowiring. In Spring’s XML format, set the
autowire-candidate
attribute of the<bean/>
element tofalse
; the container makes that specific bean definition unavailable to the autowiring infrastructure (including annotation style configurations such as@Autowired
).- 在每个bean的基础上,您可以从自动装配中排除一个bean。在Spring的XML格式中,将元素的autowell -candidate属性设置为false;容器使得特定的bean定义对自动装配基础设施不可用(包括注释风格配置,如@Autowired)。
The
autowire-candidate
attribute is designed to only affect type-based autowiring. It does not affect explicit references by name, which will get resolved even if the specified bean is not marked as an autowire candidate. As a consequence, autowiring by name will nevertheless inject a bean if the name matches.- autowire-candidate属性被设计为只影响基于类型的自动装配。它不会影响名称的显式引用,即使指定的bean没有标记为自动装配候选对象,也会被解析。因此,如果名称匹配,按名称自动装配仍然会注入一个bean。
You can also limit autowire candidates based on pattern-matching against bean names. The top-level
<beans/>
element accepts one or more patterns within itsdefault-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 oftrue
orfalse
for a bean definitionsautowire-candidate
attribute always takes precedence, and for such beans, the pattern matching rules do not apply.- 您还可以基于对bean名称的模式匹配来限制自动连接候选项。顶级的元素在其默认-自动连接-候选属性中接受一个或多个模式。例如,要将自动装配候选状态限制为名称以Repository结尾的任何bean,可以提供一个值*Repository。要提供多个模式,请在逗号分隔的列表中定义它们。bean定义自动候选属性的显式值true或false总是优先,对于这样的bean,模式匹配规则不适用。
These techniques are useful for beans that you never want to be injected into other beans by autowiring. It does not mean that an excluded bean cannot itself be configured using autowiring. Rather, the bean itself is not a candidate for autowiring other beans.
- 这些技术对于那些您永远不希望通过自动装配被注入到其他bean中的bean非常有用。这并不意味着被排除的bean本身不能使用自动装配进行配置。相反,该bean本身不是自动连接其他bean的候选对象。
1.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的属性来处理依赖关系。当bean的生命周期不同时,问题就出现了。假设单例bean A需要使用非单例(原型)bean B,可能在对A的每次方法调用上都是如此,容器只创建单例bean A一次,因此只有一次机会设置属性。的帐目
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:- 一个解决办法是放弃一些控制反转。您可以通过实现applicationcontexts taware接口,以及在每次bean A需要bean B实例时,通过对容器进行getBean(“B”)调用来让bean A知道容器。下面是这种方法的一个例子:
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;
// Spring-API imports
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 = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
// notice the Spring API dependency!
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 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.
- 查找方法注入是指容器覆盖容器管理bean上的方法,返回容器中另一个已命名bean的查找结果的能力。查找通常涉及原型bean,如上一节所述的场景。Spring框架通过使用来自CGLIB库的字节码生成动态地生成覆盖该方法的子类来实现这种方法注入。
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 befinal
either.- 要使这个动态子类工作,Spring bean容器将子类化的类不能是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 theabstract
method.- 单元测试具有抽象方法的类需要您自己创建类的子类,并提供抽象方法的存根实现。
Concrete methods are also necessary for component scanning which requires concrete classes to pick up.
- Concrete methods are also necessary for component scanning which requires concrete classes to pick up.
A further key limitation is that lookup methods won’t 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.- 另一个关键的限制是,查找方法不能与工厂方法一起工作,特别是与配置类中的@Bean方法一起工作,因为在这种情况下容器不负责创建实例,因此不能动态地创建运行时生成的子类。
Looking at the
CommandManager
class in the previous code snippet, you see that the Spring container will dynamically override the implementation of thecreateCommand()
method. YourCommandManager
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:- 在包含要注入的方法的客户端类中(本例中为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 themyCommand
bean as a prototype, if that is actually what is needed. If it is as a singleton, the same instance of themyCommand
bean is returned each time.- 标识为commandManager的bean在需要myCommand bean的新实例时调用自己的方法createCommand()。如果真的需要将myCommand bean部署为原型,则必须小心。如果它是单例的,那么每次都返回相同的myCommand bean实例。
Alternatively, within the annotation-based component model, you may declare a lookup method through the
@Lookup
annotation:- 或者,在基于注释的组件模型中,您可以通过@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:
- 或者,更习惯地说,你可以依赖于目标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 Spring’s 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.
请注意,您通常会使用具体的存根实现来声明这种带注释的查找方法,以便它们与Spring的组件扫描规则兼容,其中抽象类在默认情况下会被忽略。此限制不适用于显式注册或显式导入的bean类。
Another way of accessing differently scoped target beans is an
ObjectFactory
/Provider
injection point. Check out Scoped beans as dependencies.The interested reader may also find the
ServiceLocatorFactoryBean
(in theorg.springframework.beans.factory.config
package) to be of use.访问作用域不同的目标bean的另一种方法是ObjectFactory/ Provider注入点。检出作用域bean作为依赖项。
感兴趣的读者还可以在org.springframework.beans.factory中找到ServiceLocatorFactoryBean。配置包)的使用。
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.
- 方法注入的一种不如查找方法注入有用的形式是用另一个方法实现替换托管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.bean .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 matchjava.lang.String
:- 可以使用元素中包含的一个或多个< argtype />元素来指示被覆盖方法的方法签名。只有当方法被重载并且类中存在多个变体时,参数的签名才有必要。为了方便,参数的类型字符串可以是完全限定类型名的子字符串。例如,以下所有匹配java.lang.String:
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.
- 由于参数的数量通常足以区分每种可能的选择,因此通过只键入与参数类型匹配的最短字符串,此快捷方式可以节省大量输入。
后续翻译玩命加载中...
spring官网在线学习文档翻译的更多相关文章
- 看了 Spring 官网脚手架真香,也撸一个 SpringBoot DDD 微服务的脚手架!
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 为什么我们要去造轮子? 造轮子的核心目的,是为了解决通用共性问题的凝练和复用. 虽然 ...
- Spring官网阅读 | 总结篇
接近用了4个多月的时间,完成了整个<Spring官网阅读>系列的文章,本文主要对本系列所有的文章做一个总结,同时也将所有的目录汇总成一篇文章方便各位读者来阅读. 下面这张图是我整个的写作大 ...
- Spring官网阅读(十八)Spring中的AOP
文章目录 什么是AOP AOP中的核心概念 切面 连接点 通知 切点 引入 目标对象 代理对象 织入 Spring中如何使用AOP 1.开启AOP 2.申明切面 3.申明切点 切点表达式 excecu ...
- Spring官网阅读(十七)Spring中的数据校验
文章目录 Java中的数据校验 Bean Validation(JSR 380) 使用示例 Spring对Bean Validation的支持 Spring中的Validator 接口定义 UML类图 ...
- Spring官网阅读(十六)Spring中的数据绑定
文章目录 DataBinder UML类图 使用示例 源码分析 bind方法 doBind方法 applyPropertyValues方法 获取一个属性访问器 通过属性访问器直接set属性值 1.se ...
- Spring官网阅读(二)(依赖注入及方法注入)
上篇文章我们学习了官网中的1.2,1.3两小节,主要是涉及了容器,以及Spring实例化对象的一些知识.这篇文章我们继续学习Spring官网,主要是针对1.4小节,主要涉及到Spring的依赖注入.虽 ...
- Spring官网阅读(三)自动注入
上篇文章我们已经学习了1.4小结中关于依赖注入跟方法注入的内容.这篇文章我们继续学习这结中的其他内容,顺便解决下我们上篇文章留下来的一个问题-----注入模型. 文章目录 前言: 自动注入: 自动注入 ...
- Spring官网阅读(四)BeanDefinition(上)
前面几篇文章已经学习了官网中的1.2,1.3,1.4三小结,主要是容器,Bean的实例化及Bean之间的依赖关系等.这篇文章,我们继续官网的学习,主要是BeanDefinition的相关知识,这是Sp ...
- Spring官网阅读(一)容器及实例化
从今天开始,我们一起过一遍Spring的官网,一边读,一边结合在路神课堂上学习的知识,讲一讲自己的理解.不管是之前关于动态代理的文章,还是读Spring的官网,都是为了之后对Spring的源码做更全面 ...
随机推荐
- 在.NET Core中使用MongoDB明细教程(1):驱动基础及文档插入
MongoDB,被归类为NoSQL数据库,是一个以类JSON格式存储数据的面向文档的数据库系统.MongoDB在底层以名为bson的二进制编码格式表示JSON文档,MongoDB bson实现是轻量级 ...
- SpringMVC的简介和工作流程
一.简介 Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面.Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块.Spri ...
- 本blog的地图
欢迎 CTRL+F收索 / CTRL+D 持续更新 C++: C++快速排序 C++归并排序 高精度 CSS: CSS实现ps基础操作 PYTHON: python爬虫教程,一篇就够了 其他推荐 ...
- 【测试技术分享】Liunx常用操作命令集合
Linux命令 ls 查看文件目录内容 ls -lha l:详细信息 h:人性化显示 a:查看隐藏目录 ls -目录名 查看指定目录 d rwx rwx rwx d:文件夹 -:文件 rwx:拥有 ...
- arp_ignore与arp_announce
arp_ignore:定义接收到ARP请求时的响应级别0:只要本地设置的有相应的地址,就给予响应.(默认)1:仅回应目标IP地址是本地的入网地址的arp请求.2:仅回应目标IP地址是本地的入网地址,而 ...
- Spring Security拦截器加载流程分析--练气中期
写在前面 上回我们讲了spring security整合spring springmvc的流程,并且知道了spring security是通过过滤器链来进行认证授权操作的.今天我们来分析一下sprin ...
- 第7篇scrum冲刺(5.27)
一.站立会议 1.照片 2.工作安排 成员 昨天已完成的工作 今天的工作安排 困难 陈芝敏 学习云开发,云函数调用以及数据的前后端传递 今天实现云词库搭建,随机获取并显示,对云开发有更深的认识 ...
- Deep and Beautiful. The Reward Prediction Error Hypothesis of Dopamine
郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! Contents: Abstract 1. Introduction 2. Reward-Prediction Error Meets D ...
- Python中print()函数不换行的方法以及分隔符替换
一.让print()函数不换行 在Python中,print()函数默认是换行的.但是,在很多情况下,我们需要不换行的输出(比如在算法竞赛中).那么,在Python中如何做到这一点呢? 其实很简单.只 ...
- codeforce Round #665(div 2)A B C
A. Distance and Axis 题意:在一个0x轴上,给了a在0x轴上的坐标,要你放一个b点使得abs(0B - AB)的值等于 k,但是有的时候如果不移动A点就不能实现这个条件,所以要你求 ...