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注释的方法。
- Spring配置由容器必须管理的至少一个(通常是多个)bean定义组成。基于xml的配置元数据显示这些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定义。例如:
- 您可以使用应用程序上下文构造函数从所有这些XML片段加载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的实例
- ApplicationContext是一个高级工厂的接口,该工厂能够维护不同bean及其依赖项的注册表。使用方法T getBean(字符串名,类
-
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
定义的形式
- 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的配置元数据中,可以使用
元素来完成此任务。
- 然而,指定实际定义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的配置元数据,则指定要在
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类不通过继承关联,则不存在潜在的歧义。因此,以下配置可以很好地工作,您不需要在
元素中显式地指定构造函数参数索引和/或类型。
- 假设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无法确定值的类型,因此如果没有帮助,就无法按类型进行匹配。考虑以下类
- 当引用另一个bean时,类型是已知的,可以进行匹配(就像前面的例子一样)。当使用简单类型时,例如
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的配置元数据支持其
和 元素中的子元素类型
- 如前一节所述,可以将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的几个地方之一.
- Spring容器将
-
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(字符串值——而不是引用)传递给
或 元素的一种防止错误的方法。
- 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
- ref元素是
-
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.
<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.- 在
- 、
、
- 在
<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
- ,
- Spring容器还支持集合的合并。应用开发者可以定义父样式
- 、
、 或 元素,让子样式 - 、
、 或 元素继承和覆盖父集合的值。也就是说,子集合的值是合并父集合和子集合的元素的结果,子集合元素覆盖父集合中指定的值。
- 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集合合并的结果。
- 注意在子bean定义的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。
- p-名称空间使您能够使用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的引用。
- 如您所见,这个示例不仅包含使用p-名称空间的属性值,而且还使用一种特殊格式来声明属性引用。第一个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属性控制;例如:
- 在XML中,这种行为由
<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。
- 当使用基于xml的配置元数据[2]时,您可以使用
-
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定义。
- 通过将单个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)。
- 在每个bean的基础上,您可以从自动装配中排除一个bean。在Spring的XML格式中,将
-
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,模式匹配规则不适用。
- 您还可以基于对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.
- 由于参数的数量通常足以区分每种可能的选择,因此通过只键入与参数类型匹配的最短字符串,此快捷方式可以节省大量输入。
1.5. Bean scopes(bean 范围)
When you create a bean definition, you create a recipe for creating actual instances of the class defined by that bean definition. The idea that a bean definition is a recipe is important, because it means that, as with a class, you can create many object instances from a single recipe.
- 当您创建bean定义时,您创建了一个配方,用于创建由该bean定义定义的类的实际实例。bean定义是菜谱的思想很重要,因为这意味着,与类一样,您可以从单个菜谱创建许多对象实例。
You can control not only the various dependencies and configuration values that are to be plugged into an object that is created from a particular bean definition, but also the scope of the objects created from a particular bean definition. This approach is powerful and flexible in that you can choose the scope of the objects you create through configuration instead of having to bake in the scope of an object at the Java class level. Beans can be defined to be deployed in one of a number of scopes: out of the box, the Spring Framework supports six scopes, four of which are available only if you use a web-aware ApplicationContext
.
- 您不仅可以控制要插入到从特定bean定义创建的对象中的各种依赖项和配置值,还可以控制从特定bean定义创建的对象的范围。这种方法强大而灵活,因为您可以选择通过配置创建的对象的范围,而不必在Java类级别上烘焙对象的范围。可以将bean定义为部署在多种作用域中的一种:开箱即用的Spring框架支持6种作用域,其中4种作用域只有在yo的情况下才可用
The following scopes are supported out of the box. You can also create a custom scope.
- 支持开箱即用的以下作用域。您还可以创建自定义范围。
Scope(范围) | Description(描述) |
---|---|
singleton | (Default) Scopes a single bean definition to a single object instance per Spring IoC container.((默认情况下)将单个bean定义作用于每个Spring IoC容器的单个对象实例。) |
prototype | Scopes a single bean definition to any number of object instances.(将单个bean定义作用于任意数量的对象实例。) |
request | Scopes a single bean definition to the lifecycle of a single HTTP request; that is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext .(将单个bean定义定位到单个HTTP请求的生命周期;也就是说,每个HTTP请求都有它自己的bean实例,该实例是在单个bean定义的背面创建的。仅在支持web的Spring ApplicationContext上下文中有效。) |
session | Scopes a single bean definition to the lifecycle of an HTTP Session . Only valid in the context of a web-aware Spring ApplicationContext .(将单个bean定义作用于HTTP会话的生命周期。仅在支持web的Spring ApplicationContext上下文中有效。) |
application | Scopes a single bean definition to the lifecycle of a ServletContext . Only valid in the context of a web-aware Spring ApplicationContext .(将单个bean定义作用于ServletContext的生命周期。仅在支持web的Spring ApplicationContext上下文中有效。) |
websocket | Scopes a single bean definition to the lifecycle of a WebSocket . Only valid in the context of a web-aware Spring ApplicationContext .(将单个bean定义作用于WebSocket的生命周期。仅在支持web的Spring ApplicationContext上下文中有效。) |
As of Spring 3.0, a thread scope is available, but is not registered by default. For more information, see the documentation for SimpleThreadScope . For instructions on how to register this or any other custom scope, see Using a custom scope.(在Spring 3.0中,线程作用域是可用的,但是默认情况下没有注册。有关更多信息,请参见SimpleThreadScope的文档。有关如何注册此范围或任何其他自定义范围的说明,请参见使用自定义范围。) |
|
---|---|
1.5.1. The singleton scope(单例的范围)
Only one shared instance of a singleton bean is managed, and all requests for beans with an id or ids matching that bean definition result in that one specific bean instance being returned by the Spring container.(只管理单例bean的一个共享实例,并且所有对id或id与该bean定义匹配的bean的请求都会导致Spring容器返回一个特定的bean实例。)
To put it another way, when you define a bean definition and it is scoped as a singleton, the Spring IoC container creates exactly one instance of the object defined by that bean definition. This single instance is stored in a cache of such singleton beans, and all subsequent requests and references for that named bean return the cached object.
- (换句话说,当您定义一个bean定义并且它的作用域是一个单例对象时,Spring IoC容器会创建该bean定义定义的对象的一个实例。这个单一实例存储在这样的单例bean的缓存中,对这个已命名bean的所有后续请求和引用都会返回缓存的对象。)
Spring’s concept of a singleton bean differs from the Singleton pattern as defined in the Gang of Four (GoF) patterns book. The GoF Singleton hard-codes the scope of an object such that one and only one instance of a particular class is created per ClassLoader. The scope of the Spring singleton is best described as per container and per bean. This means that if you define one bean for a particular class in a single Spring container, then the Spring container creates one and only one instance of the class defined by that bean definition. The singleton scope is the default scope in Spring. To define a bean as a singleton in XML, you would write, for example:
- Spring的单例bean概念不同于“四人帮”(GoF)模式书中定义的单例模式。GoF单例对对象的作用域进行硬编码,这样每个类加载器都会创建一个且只有一个特定类的实例。Spring单例的作用域最好按照每个容器和每个bean来描述。这意味着,如果您在单个Spring容器中为特定类定义一个bean,那么Spring容器将创建由该bean定义定义的类的一个且仅一个实例。单例作用域是Spring中的默认作用域。到德
<bean id="accountService" class="com.foo.DefaultAccountService"/>
<!-- the following is equivalent, though redundant (singleton scope is the default) -->
<bean id="accountService" class="com.foo.DefaultAccountService" scope="singleton"/>
1.5.2. The prototype scope(原型范围)
The non-singleton, prototype scope of bean deployment results in the creation of a new bean instance every time a request for that specific bean is made. That is, the bean is injected into another bean or you request it through a getBean()
method call on the container. As a rule, use the prototype scope for all stateful beans and the singleton scope for stateless beans.
- bean部署的非单例、原型范围导致每次对特定bean发出请求时都创建一个新的bean实例。也就是说,该bean被注入到另一个bean中,或者您通过容器上的getBean()方法调用请求它。作为规则,对所有有状态bean使用原型作用域,对无状态bean使用单例作用域。
The following diagram illustrates the Spring prototype scope. A data access object (DAO) is not typically configured as a prototype, because a typical DAO does not hold any conversational state; it was just easier for this author to reuse the core of the singleton diagram.
- 下图演示了Spring原型范围。数据访问对象(DAO)通常不配置为原型,因为典型的DAO不持有任何会话状态;对于作者来说,重用单例图的核心更加容易。
The following example defines a bean as a prototype in XML:
- 下面的例子用XML将bean定义为原型:
<bean id="accountService" class="com.foo.DefaultAccountService" scope="prototype"/>
In contrast to the other scopes, Spring does not manage the complete lifecycle of a prototype bean: the container instantiates, configures, and otherwise assembles a prototype object, and hands it to the client, with no further record of that prototype instance. Thus, although initialization lifecycle callback methods are called on all objects regardless of scope, in the case of prototypes, configured destruction lifecycle callbacks are not called. The client code must clean up prototype-scoped objects and release expensive resources that the prototype bean(s) are holding. To get the Spring container to release resources held by prototype-scoped beans, try using a custom bean post-processor, which holds a reference to beans that need to be cleaned up.
- 与其他作用域相比,Spring不管理原型bean的完整生命周期:容器实例化、配置和组装原型对象,然后将其交给客户端,而不进一步记录该原型实例。因此,尽管初始化生命周期回调方法在所有对象上都被调用,但在原型的情况下,配置的销毁生命周期回调不会被调用。客户端代码必须清理原型范围内的对象,并释放原型bean所持有的昂贵资源。去找弹簧公司与其他作用域相比,Spring不管理原型bean的完整生命周期:容器实例化、配置和组装原型对象,然后将其交给客户端,而不进一步记录该原型实例。因此,尽管初始化生命周期回调方法在所有对象上都被调用,但在原型的情况下,配置的销毁生命周期回调不会被调用。客户端代码必须清理原型范围内的对象,并释放原型bean所持有的昂贵资源。去找弹簧公司
In some respects, the Spring container’s role in regard to a prototype-scoped bean is a replacement for the Java new
operator. All lifecycle management past that point must be handled by the client. (For details on the lifecycle of a bean in the Spring container, see Lifecycle callbacks.)
- 在某些方面,Spring容器对于原型作用域bean的角色是Java new操作符的替代品。超过这个时间点的所有生命周期管理都必须由客户处理。(有关Spring容器中bean生命周期的详细信息,请参见生命周期回调。)
1.5.3. Singleton beans with prototype-bean dependencies(具有原型bean依赖关系的ingleton bean)
When you use singleton-scoped beans with dependencies on prototype beans, be aware that dependencies are resolved at instantiation time. Thus if you dependency-inject a prototype-scoped bean into a singleton-scoped bean, a new prototype bean is instantiated and then dependency-injected into the singleton bean. The prototype instance is the sole instance that is ever supplied to the singleton-scoped bean.
- 当您使用带有原型bean依赖项的单例范围bean时,请注意依赖项是在实例化时解析的。因此,如果您依赖地将一个原型作用域的bean注入到一个单例作用域的bean中,那么一个新的原型bean将被实例化,然后依赖地注入到单例bean中。原型实例是提供给单例作用域bean的唯一实例。
However, suppose you want the singleton-scoped bean to acquire a new instance of the prototype-scoped bean repeatedly at runtime. You cannot dependency-inject a prototype-scoped bean into your singleton bean, because that injection occurs only once, when the Spring container is instantiating the singleton bean and resolving and injecting its dependencies. If you need a new instance of a prototype bean at runtime more than once, see Method injection
- 但是,假设您希望单例作用域bean在运行时重复获得原型作用域bean的新实例。您不能依赖地将原型作用域的bean注入到单例bean中,因为该注入只会在Spring容器实例化单例bean并解析和注入其依赖时发生一次。如果您不止一次地需要原型bean在运行时的新实例,请参阅方法注入
1.5.4. Request, session, application, and WebSocket scopes(请求、会话、应用程序和WebSocket作用域)
The request
, session
, application
, and websocket
scopes are only available if you use a web-aware Spring ApplicationContext
implementation (such as XmlWebApplicationContext
). If you use these scopes with regular Spring IoC containers such as the ClassPathXmlApplicationContext
, an IllegalStateException
will be thrown complaining about an unknown bean scope.
- 请求、会话、应用程序和websocket作用域只有在使用支持web的Spring ApplicationContext实现(如XmlWebApplicationContext)时才可用。如果将这些作用域与常规的Spring IoC容器(如ClassPathXmlApplicationContext)一起使用,就会抛出一个IllegalStateException,抱怨未知的bean作用域。
Initial web configuration(最初的网络配置)
To support the scoping of beans at the request
, session
, application
, and websocket
levels (web-scoped beans), some minor initial configuration is required before you define your beans. (This initial setup is not required for the standard scopes, singleton
and prototype
.)
- 为了在请求、会话、应用程序和websocket级别(web作用域的bean)上支持bean的作用域,在定义bean之前需要进行一些小的初始配置。(标准范围、单例和原型不需要这种初始设置。)
How you accomplish this initial setup depends on your particular Servlet environment.
- 如何完成这个初始设置取决于特定的Servlet环境。
If you access scoped beans within Spring Web MVC, in effect, within a request that is processed by the Spring DispatcherServlet
, then no special setup is necessary: DispatcherServlet
already exposes all relevant state.
- 如果您在Spring Web MVC中访问范围限定的bean,实际上是在Spring DispatcherServlet处理的请求中访问,那么不需要特殊设置:DispatcherServlet已经公开了所有相关状态
If you use a Servlet 2.5 web container, with requests processed outside of Spring’s DispatcherServlet
(for example, when using JSF or Struts), you need to register the org.springframework.web.context.request.RequestContextListener
ServletRequestListener
. For Servlet 3.0+, this can be done programmatically via the WebApplicationInitializer
interface. Alternatively, or for older containers, add the following declaration to your web application’s web.xml
file:
- 如果您使用Servlet 2.5 web容器,并且请求是在Spring的DispatcherServlet之外处理的(例如,在使用JSF或Struts时),那么您需要注册org.springframework.web.context.request。RequestContextListener ServletRequestListener。对于Servlet 3.0+,这可以通过WebApplicationInitializer接口以编程方式完成。或者,对于较旧的容器,添加以下声明到您的web应用程序的web.xml文件:
<web-app>
...
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
...
</web-app>
Alternatively, if there are issues with your listener setup, consider using Spring’s RequestContextFilter
. The filter mapping depends on the surrounding web application configuration, so you have to change it as appropriate.
- 另外,如果侦听器设置存在问题,可以考虑使用Spring的RequestContextFilter。过滤器映射取决于周围的web应用程序配置,因此您必须适当地更改它。
<web-app>
...
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
</web-app>
DispatcherServlet
, RequestContextListener
, and RequestContextFilter
all do exactly the same thing, namely bind the HTTP request object to the Thread
that is servicing that request. This makes beans that are request- and session-scoped available further down the call chain.
- DispatcherServlet、RequestContextListener和RequestContextFilter都执行完全相同的操作,即将HTTP请求对象绑定到为该请求提供服务的线程。这使得作用域为请求和会话的bean在调用链的更深处可用。
Request scope(请求作用域)
Consider the following XML configuration for a bean definition:
- 考虑以下针对bean定义的XML配置:
<bean id="loginAction" class="com.foo.LoginAction" scope="request"/>
The Spring container creates a new instance of the LoginAction
bean by using the loginAction
bean definition for each and every HTTP request. That is, the loginAction
bean is scoped at the HTTP request level. You can change the internal state of the instance that is created as much as you want, because other instances created from the same loginAction
bean definition will not see these changes in state; they are particular to an individual request. When the request completes processing, the bean that is scoped to the request is discarded.
- Spring容器通过为每个HTTP请求使用LoginAction bean定义来创建LoginAction bean的一个新实例。也就是说,loginAction bean的作用域在HTTP请求级别。您可以随心所欲地更改已创建实例的内部状态,因为从相同loginAction bean定义创建的其他实例将不会看到这些状态变化;它们是针对个别请求的。当请求完成处理时,作用域为该请求的bean将被丢弃。
When using annotation-driven components or Java Config, the @RequestScope
annotation can be used to assign a component to the request
scope.
- 当使用注释驱动的组件或Java配置时,可以使用@RequestScope注释将组件分配到请求范围。
@RequestScope
@Component
public class LoginAction {
// ...
}
Session scope
Consider the following XML configuration for a bean definition:
- 考虑以下针对bean定义的XML配置:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
The Spring container creates a new instance of the UserPreferences
bean by using the userPreferences
bean definition for the lifetime of a single HTTP Session
. In other words, the userPreferences
bean is effectively scoped at the HTTP Session
level. As with request-scoped
beans, you can change the internal state of the instance that is created as much as you want, knowing that other HTTP Session
instances that are also using instances created from the same userPreferences
bean definition do not see these changes in state, because they are particular to an individual HTTP Session
. When the HTTP Session
is eventually discarded, the bean that is scoped to that particular HTTP Session
is also discarded.
- Spring容器通过使用单个HTTP会话生存期的UserPreferences bean定义来创建一个UserPreferences bean的新实例。换句话说,userPreferences bean有效地限定了HTTP会话级别的范围。与请求范围内bean一样,你可以改变内部状态的实例创建尽可能多的你想要的,知道其他HTTP会话实例也使用相同的实例创建userPreferences bean定义看不到这些变化状态,因为他们是特定于一个单独的HTTP会话。当HTTP会话最终被丢弃时,作用域为该特定HTTP会话的bean也将被丢弃。
When using annotation-driven components or Java Config, the @SessionScope
annotation can be used to assign a component to the session
scope.
- 当使用注释驱动的组件或Java配置时,可以使用@SessionScope注释将组件分配给会话范围。
@SessionScope
@Component
public class UserPreferences {
// ...
}
Application scope
Consider the following XML configuration for a bean definition:
- 考虑以下针对bean定义的XML配置:
<bean id="appPreferences" class="com.foo.AppPreferences" scope="application"/>
The Spring container creates a new instance of the AppPreferences
bean by using the appPreferences
bean definition once for the entire web application. That is, the appPreferences
bean is scoped at the ServletContext
level, stored as a regular ServletContext
attribute. This is somewhat similar to a Spring singleton bean but differs in two important ways: It is a singleton per ServletContext
, not per Spring 'ApplicationContext' (for which there may be several in any given web application), and it is actually exposed and therefore visible as a ServletContext
attribute.
- Spring容器为整个web应用程序使用一次AppPreferences bean定义,从而创建AppPreferences bean的一个新实例。也就是说,appPreferences bean的作用域在ServletContext级别,存储为一个常规的ServletContext属性。这有点类似于弹簧单例bean,但在两个重要方面不同:它是一个单例每ServletContext不是每春天ApplicationContext的(可能有几个在任何给定的web应用程序),它实际上是暴露,因此可见ServletContext属性。
When using annotation-driven components or Java Config, the @ApplicationScope
annotation can be used to assign a component to the application
scope.
- 当使用注释驱动的组件或Java配置时,可以使用@ApplicationScope注释将组件分配给应用程序范围。
@ApplicationScope
@Component
public class AppPreferences {
// ...
}
Scoped beans as dependencies(将限定范围的bean作为依赖项)
The Spring IoC container manages not only the instantiation of your objects (beans), but also the wiring up of collaborators (or dependencies). If you want to inject (for example) an HTTP request scoped bean into another bean of a longer-lived scope, you may choose to inject an AOP proxy in place of the scoped bean. That is, you need to inject a proxy object that exposes the same public interface as the scoped object but that can also retrieve the real target object from the relevant scope (such as an HTTP request) and delegate method calls onto the real object.
- Spring IoC容器不仅管理对象(bean)的实例化,而且还管理协作者(或依赖关系)的连接。例如,如果您想将一个HTTP请求作用域的bean注入(例如)到另一个存在更长的作用域的bean中,您可以选择注入一个AOP代理来代替作用域的bean。也就是说,您需要注入一个代理对象,该代理对象公开与作用域对象相同的公共接口,但也可以从相关作用域检索实际目标对象(例如HTTP请求),并将方法调用委托给实际对象。
You may also use <aop:scoped-proxy/> between beans that are scoped as singleton , with the reference then going through an intermediate proxy that is serializable and therefore able to re-obtain the target singleton bean on deserialization.When declaring <aop:scoped-proxy/> against a bean of scope prototype , every method call on the shared proxy will lead to the creation of a new target instance which the call is then being forwarded to.Also, scoped proxies are not the only way to access beans from shorter scopes in a lifecycle-safe fashion. You may also simply declare your injection point (i.e. the constructor/setter argument or autowired field) as ObjectFactory<MyTargetBean> , allowing for a getObject() call to retrieve the current instance on demand every time it is needed - without holding on to the instance or storing it separately.As an extended variant, you may declare ObjectProvider<MyTargetBean> which delivers several additional access variants, including getIfAvailable and getIfUnique .The JSR-330 variant of this is called Provider , used with a Provider<MyTargetBean> declaration and a corresponding get() call for every retrieval attempt. See here for more details on JSR-330 overall. |
|
---|---|
- 你也可以使用aop:作用域代理。在作用域为单例的bean之间进行引用,然后通过一个中间代理进行引用,该代理是可序列化的,因此能够在反序列化时重新获得目标单例bean。当宣布& lt; aop:作用域内的代理/比;对于作用域原型bean,对共享代理的每个方法调用都将创建一个新的目标实例,然后将调用转发到该目标实例。而且,作用域代理并不是以生命周期安全的方式从更短的作用域访问bean的唯一方法。你也可以简单地声明你的注射点(即构造函数/ setter的论点或autowired的字段)ObjectFactory< MyTargetBean>,允许getObject()调用来检索当前实例对需求每次需要——没有分别持有实例或存储它。作为扩展变体,您可以声明objectprovidermytargetbean>它提供了几个额外的访问变量,包括getIfAvailable和getIfUnique。它的JSR-330变种称为提供者,与提供者一起使用。声明,并对每次检索尝试进行相应的get()调用。关于JSR-330的更多详细信息请参见这里。
The configuration in the following example is only one line, but it is important to understand the "why" as well as the "how" behind it.
- 下面示例中的配置只有一行,但是理解其背后的“原因”和“方式”很重要。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- an HTTP Session-scoped bean exposed as a proxy -->
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
<!-- instructs the container to proxy the surrounding bean -->
<aop:scoped-proxy/>
</bean>
<!-- a singleton-scoped bean injected with a proxy to the above bean -->
<bean id="userService" class="com.foo.SimpleUserService">
<!-- a reference to the proxied userPreferences bean -->
<property name="userPreferences" ref="userPreferences"/>
</bean>
</beans>
To create such a proxy, you insert a child <aop:scoped-proxy/>
element into a scoped bean definition (see Choosing the type of proxy to create and XML Schema-based configuration). Why do definitions of beans scoped at the request
, session
and custom-scope levels require the <aop:scoped-proxy/>
element? Let’s examine the following singleton bean definition and contrast it with what you need to define for the aforementioned scopes (note that the following userPreferences
bean definition as it stands is incomplete).
- 要创建这样的代理,需要将子元素aop:作用域代理/插入作用域bean定义中(请参阅选择要创建的代理类型和基于XML模式的配置)。为什么在请求、会话和自定义作用域级别定义的bean需要aop:作用域代理/元素?让我们检查一下下面的单例bean定义,并将其与您需要为上述范围定义的内容进行对比(注意,下面的userPreferences bean定义是不完整的)。
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
In the preceding example, the singleton bean userManager
is injected with a reference to the HTTP Session
-scoped bean userPreferences
. The salient point here is that the userManager
bean is a singleton: it will be instantiated exactly once per container, and its dependencies (in this case only one, the userPreferences
bean) are also injected only once. This means that the userManager
bean will only operate on the exact same userPreferences
object, that is, the one that it was originally injected with.
- 在前面的示例中,单例bean userManager被注入一个对HTTP会话作用域bean用户首选项的引用。这里突出的一点是userManager bean是一个单例:它将为每个容器实例化一次,而且它的依赖项(在本例中只有一个,即userPreferences bean)也只注入一次。这意味着userManager bean将只操作完全相同的userPreferences对象,即最初注入它的那个对象。
This is not the behavior you want when injecting a shorter-lived scoped bean into a longer-lived scoped bean, for example injecting an HTTP Session
-scoped collaborating bean as a dependency into singleton bean. Rather, you need a single userManager
object, and for the lifetime of an HTTP Session
, you need a userPreferences
object that is specific to said HTTP Session
. Thus the container creates an object that exposes the exact same public interface as the UserPreferences
class (ideally an object that is a UserPreferences
instance) which can fetch the real UserPreferences
object from the scoping mechanism (HTTP request, Session
, etc.). The container injects this proxy object into the userManager
bean, which is unaware that this UserPreferences
reference is a proxy. In this example, when a UserManager
instance invokes a method on the dependency-injected UserPreferences
object, it actually is invoking a method on the proxy. The proxy then fetches the real UserPreferences
object from (in this case) the HTTP Session
, and delegates the method invocation onto the retrieved real UserPreferences
object.
- 当将较短作用域bean注入到较长作用域bean中时,这不是您想要的行为,例如将HTTP会话作用域的协作bean作为依赖项注入到单例bean中。相反,您需要一个userManager对象,并且在HTTP会话的生命周期中,您需要一个特定于所述HTTP会话的userPreferences对象。因此,容器创建一个对象,该对象公开与UserPreferences类完全相同的公共接口(理想情况下,该对象是一个UserPreferences实例),它可以从作用域机制(HTTP请求、会话等)中获取真正的UserPreferences对象。容器将这个代理对象注入到userManager bean中,该bean不知道这个UserPreferences引用是一个代理。在本例中,当UserManager实例调用依赖注入的UserPreferences对象上的方法时,它实际上是在调用代理上的方法。代理然后从(在本例中)HTTP会话中获取真实的UserPreferences对象,并将方法调用委托给检索到的真实UserPreferences对象。
Thus you need the following, correct and complete, configuration when injecting request-
and session-scoped
beans into collaborating objects:
- 因此,当将请求和会话作用域的bean注入到协作对象中时,您需要以下正确且完整的配置:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
<aop:scoped-proxy/>
</bean>
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
Choosing the type of proxy to create(选择要创建的代理类型)
By default, when the Spring container creates a proxy for a bean that is marked up with the <aop:scoped-proxy/>
element, a CGLIB-based class proxy is created.
- 默认情况下,当Spring容器为标记为aop:作用域代理/元素的bean创建代理时,将创建一个基于cglib的类代理。
CGLIB proxies only intercept public method calls! Do not call non-public methods on such a proxy; they will not be delegated to the actual scoped target object. | |
---|---|
- CGLIB代理仅拦截公共方法调用!不要在这样的代理上调用非公共方法;它们不会被委托给实际的有作用域的目标对象。
Alternatively, you can configure the Spring container to create standard JDK interface-based proxies for such scoped beans, by specifying false
for the value of the proxy-target-class
attribute of the <aop:scoped-proxy/>
element. Using JDK interface-based proxies means that you do not need additional libraries in your application classpath to effect such proxying. However, it also means that the class of the scoped bean must implement at least one interface, and that all collaborators into which the scoped bean is injected must reference the bean through one of its interfaces.
- 或者,您可以配置Spring容器,通过为aop:作用域-proxy/元素的代理-目标-类属性的值指定false,为这种作用域bean创建标准的基于JDK接口的代理。使用JDK基于接口的代理意味着您不需要在应用程序类路径中添加额外的库来实现这种代理。然而,这也意味着作用域bean的类必须实现至少一个接口,并且所有注入作用域bean的协作者必须通过它的一个接口引用该bean。
<!-- DefaultUserPreferences implements the UserPreferences interface -->
<bean id="userPreferences" class="com.foo.DefaultUserPreferences" scope="session">
<aop:scoped-proxy proxy-target-class="false"/>
</bean>
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
For more detailed information about choosing class-based or interface-based proxying, see Proxying mechanisms.
- 有关选择基于类或基于接口的代理的详细信息,请参阅代理机制。
1.5.5. Custom scopes(自定义范围)
The bean scoping mechanism is extensible; You can define your own scopes, or even redefine existing scopes, although the latter is considered bad practice and you cannot override the built-in singleton
and prototype
scopes.
- bean的作用域机制是可扩展的;您可以定义自己的作用域,或者甚至重新定义现有的作用域,尽管后者被认为是不好的做法,而且您不能覆盖内置的singleton和prototype作用域。
Creating a custom scope(创建自定义范围)
To integrate your custom scope(s) into the Spring container, you need to implement the org.springframework.beans.factory.config.Scope
interface, which is described in this section. For an idea of how to implement your own scopes, see the Scope
implementations that are supplied with the Spring Framework itself and the Scope
javadocs, which explains the methods you need to implement in more detail.
- 要将您的自定义范围集成到Spring容器中,您需要实现org.springframework.bean .factory.config。Scope接口,将在本节中描述。要了解如何实现自己的作用域,请参阅随Spring框架本身提供的作用域实现和作用域javadocs,后者更详细地解释了需要实现的方法。
The Scope
interface has four methods to get objects from the scope, remove them from the scope, and allow them to be destroyed.
- Scope接口有四个方法,用于从范围中获取对象、从范围中删除对象以及允许销毁它们。
The following method returns the object from the underlying scope. The session scope implementation, for example, returns the session-scoped bean (and if it does not exist, the method returns a new instance of the bean, after having bound it to the session for future reference).
- 下面的方法从基础范围返回对象。例如,会话作用域实现返回会话作用域bean(如果它不存在,则在将其绑定到会话以供将来引用之后,该方法返回bean的一个新实例)。
Object get(String name, ObjectFactory objectFactory)
The following method removes the object from the underlying scope. The session scope implementation for example, removes the session-scoped bean from the underlying session. The object should be returned, but you can return null if the object with the specified name is not found.
- 下面的方法将对象从基础范围中移除。例如,会话作用域实现从基础会话中删除会话作用域bean。应该返回该对象,但如果没有找到具有指定名称的对象,则可以返回null。
Object remove(String name)
The following method registers the callbacks the scope should execute when it is destroyed or when the specified object in the scope is destroyed. Refer to the javadocs or a Spring scope implementation for more information on destruction callbacks.
- 以下方法注册范围在销毁或销毁范围中的指定对象时应该执行的回调。有关销毁回调的更多信息,请参考javadocs或Spring作用域实现。
void registerDestructionCallback(String name, Runnable destructionCallback)
The following method obtains the conversation identifier for the underlying scope. This identifier is different for each scope. For a session scoped implementation, this identifier can be the session identifier.
- 下面的方法获取底层范围的对话标识符。这个标识符对于每个范围都是不同的。对于会话范围的实现,此标识符可以是会话标识符。
String getConversationId()
Using a custom scope(使用自定义范围)
After you write and test one or more custom Scope
implementations, you need to make the Spring container aware of your new scope(s). The following method is the central method to register a new Scope
with the Spring container:
- 在您编写和测试一个或多个自定义范围实现之后,您需要让Spring容器知道您的新范围。下面的方法是向Spring容器注册新范围的中心方法:
void registerScope(String scopeName, Scope scope);
This method is declared on the ConfigurableBeanFactory
interface, which is available on most of the concrete ApplicationContext
implementations that ship with Spring via the BeanFactory property.
- 此方法是在ConfigurableBeanFactory接口上声明的,该接口可用于Spring通过BeanFactory属性附带的大多数具体ApplicationContext实现。
The first argument to the registerScope(..)
method is the unique name associated with a scope; examples of such names in the Spring container itself are singleton
and prototype
. The second argument to the registerScope(..)
method is an actual instance of the custom Scope
implementation that you wish to register and use.
- registerScope(..)方法的第一个参数是与作用域关联的唯一名称;此类名称在Spring容器本身中的例子有singleton和prototype。registerScope(..)方法的第二个参数是您希望注册和使用的自定义范围实现的一个实际实例。
Suppose that you write your custom Scope
implementation, and then register it as below.
- 假设您编写了自定义范围实现,然后按如下方式注册它。
The example below uses SimpleThreadScope which is included with Spring, but not registered by default. The instructions would be the same for your own custom Scope implementations. |
|
---|---|
- 下面的示例使用了SimpleThreadScope,它包含在Spring中,但默认情况下没有注册。对于您自己的自定义范围实现,说明是相同的。
Scope threadScope = new SimpleThreadScope();
beanFactory.registerScope("thread", threadScope);
You then create bean definitions that adhere to the scoping rules of your custom Scope
:
- 然后,您创建了遵守自定义范围的范围规则的bean定义:
<bean id="..." class="..." scope="thread">
With a custom Scope
implementation, you are not limited to programmatic registration of the scope. You can also do the Scope
registration declaratively, using the CustomScopeConfigurer
class:
- 使用自定义范围实现,您不必局限于对范围的编程式注册。您还可以使用CustomScopeConfigurer类声明性地进行范围注册:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="thread">
<bean class="org.springframework.context.support.SimpleThreadScope"/>
</entry>
</map>
</property>
</bean>
<bean id="bar" class="x.y.Bar" scope="thread">
<property name="name" value="Rick"/>
<aop:scoped-proxy/>
</bean>
<bean id="foo" class="x.y.Foo">
<property name="bar" ref="bar"/>
</bean>
</beans>
When you place <aop:scoped-proxy/> in a FactoryBean implementation, it is the factory bean itself that is scoped, not the object returned from getObject() . |
|
---|---|
- 当您在FactoryBean实现中放置aop:作用域-代理/时,作用域是工厂bean本身,而不是从getObject()返回的对象。
1.6. Customizing the nature of a bean(自定义bean的性质)
1.6.1. Lifecycle callbacks(生命周期回调)
To interact with the container’s management of the bean lifecycle, you can implement the Spring InitializingBean
and DisposableBean
interfaces. The container calls afterPropertiesSet()
for the former and destroy()
for the latter to allow the bean to perform certain actions upon initialization and destruction of your beans.
- 要与容器对bean生命周期的管理交互,您可以实现Spring InitializingBean和DisposableBean接口。容器对前者调用afterPropertiesSet(),对后者调用destroy(),以允许bean在初始化和销毁bean时执行某些操作。
The JSR-250 @PostConstruct and @PreDestroy annotations are generally considered best practice for receiving lifecycle callbacks in a modern Spring application. Using these annotations means that your beans are not coupled to Spring specific interfaces. For details see @PostConstruct and @PreDestroy.If you don’t want to use the JSR-250 annotations but you are still looking to remove coupling consider the use of init-method and destroy-method object definition metadata. |
|
---|---|
- JSR-250 @PostConstruct和@PreDestroy注释通常被认为是在现代Spring应用程序中接收生命周期回调的最佳实践。使用这些注释意味着您的bean不会耦合到Spring特定的接口。详情请参阅@PostConstruct和@PreDestroy。
- 如果您不想使用JSR-250注释,但仍然希望消除耦合,那么可以考虑使用init-method和destroy-method对象定义元数据。
Internally, the Spring Framework uses BeanPostProcessor
implementations to process any callback interfaces it can find and call the appropriate methods. If you need custom features or other lifecycle behavior Spring does not offer out-of-the-box, you can implement a BeanPostProcessor
yourself. For more information, see Container Extension Points.
- 在内部,Spring框架使用BeanPostProcessor实现来处理它可以找到的任何回调接口,并调用适当的方法。如果您需要自定义特性或Spring不能提供的其他生命周期行为,那么您可以自己实现BeanPostProcessor。有关更多信息,请参见容器扩展点。
In addition to the initialization and destruction callbacks, Spring-managed objects may also implement the Lifecycle
interface so that those objects can participate in the startup and shutdown process as driven by the container’s own lifecycle.
-除了初始化和销毁回调之外,spring管理的对象还可以实现生命周期接口,以便这些对象可以参与由容器自己的生命周期驱动的启动和关闭过程。
The lifecycle callback interfaces are described in this section.
- 本节将描述生命周期回调接口。
Initialization callbacks(初始化回调。)
The org.springframework.beans.factory.InitializingBean
interface allows a bean to perform initialization work after all necessary properties on the bean have been set by the container. The InitializingBean
interface specifies a single method:
- org.springframework.beans.factory。InitializingBean接口允许一个bean在容器设置了该bean上所有必要的属性之后执行初始化工作。InitializingBean接口指定了一个方法:
void afterPropertiesSet() throws Exception;
It is recommended that you do not use the InitializingBean
interface because it unnecessarily couples the code to Spring. Alternatively, use the @PostConstruct
annotation or specify a POJO initialization method. In the case of XML-based configuration metadata, you use the init-method
attribute to specify the name of the method that has a void no-argument signature. With Java config, you use the initMethod
attribute of @Bean
, see Receiving lifecycle callbacks. For example, the following:
- 建议您不要使用InitializingBean接口,因为它不必要地将代码与Spring结合在一起。或者,使用@PostConstruct注释或指定POJO初始化方法。对于基于xml的配置元数据,可以使用init-method属性来指定具有空无参数签名的方法的名称。使用Java配置,您可以使用@Bean的initMethod属性,请参阅接收生命周期回调。例如,以下内容
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {
public void init() {
// do some initialization work
}
}
…is exactly the same as…(和…完全一样。)
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements InitializingBean {
public void afterPropertiesSet() {
// do some initialization work
}
}
but does not couple the code to Spring.(但是没有将代码与Spring耦合。)
Destruction callbacks(破坏回调)
Implementing the org.springframework.beans.factory.DisposableBean
interface allows a bean to get a callback when the container containing it is destroyed. The DisposableBean
interface specifies a single method:
- 实施org.springframework.beans.factory。DisposableBean接口允许bean在包含它的容器被销毁时获得回调。DisposableBean接口指定了一个方法
void destroy() throws Exception;
It is recommended that you do not use the DisposableBean
callback interface because it unnecessarily couples the code to Spring. Alternatively, use the @PreDestroy
annotation or specify a generic method that is supported by bean definitions. With XML-based configuration metadata, you use the destroy-method
attribute on the <bean/>
. With Java config, you use the destroyMethod
attribute of @Bean
, see Receiving lifecycle callbacks. For example, the following definition:
- 建议您不要使用一次性bean回调接口,因为它不必要地将代码与Spring结合在一起。或者,使用@PreDestroy注释或指定bean定义支持的泛型方法。对于基于xml的配置元数据,可以使用
上的destroy-method属性。使用Java配置,您可以使用@Bean的destroyMethod属性,参见接收生命周期回调。例如,以下定义:
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
public class ExampleBean {
public void cleanup() {
// do some destruction work (like releasing pooled connections)
}
}
is exactly the same as:(就等于:)
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements DisposableBean {
public void destroy() {
// do some destruction work (like releasing pooled connections)
}
}
but does not couple the code to Spring.(但是没有将代码与Spring耦合。)
The destroy-method attribute of a <bean> element can be assigned a special (inferred) value which instructs Spring to automatically detect a public close or shutdown method on the specific bean class (any class that implements java.lang.AutoCloseable or java.io.Closeable would therefore match). This special (inferred) value can also be set on the default-destroy-method attribute of a <beans> element to apply this behavior to an entire set of beans (see Default initialization and destroy methods). Note that this is the default behavior with Java config. |
|
---|---|
元素的destroy-method属性可以被分配一个特殊的(推断的)值,该值指示Spring自动检测特定bean类(任何实现java.lang的类)上的公共关闭或关闭方法。AutoCloseable或io。Closeable将因此匹配)。这个特殊的(推断的)值也可以在 元素的Default -destroy-method属性上设置,以将此行为应用于整个bean集合(参见默认初始化和destroy方法)。注意,这是Java配置的默认行为。
Default initialization and destroy methods(默认的初始化和销毁方法)
When you write initialization and destroy method callbacks that do not use the Spring-specific InitializingBean
and DisposableBean
callback interfaces, you typically write methods with names such as init()
, initialize()
, dispose()
, and so on. Ideally, the names of such lifecycle callback methods are standardized across a project so that all developers use the same method names and ensure consistency.
- 当您编写初始化和销毁不使用特定于spring的InitializingBean和DisposableBean回调接口的方法回调时,您通常编写具有init()、initialize()、dispose()等名称的方法。理想情况下,这种生命周期回调方法的名称在整个项目中标准化,以便所有开发人员使用相同的方法名称并确保一致性。
You can configure the Spring container to look
for named initialization and destroy callback method names on every bean. This means that you, as an application developer, can write your application classes and use an initialization callback called init()
, without having to configure an init-method="init"
attribute with each bean definition. The Spring IoC container calls that method when the bean is created (and in accordance with the standard lifecycle callback contract described previously). This feature also enforces a consistent naming convention for initialization and destroy method callbacks.
- 您可以配置Spring容器来查找已命名的初始化,并销毁每个bean上的回调方法名称。这意味着,作为应用程序开发人员,您可以编写应用程序类并使用名为init()的初始化回调,而不必为每个bean定义配置init-method="init"属性。Spring IoC容器在创建bean时调用该方法(并且与前面描述的标准生命周期回调契约一致)。该特性还强制对初始化和销毁方法回调执行一致的命名约定。
Suppose that your initialization callback methods are named init()
and destroy callback methods are named destroy()
. Your class will resemble the class in the following example.
- 假设您的初始化回调方法名为init(),而销毁回调方法名为destroy()。您的类将类似于下面示例中的类。
public class DefaultBlogService implements BlogService {
private BlogDao blogDao;
public void setBlogDao(BlogDao blogDao) {
this.blogDao = blogDao;
}
// this is (unsurprisingly) the initialization callback method
public void init() {
if (this.blogDao == null) {
throw new IllegalStateException("The [blogDao] property must be set.");
}
}
}
<beans default-init-method="init">
<bean id="blogService" class="com.foo.DefaultBlogService">
<property name="blogDao" ref="blogDao" />
</bean>
</beans>
The presence of the default-init-method
attribute on the top-level <beans/>
element attribute causes the Spring IoC container to recognize a method called init
on beans as the initialization method callback. When a bean is created and assembled, if the bean class has such a method, it is invoked at the appropriate time.
- 在顶级
元素属性中出现的default-init-method属性会导致Spring IoC容器将bean上的init方法识别为初始化方法回调。在创建和组装bean时,如果bean类有这样的方法,则会在适当的时候调用它。
You configure destroy method callbacks similarly (in XML, that is) by using the default-destroy-method
attribute on the top-level <beans/>
element.
- 您可以通过使用顶级
元素上的default-destroy-method属性来配置销毁方法回调(即在XML中)。
Where existing bean classes already have callback methods that are named at variance with the convention, you can override the default by specifying (in XML, that is) the method name using the init-method
and destroy-method
attributes of the <bean/>
itself.
- 如果现有的bean类已经有了根据约定命名的回调方法,那么您可以通过使用
本身的init-method和destroy-method属性指定(在XML中)方法名来覆盖默认值。
The Spring container guarantees that a configured initialization callback is called immediately after a bean is supplied with all dependencies. Thus the initialization callback is called on the raw bean reference, which means that AOP interceptors and so forth are not yet applied to the bean. A target bean is fully created first, then an AOP proxy (for example) with its interceptor chain is applied. If the target bean and the proxy are defined separately, your code can even interact with the raw target bean, bypassing the proxy. Hence, it would be inconsistent to apply the interceptors to the init method, because doing so would couple the lifecycle of the target bean with its proxy/interceptors and leave strange semantics when your code interacts directly to the raw target bean.
- Spring容器保证在为bean提供所有依赖项后立即调用已配置的初始化回调。因此在原始bean引用上调用初始化回调,这意味着AOP拦截器等还没有应用到bean上。首先完全创建一个目标bean,然后应用一个带有拦截器链的AOP代理(例如)。如果目标bean和代理是分开定义的,那么您的代码甚至可以绕过代理与原始目标bean交互。因此,将拦截器应用于
Combining lifecycle mechanisms(结合生命周期机制)
As of Spring 2.5, you have three options for controlling bean lifecycle behavior: the InitializingBean
and DisposableBean
callback interfaces; custom init()
and destroy()
methods; and the @PostConstruct
and @PreDestroy
annotations. You can combine these mechanisms to control a given bean.
- 在spring2.5中,控制bean生命周期行为有三种选择:InitializingBean和一次性bean回调接口;自定义init()和destroy()方法;@PostConstruct和@PreDestroy注释。您可以组合这些机制来控制给定的bean。
If multiple lifecycle mechanisms are configured for a bean, and each mechanism is configured with a different method name, then each configured method is executed in the order listed below. However, if the same method name is configured - for example, init() for an initialization method - for more than one of these lifecycle mechanisms, that method is executed once, as explained in the preceding section. |
|
---|---|
- 如果为一个bean配置了多个生命周期机制,并且每个机制都配置了不同的方法名,那么每个配置的方法都按照下面列出的顺序执行。但是,如果为多个生命周期机制配置了相同的方法名—例如,初始化方法的init()—那么该方法将执行一次,如上一节所述。
Multiple lifecycle mechanisms configured for the same bean, with different initialization methods, are called as follows:
-
- 使用不同的初始化方法,为同一个bean配置的多个生命周期机制如下所示:
-
Methods annotated with
@PostConstruct
-
afterPropertiesSet()
as defined by theInitializingBean
callback interface -
A custom configured
init()
method
Destroy methods are called in the same order:
-
Methods annotated with
@PreDestroy
-
destroy()
as defined by theDisposableBean
callback interface -
A custom configured
destroy()
method-
用@PostConstruct注释的方法
InitializingBean回调接口定义的afterPropertiesSet()
自定义配置的init()方法
销毁方法的调用顺序相同:
用@PreDestroy注释的方法
销毁(),由DisposableBean回调接口定义
自定义配置的destroy()方法
-
Startup and shutdown callbacks(启动和关闭回调)
The Lifecycle
interface defines the essential methods for any object that has its own lifecycle requirements (e.g. starts and stops some background process):
- 生命周期接口为任何有生命周期需求的对象(例如启动和停止某些后台进程)定义了基本方法:
public interface Lifecycle {
void start();
void stop();
boolean isRunning();
}
Any Spring-managed object may implement that interface. Then, when the ApplicationContext
itself receives start and stop signals, e.g. for a stop/restart scenario at runtime, it will cascade those calls to all Lifecycle
implementations defined within that context. It does this by delegating to a LifecycleProcessor
:
- 任何spring管理的对象都可以实现该接口。然后,当ApplicationContext本身接收到启动和停止信号时,例如在运行时的停止/重启场景,它将把这些调用串联到在该上下文中定义的所有生命周期实现。它通过委托给生命周期处理器来实现这一点:
public interface LifecycleProcessor extends Lifecycle {
void onRefresh();
void onClose();
}
Notice that the LifecycleProcessor
is itself an extension of the Lifecycle
interface. It also adds two other methods for reacting to the context being refreshed and closed.
- 注意,LifecycleProcessor本身就是生命周期接口的扩展。它还添加了另外两个方法,用于对刷新和关闭上下文做出反应。
Note that the regular org.springframework.context.Lifecycle interface is just a plain contract for explicit start/stop notifications and does NOT imply auto-startup at context refresh time. Consider implementing org.springframework.context.SmartLifecycle instead for fine-grained control over auto-startup of a specific bean (including startup phases). Also, please note that stop notifications are not guaranteed to come before destruction: On regular shutdown, all Lifecycle beans will first receive a stop notification before the general destruction callbacks are being propagated; however, on hot refresh during a context’s lifetime or on aborted refresh attempts, only destroy methods will be called. |
|
---|---|
- 请注意常规的org.springframework.context。生命周期接口只是一个显式启动/停止通知的普通契约,并不意味着在上下文刷新时自动启动。考虑实施org.springframework.context。SmartLifecycle用于对特定bean的自动启动进行细粒度控制(包括启动阶段)。另外,请注意,停止通知不能保证在销毁之前发出:在常规关闭时,所有生命周期bean将首先在传播常规销毁回调之前收到停止通知;然而,在热
The order of startup and shutdown invocations can be important. If a "depends-on" relationship exists between any two objects, the dependent side will start after its dependency, and it will stop before its dependency. However, at times the direct dependencies are unknown. You may only know that objects of a certain type should start prior to objects of another type. In those cases, the SmartLifecycle
interface defines another option, namely the getPhase()
method as defined on its super-interface, Phased
.
- 启动和关闭调用的顺序可能很重要。如果任何两个对象之间存在“依赖-依赖”关系,依赖端将在依赖之后开始,并在依赖之前停止。然而,有时直接的依赖关系是未知的。您可能只知道某种类型的对象应该先于另一种类型的对象启动。在这些情况下,SmartLifecycle接口定义了另一个选项,即在其超接口phase上定义的getPhase()方法。
public interface Phased {
int getPhase();
}
public interface SmartLifecycle extends Lifecycle, Phased {
boolean isAutoStartup();
void stop(Runnable callback);
}
When starting, the objects with the lowest phase start first, and when stopping, the reverse order is followed. Therefore, an object that implements SmartLifecycle
and whose getPhase()
method returns Integer.MIN_VALUE
would be among the first to start and the last to stop. At the other end of the spectrum, a phase value of Integer.MAX_VALUE
would indicate that the object should be started last and stopped first (likely because it depends on other processes to be running). When considering the phase value, it’s also important to know that the default phase for any "normal" Lifecycle
object that does not implement SmartLifecycle
would be 0. Therefore, any negative phase value would indicate that an object should start before those standard components (and stop after them), and vice versa for any positive phase value.
- 启动时,相位最低的对象先启动,停止时,顺序相反。因此,实现SmartLifecycle并其getPhase()方法返回整数的对象。MIN_VALUE将首先开始,最后停止。在频谱的另一端,一个整数相位值。MAX_VALUE表示应该最后启动并首先停止该对象(可能是因为它依赖于正在运行的其他进程)。在考虑阶段值时,同样重要的是要知道任何“正常”生命周期对象的默认阶段是
As you can see the stop method defined by SmartLifecycle
accepts a callback. Any implementation must invoke that callback’s run()
method after that implementation’s shutdown process is complete. That enables asynchronous shutdown where necessary since the default implementation of the LifecycleProcessor
interface, DefaultLifecycleProcessor
, will wait up to its timeout value for the group of objects within each phase to invoke that callback. The default per-phase timeout is 30 seconds. You can override the default lifecycle processor instance by defining a bean named "lifecycleProcessor" within the context. If you only want to modify the timeout, then defining the following would be sufficient:
- 你可以看到SmartLifecycle定义的stop方法接受一个回调。任何实现都必须在该实现的关闭过程完成后调用该回调的run()方法。这允许在必要时异步关闭,因为LifecycleProcessor接口的默认实现DefaultLifecycleProcessor将等待每个阶段中的对象组的超时值来调用该回调。每个相位的默认超时时间为30秒。您可以通过在内部定义一个名为“lifecycleProcessor”的bean来覆盖默认的生命周期处理器实例
<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
<!-- timeout value in milliseconds -->
<property name="timeoutPerShutdownPhase" value="10000"/>
</bean>
As mentioned, the LifecycleProcessor
interface defines callback methods for the refreshing and closing of the context as well. The latter will simply drive the shutdown process as if stop()
had been called explicitly, but it will happen when the context is closing. The 'refresh' callback on the other hand enables another feature of SmartLifecycle
beans. When the context is refreshed (after all objects have been instantiated and initialized), that callback will be invoked, and at that point the default lifecycle processor will check the boolean value returned by each SmartLifecycle
object’s isAutoStartup()
method. If "true", then that object will be started at that point rather than waiting for an explicit invocation of the context’s or its own start()
method (unlike the context refresh, the context start does not happen automatically for a standard context implementation). The "phase" value as well as any "depends-on" relationships will determine the startup order in the same way as described above.
- 如前所述,LifecycleProcessor接口还定义了刷新和关闭上下文的回调方法。后者只会像显式调用stop()一样驱动关闭进程,但是它会在上下文关闭时发生。另一方面,“刷新”回调启用了SmartLifecycle bean的另一个特性。当上下文被刷新时(在所有对象被实例化和初始化之后),那个回调将被调用,在这一点上,默认生命周期处理器将检查每个SmartLifecycle对象的isA返回的布尔值
Shutting down the Spring IoC container gracefully in non-web applications(在非web应用程序中优雅地关闭Spring IoC容器)
This section applies only to non-web applications. Spring’s web-based ApplicationContext implementations already have code in place to shut down the Spring IoC container gracefully when the relevant web application is shut down. |
|
---|---|
- 本节仅适用于非web应用程序。Spring的基于web的ApplicationContext实现已经准备好了在相关web应用程序关闭时优雅地关闭Spring IoC容器的代码。
If you are using Spring’s IoC container in a non-web application environment; for example, in a rich client desktop environment; you register a shutdown hook with the JVM. Doing so ensures a graceful shutdown and calls the relevant destroy methods on your singleton beans so that all resources are released. Of course, you must still configure and implement these destroy callbacks correctly.
- 如果您在非web应用程序环境中使用Spring的IoC容器;例如,在富客户端桌面环境中;您在JVM上注册了一个关机钩子。这样做可以确保优雅地关闭,并调用单例bean上的相关销毁方法,从而释放所有资源。当然,您仍然必须正确配置和实现这些销毁回调。
To register a shutdown hook, you call the registerShutdownHook()
method that is declared on the ConfigurableApplicationContext
interface:
- 要注册一个关机钩子,你需要调用registerShutdownHook()方法,该方法在ConfigurableApplicationContext接口上声明:
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class Boot {
public static void main(final String[] args) throws Exception {
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
// add a shutdown hook for the above context...
ctx.registerShutdownHook();
// app runs here...
// main method exits, hook is called prior to the app shutting down...
}
}
1.6.2. ApplicationContextAware and BeanNameAware
When an ApplicationContext
creates an object instance that implements the org.springframework.context.ApplicationContextAware
interface, the instance is provided with a reference to that ApplicationContext
.
- 当ApplicationContext创建一个实现org.springframework.context的对象实例时。applicationcontexts taware接口,该实例通过对ApplicationContext的引用提供。
public interface ApplicationContextAware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
Thus beans can manipulate programmatically the ApplicationContext
that created them, through the ApplicationContext
interface, or by casting the reference to a known subclass of this interface, such as ConfigurableApplicationContext
, which exposes additional functionality. One use would be the programmatic retrieval of other beans. Sometimes this capability is useful; however, in general you should avoid it, because it couples the code to Spring and does not follow the Inversion of Control style, where collaborators are provided to beans as properties. Other methods of the ApplicationContext
provide access to file resources, publishing application events, and accessing a MessageSource
. These additional features are described in Additional capabilities of the ApplicationContext
- 因此,bean可以通过ApplicationContext接口以编程方式操作创建它们的ApplicationContext,或者通过强制转换对该接口已知子类的引用,比如ConfigurableApplicationContext,它公开了其他功能。一种用途是对其他bean进行编程检索。有时这种能力是有用的;但是,通常应该避免使用它,因为它将代码与Spring结合在一起,并且不遵循控制反转风格,在这种风格中协作者作为属性提供给bean。ApplicationContext p的其他方法
As of Spring 2.5, autowiring is another alternative to obtain reference to the ApplicationContext
. The "traditional" constructor
and byType
autowiring modes (as described in Autowiring collaborators) can provide a dependency of type ApplicationContext
for a constructor argument or setter method parameter, respectively. For more flexibility, including the ability to autowire fields and multiple parameter methods, use the new annotation-based autowiring features. If you do, the ApplicationContext
is autowired into a field, constructor argument, or method parameter that is expecting the ApplicationContext
type if the field, constructor, or method in question carries the @Autowired
annotation. For more information, see @Autowired.
- 在spring2.5中,自动装配是获得对ApplicationContext引用的另一种选择。“传统的”构造函数和byType自动装配模式(如在自动装配协作器中描述的)可以分别为构造函数参数或setter方法参数提供类型ApplicationContext的依赖关系。为了获得更大的灵活性,包括自动装配字段和多个参数方法的能力,可以使用新的基于注解的自动装配特性。如果你这样做了,ApplicationContext就会自动生成一个字段、构造函数参数或需要应用程序的方法参数
When an ApplicationContext
creates a class that implements the org.springframework.beans.factory.BeanNameAware
interface, the class is provided with a reference to the name defined in its associated object definition.
- 当ApplicationContext创建一个实现org.springframework.beans.factory的类时。BeanNameAware接口,为类提供对其关联对象定义中定义的名称的引用。
public interface BeanNameAware {
void setBeanName(String name) throws BeansException;
}
The callback is invoked after population of normal bean properties but before an initialization callback such as InitializingBean
afterPropertiesSet or a custom init-method.
- 在填充普通bean属性之后,在初始化回调(如InitializingBean afterPropertiesSet或自定义初始化方法)之前调用回调。
1.6.3. Other Aware interfaces(其他意识到接口)
Besides ApplicationContextAware
and BeanNameAware
discussed above, Spring offers a range of Aware
interfaces that allow beans to indicate to the container that they require a certain infrastructure dependency. The most important Aware
interfaces are summarized below - as a general rule, the name is a good indication of the dependency type:
- 除了上面讨论的applicationcontext taware和BeanNameAware之外,Spring还提供了一系列可感知的接口,允许bean向容器表明它们需要某种基础设施依赖关系。下面总结了最重要的感知接口——作为一个通用规则,接口的名称很好地说明了依赖类型:
Name | Injected Dependency(依赖注入) | Explained in…(阐述) |
---|---|---|
ApplicationContextAware (回调接口) |
Declaring ApplicationContext |
ApplicationContextAware and BeanNameAware |
ApplicationEventPublisherAware |
Event publisher of the enclosing ApplicationContext |
Additional capabilities of the ApplicationContext |
BeanClassLoaderAware |
Class loader used to load the bean classes. | Instantiating beans |
BeanFactoryAware |
Declaring BeanFactory |
ApplicationContextAware and BeanNameAware |
BeanNameAware |
Name of the declaring bean | ApplicationContextAware and BeanNameAware |
BootstrapContextAware |
Resource adapter BootstrapContext the container runs in. Typically available only in JCA aware ApplicationContext s |
JCA CCI |
LoadTimeWeaverAware |
Defined weaver for processing class definition at load time | Load-time weaving with AspectJ in the Spring Framework |
MessageSourceAware |
Configured strategy for resolving messages (with support for parametrization and internationalization) | Additional capabilities of the ApplicationContext |
NotificationPublisherAware |
Spring JMX notification publisher | Notifications |
ResourceLoaderAware |
Configured loader for low-level access to resources | Resources |
ServletConfigAware |
Current ServletConfig the container runs in. Valid only in a web-aware Spring ApplicationContext |
Spring MVC |
ServletContextAware |
Current ServletContext the container runs in. Valid only in a web-aware Spring ApplicationContext |
Spring MVC |
Note again that usage of these interfaces ties your code to the Spring API and does not follow the Inversion of Control style. As such, they are recommended for infrastructure beans that require programmatic access to the container.
- 请再次注意,使用这些接口将您的代码绑定到Spring API,并且不遵循控制反转样式。因此,建议将它们用于需要对容器进行编程访问的基础设施bean。
1.7. Bean definition inheritance(Bean定义继承)
A bean definition can contain a lot of configuration information, including constructor arguments, property values, and container-specific information such as initialization method, static factory method name, and so on. A child bean definition inherits configuration data from a parent definition. The child definition can override some values, or add others, as needed. Using parent and child bean definitions can save a lot of typing. Effectively, this is a form of templating.
- bean定义可以包含许多配置信息,包括构造函数参数、属性值和特定于容器的信息,如初始化方法、静态工厂方法名等。子bean定义从父bean定义继承配置数据。子定义可以根据需要覆盖某些值,或者添加其他值。使用父bean和子bean定义可以节省大量输入。实际上,这是一种模板形式。
If you work with an ApplicationContext
interface programmatically, child bean definitions are represented by the ChildBeanDefinition
class. Most users do not work with them on this level, instead configuring bean definitions declaratively in something like the ClassPathXmlApplicationContext
. When you use XML-based configuration metadata, you indicate a child bean definition by using the parent
attribute, specifying the parent bean as the value of this attribute.
- 如果您以编程方式使用ApplicationContext接口,则子bean定义由ChildBeanDefinition类表示。大多数用户不在这个级别上使用它们,而是在类似ClassPathXmlApplicationContext的东西中声明性地配置bean定义。当您使用基于xml的配置元数据时,您可以通过使用父属性指定子bean定义,并将父bean指定为该属性的值。
<bean id="inheritedTestBean" abstract="true"
class="org.springframework.beans.TestBean">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
<bean id="inheritsWithDifferentClass"
class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBean" init-method="initialize">
<property name="name" value="override"/>
<!-- the age property value of 1 will be inherited from parent -->
</bean>
A child bean definition uses the bean class from the parent definition if none is specified, but can also override it. In the latter case, the child bean class must be compatible with the parent, that is, it must accept the parent’s property values.
- 如果没有指定,子bean定义使用父定义中的bean类,但是也可以覆盖它。在后一种情况下,子bean类必须与父bean兼容,也就是说,它必须接受父bean的属性值。
A child bean definition inherits scope, constructor argument values, property values, and method overrides from the parent, with the option to add new values. Any scope, initialization method, destroy method, and/or static
factory method settings that you specify will override the corresponding parent settings.
- 子bean定义从父bean继承范围、构造函数参数值、属性值和方法覆盖,并提供添加新值的选项。您指定的任何范围、初始化方法、销毁方法和/或静态工厂方法设置都将覆盖相应的父设置。
The remaining settings are always taken from the child definition: depends on, autowire mode, dependency check, singleton, lazy init.
- 其余的设置总是取自子定义:依赖、自动装配模式、依赖检查、单例、延迟初始化。
The preceding example explicitly marks the parent bean definition as abstract by using the abstract
attribute. If the parent definition does not specify a class, explicitly marking the parent bean definition as abstract
is required, as follows:
- 前面的示例通过使用抽象属性显式地将父bean定义标记为抽象。如果父定义没有指定类,则需要显式地将父bean定义标记为抽象,如下所示:
<bean id="inheritedTestBeanWithoutClass" abstract="true">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
<bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBeanWithoutClass" init-method="initialize">
<property name="name" value="override"/>
<!-- age will inherit the value of 1 from the parent bean definition-->
</bean>
The parent bean cannot be instantiated on its own because it is incomplete, and it is also explicitly marked as abstract
. When a definition is abstract
like this, it is usable only as a pure template bean definition that serves as a parent definition for child definitions. Trying to use such an abstract
parent bean on its own, by referring to it as a ref property of another bean or doing an explicit getBean()
call with the parent bean id, returns an error. Similarly, the container’s internal preInstantiateSingletons()
method ignores bean definitions that are defined as abstract.
- 父bean不能自己实例化,因为它不完整,而且它还显式地标记为抽象。当定义是这样的抽象时,它只能作为纯模板bean定义使用,作为子定义的父定义。试图单独使用这样一个抽象的父bean,通过将其作为另一个bean的ref属性引用,或者使用父bean id执行显式的getBean()调用,将会返回一个错误。类似地,容器的内部预实例化esingletons()方法忽略被定义为抽象的bean定义
ApplicationContext pre-instantiates all singletons by default. Therefore, it is important (at least for singleton beans) that if you have a (parent) bean definition which you intend to use only as a template, and this definition specifies a class, you must make sure to set the abstract attribute to true, otherwise the application context will actually (attempt to) pre-instantiate the abstract bean. |
|
---|---|
- 默认情况下,ApplicationContext预实例化所有单例。因此,它是重要的(至少对单例bean),如果你有一个(父)bean定义你只打算使用作为模板,这个定义指定了一个类,您必须确保设置抽象属性为true,否则应用程序上下文会(试图)pre-instantiate抽象的bean。
1.8. Container Extension Points(容器扩展点)
Typically, an application developer does not need to subclass ApplicationContext
implementation classes. Instead, the Spring IoC container can be extended by plugging in implementations of special integration interfaces. The next few sections describe these integration interfaces.
- 通常,应用程序开发人员不需要子类化ApplicationContext实现类。相反,可以通过插入特殊集成接口的实现来扩展Spring IoC容器。接下来的几节将描述这些集成接口。
1.8.1. Customizing beans using a BeanPostProcessor(使用BeanPostProcessor定制bean)
The BeanPostProcessor
interface defines callback methods that you can implement to provide your own (or override the container’s default) instantiation logic, dependency-resolution logic, and so forth. If you want to implement some custom logic after the Spring container finishes instantiating, configuring, and initializing a bean, you can plug in one or more BeanPostProcessor
implementations.
- BeanPostProcessor接口定义了回调方法,您可以实现这些方法来提供您自己的(或覆盖容器的默认值)实例化逻辑、依赖解析逻辑等等。如果您想在Spring容器完成实例化、配置和初始化bean之后实现一些自定义逻辑,您可以插入一个或多个BeanPostProcessor实现。
You can configure multiple BeanPostProcessor
instances, and you can control the order in which these BeanPostProcessor
s execute by setting the order
property. You can set this property only if the BeanPostProcessor
implements the Ordered
interface; if you write your own BeanPostProcessor
you should consider implementing the Ordered
interface too. For further details, consult the javadocs of the BeanPostProcessor
and Ordered
interfaces. See also the note below on programmatic registration of BeanPostProcessor
s.
- 您可以配置多个BeanPostProcessor实例,并且可以通过设置order属性来控制这些BeanPostProcessor的执行顺序。只有当BeanPostProcessor实现了Ordered接口时,您才能设置此属性;如果您编写自己的BeanPostProcessor,您也应该考虑实现Ordered接口。要了解更多细节,请咨询BeanPostProcessor和有序接口的javadocs。请参阅下面关于beanpostprocessor编程注册的说明。
BeanPostProcessor s operate on bean (or object) instances; that is to say, the Spring IoC container instantiates a bean instance and then BeanPostProcessor s do their work.BeanPostProcessor s are scoped per-container. This is only relevant if you are using container hierarchies. If you define a BeanPostProcessor in one container, it will only post-process the beans in that container. In other words, beans that are defined in one container are not post-processed by a BeanPostProcessor defined in another container, even if both containers are part of the same hierarchy.To change the actual bean definition (i.e., the blueprint that defines the bean), you instead need to use a BeanFactoryPostProcessor as described in Customizing configuration metadata with a BeanFactoryPostProcessor. |
|
---|---|
- beanpostprocessor对bean(或对象)实例进行操作;也就是说,Spring IoC容器实例化一个bean实例,然后beanpostprocessor执行它们的工作。beanpostprocessor的作用域为每个容器。这只有在使用容器层次结构时才有用。如果在一个容器中定义了BeanPostProcessor,那么它将只对该容器中的bean进行后处理。换句话说,在一个容器中定义的bean不会被另一个容器中定义的BeanPostProcessor进行后处理,即使这两个容器属于同一层次结构。要改变实际的
The org.springframework.beans.factory.config.BeanPostProcessor
interface consists of exactly two callback methods. When such a class is registered as a post-processor with the container, for each bean instance that is created by the container, the post-processor gets a callback from the container both before container initialization methods (such as InitializingBean’s afterPropertiesSet() and any declared init method) are called as well as after any bean initialization callbacks. The post-processor can take any action with the bean instance, including ignoring the callback completely. A bean post-processor typically checks for callback interfaces or may wrap a bean with a proxy. Some Spring AOP infrastructure classes are implemented as bean post-processors in order to provide proxy-wrapping logic.
- org.springframework.beans.factory.config。BeanPostProcessor接口恰好由两个回调方法组成。当这样一个类注册为后处理器的容器,每个容器创建bean实例,后处理器从容器之前得到一个回调容器初始化方法(如InitializingBean年代afterPropertiesSet()和任何宣布init方法)被称为以及任何bean初始化后回调。后处理器可以对bean实例采取任何操作,包括完全忽略回调。bean后处理器通常检查回调接口,或者使用代理包装bean。为了提供代理包装逻辑,一些Spring AOP基础设施类被实现为bean后处理器。
An ApplicationContext
automatically detects any beans that are defined in the configuration metadata which implement the BeanPostProcessor
interface. The ApplicationContext
registers these beans as post-processors so that they can be called later upon bean creation. Bean post-processors can be deployed in the container just like any other beans.
- ApplicationContext自动检测在实现BeanPostProcessor接口的配置元数据中定义的任何bean。ApplicationContext将这些bean注册为后处理器,以便在稍后创建bean时调用它们。Bean后处理器可以像其他Bean一样部署在容器中。
Note that when declaring a BeanPostProcessor
using an @Bean
factory method on a configuration class, the return type of the factory method should be the implementation class itself or at least the org.springframework.beans.factory.config.BeanPostProcessor
interface, clearly indicating the post-processor nature of that bean. Otherwise, the ApplicationContext
won’t be able to autodetect it by type before fully creating it. Since a BeanPostProcessor
needs to be instantiated early in order to apply to the initialization of other beans in the context, this early type detection is critical.
- 注意,当在配置类上使用@Bean工厂方法声明BeanPostProcessor时,工厂方法的返回类型应该是实现类本身,或者至少是org.springframework.bean .factory.config。BeanPostProcessor接口,清楚地表明该bean的后处理器特性。否则,ApplicationContext将不能在完全创建它之前根据类型自动检测它。由于BeanPostProcessor需要尽早实例化,以便应用于上下文中其他bean的初始化,因此这种早期类型检测非常关键。
Programmatically registering BeanPostProcessorsWhile the recommended approach for BeanPostProcessor registration is through ApplicationContext auto-detection (as described above), it is also possible to register them programmatically against a ConfigurableBeanFactory using the addBeanPostProcessor method. This can be useful when needing to evaluate conditional logic before registration, or even for copying bean post processors across contexts in a hierarchy. Note however that BeanPostProcessor s added programmatically do not respect the Ordered interface. Here it is the order of registration that dictates the order of execution. Note also that BeanPostProcessor s registered programmatically are always processed before those registered through auto-detection, regardless of any explicit ordering. |
|
---|---|
BeanPostProcessors and AOP auto-proxyingClasses that implement the BeanPostProcessor interface are special and are treated differently by the container. All BeanPostProcessor s and beans that they reference directly are instantiated on startup, as part of the special startup phase of the ApplicationContext . Next, all BeanPostProcessor s are registered in a sorted fashion and applied to all further beans in the container. Because AOP auto-proxying is implemented as a BeanPostProcessor itself, neither BeanPostProcessor s nor the beans they reference directly are eligible for auto-proxying, and thus do not have aspects woven into them.For any such bean, you should see an informational log message: "Bean foo is not eligible for getting processed by all BeanPostProcessor interfaces (for example: not eligible for auto-proxying)".Note that if you have beans wired into your BeanPostProcessor using autowiring or @Resource (which may fall back to autowiring), Spring might access unexpected beans when searching for type-matching dependency candidates, and therefore make them ineligible for auto-proxying or other kinds of bean post-processing. For example, if you have a dependency annotated with @Resource where the field/setter name does not directly correspond to the declared name of a bean and no name attribute is used, then Spring will access other beans for matching them by type. |
|
---|---|
-
以编程方式注册BeanPostProcessors
虽然推荐的BeanPostProcessor注册方法是通过ApplicationContext自动检测(如上所述),但是也可以使用addBeanPostProcessor方法针对ConfigurableBeanFactory编程注册它们。当需要在注册前计算条件逻辑时,或者甚至在跨层次结构中的上下文复制bean post处理器时,这可能非常有用。但是请注意,通过编程方式添加的BeanPostProcessors不尊重有序接口。这是登记顺序
- 实现BeanPostProcessor接口的BeanPostProcessor和AOP自动代理类是特殊的,容器对它们的处理是不同的。作为ApplicationContext特殊启动阶段的一部分,它们直接引用的所有beanpostprocessor和bean都在启动时实例化。接下来,以排序的方式注册所有beanpostprocessor,并应用于容器中进一步的所有bean。因为AOP自动代理是作为BeanPostProcessor本身实现的,所以无论是BeanPostProcessor还是它们直接引用的bean都不适合自动代理,因此没有将方面编织到它们之中。对于任何这样的bean,您都应该看到一个信息日志消息:“bean foo不适合被所有BeanPostProcessor接口处理(例如:不适合自动代理)”。注意,如果您使用自动装配或@Resource(可能会回到自动装配)将bean连接到BeanPostProcessor,那么在搜索类型匹配依赖项候选时,Spring可能会访问意外的bean,从而使它们不符合自动代理或其他类型的bean后处理的条件。例如,如果您有一个用@Resource注释的依赖项,其中字段/setter名称没有直接对应于bean的声明名称,并且没有使用name属性,那么Spring将访问其他bean,以按类型匹配它们。
The following examples show how to write, register, and use BeanPostProcessor
s in an ApplicationContext
.
- 下面的示例展示了如何在ApplicationContext中编写、注册和使用BeanPostProcessors。
Example: Hello World, BeanPostProcessor-style (示例:Hello World, beanpostprocessor风格)
This first example illustrates basic usage. The example shows a custom BeanPostProcessor
implementation that invokes the toString()
method of each bean as it is created by the container and prints the resulting string to the system console.
- 第一个示例演示了基本用法。示例展示了一个自定义BeanPostProcessor实现,它在容器创建每个bean时调用该bean的toString()方法,并将结果字符串打印到系统控制台。
Find below the custom BeanPostProcessor
implementation class definition:
- 下面是自定义的BeanPostProcessor实现类定义:
package scripting;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor {
// simply return the instantiated bean as-is
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean; // we could potentially return any object reference here...
}
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("Bean '" + beanName + "' created : " + bean.toString());
return bean;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang
http://www.springframework.org/schema/lang/spring-lang.xsd">
<lang:groovy id="messenger"
script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy">
<lang:property name="message" value="Fiona Apple Is Just So Dreamy."/>
</lang:groovy>
<!--
when the above bean (messenger) is instantiated, this custom
BeanPostProcessor implementation will output the fact to the system console
-->
<bean class="scripting.InstantiationTracingBeanPostProcessor"/>
</beans>
Notice how the InstantiationTracingBeanPostProcessor
is simply defined. It does not even have a name, and because it is a bean it can be dependency-injected just like any other bean. (The preceding configuration also defines a bean that is backed by a Groovy script. The Spring dynamic language support is detailed in the chapter entitled Dynamic language support.)
- 请注意实例化tracingbeanpostprocessor是如何简单地定义的。它甚至没有名称,因为它是一个bean,所以可以像其他任何bean一样进行依赖注入。(前面的配置还定义了一个由Groovy脚本支持的bean。Spring的动态语言支持在名为动态语言支持的章节中有详细说明。)
The following simple Java application executes the preceding code and configuration:
- 以下简单的Java应用程序执行上述代码和配置:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scripting.Messenger;
public final class Boot {
public static void main(final String[] args) throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("scripting/beans.xml");
Messenger messenger = (Messenger) ctx.getBean("messenger");
System.out.println(messenger);
}
}
The output of the preceding application resembles the following:
- 上述应用程序的输出类似如下:
Bean 'messenger' created : org.springframework.scripting.groovy.GroovyMessenger@272961
org.springframework.scripting.groovy.GroovyMessenger@272961
Example: The RequiredAnnotationBeanPostProcessor(例子:)
Using callback interfaces or annotations in conjunction with a custom BeanPostProcessor
implementation is a common means of extending the Spring IoC container. An example is Spring’s RequiredAnnotationBeanPostProcessor
- a BeanPostProcessor
implementation that ships with the Spring distribution which ensures that JavaBean properties on beans that are marked with an (arbitrary) annotation are actually (configured to be) dependency-injected with a value.
- 将回调接口或注释与自定义BeanPostProcessor实现结合使用是扩展Spring IoC容器的一种常见方法。一个例子是Spring的RequiredAnnotationBeanPostProcessor——一个随Spring发行版附带的BeanPostProcessor实现,它确保用(任意)注释标记的bean上的JavaBean属性实际上(配置为)依赖注入一个值。
1.8.2. Customizing configuration metadata with a BeanFactoryPostProcessor(使用BeanFactoryPostProcessor自定义配置元数据)
The next extension point that we will look at is the org.springframework.beans.factory.config.BeanFactoryPostProcessor
. The semantics of this interface are similar to those of the BeanPostProcessor
, with one major difference: BeanFactoryPostProcessor
operates on the bean configuration metadata; that is, the Spring IoC container allows a BeanFactoryPostProcessor
to read the configuration metadata and potentially change it before the container instantiates any beans other than BeanFactoryPostProcessor
s.
- 我们将看到的下一个扩展点是org.springframework.beans.factory.config.BeanFactoryPostProcessor。这个接口的语义与BeanPostProcessor类似,但有一个主要的区别:BeanFactoryPostProcessor操作bean配置元数据;也就是说,Spring IoC容器允许BeanFactoryPostProcessor读取配置元数据,并可能在容器实例化BeanFactoryPostProcessor以外的任何bean之前更改它。
You can configure multiple BeanFactoryPostProcessor
s, and you can control the order in which these BeanFactoryPostProcessor
s execute by setting the order
property. However, you can only set this property if the BeanFactoryPostProcessor
implements the Ordered
interface. If you write your own BeanFactoryPostProcessor
, you should consider implementing the Ordered
interface too. Consult the javadocs of the BeanFactoryPostProcessor
and Ordered
interfaces for more details.
- 您可以配置多个beanfactorypostprocessor,并且您可以通过设置order属性来控制这些beanfactorypostprocessor的执行顺序。但是,您只能在BeanFactoryPostProcessor实现了有序接口的情况下设置此属性。如果您编写自己的BeanFactoryPostProcessor,您也应该考虑实现Ordered接口。有关更多细节,请咨询BeanFactoryPostProcessor和有序接口的javadocs。
If you want to change the actual bean instances (i.e., the objects that are created from the configuration metadata), then you instead need to use a BeanPostProcessor (described above in Customizing beans using a BeanPostProcessor). While it is technically possible to work with bean instances within a BeanFactoryPostProcessor (e.g., using BeanFactory.getBean() ), doing so causes premature bean instantiation, violating the standard container lifecycle. This may cause negative side effects such as bypassing bean post processing.Also, BeanFactoryPostProcessor s are scoped per-container. This is only relevant if you are using container hierarchies. If you define a BeanFactoryPostProcessor in one container, it will only be applied to the bean definitions in that container. Bean definitions in one container will not be post-processed by BeanFactoryPostProcessor s in another container, even if both containers are part of the same hierarchy. |
|
---|---|
- 如果您希望更改实际的bean实例(即从配置元数据创建的对象),那么您需要使用BeanPostProcessor(在上面使用BeanPostProcessor自定义bean中描述)。虽然在BeanFactoryPostProcessor中处理bean实例在技术上是可行的(例如,使用BeanFactory.getBean()),但是这样做会导致过早的bean实例化,违反标准的容器生命周期。这可能会导致负面的副作用,比如绕过bean后处理。此外,beanfactorypostprocessor的作用域为每个容器。这只有在使用容器层次结构时才有用。如果您在一个容器中定义了BeanFactoryPostProcessor,那么它将只应用于该容器中的bean定义。一个容器中的Bean定义不会被另一个容器中的beanfactorypostprocessor进行后处理,即使这两个容器属于同一层次结构。
A bean factory post-processor is executed automatically when it is declared inside an ApplicationContext
, in order to apply changes to the configuration metadata that define the container. Spring includes a number of predefined bean factory post-processors, such as PropertyOverrideConfigurer
and PropertyPlaceholderConfigurer
. A custom BeanFactoryPostProcessor
can also be used, for example, to register custom property editors.
- 当bean工厂后处理器在ApplicationContext中声明时,它将自动执行,以便对定义容器的配置元数据应用更改。Spring包括许多预定义的bean工厂后处理器,如PropertyOverrideConfigurer和PropertyPlaceholderConfigurer。例如,还可以使用自定义BeanFactoryPostProcessor来注册自定义属性编辑器。
An ApplicationContext
automatically detects any beans that are deployed into it that implement the BeanFactoryPostProcessor
interface. It uses these beans as bean factory post-processors, at the appropriate time. You can deploy these post-processor beans as you would any other bean.
- 当bean工厂后处理器在ApplicationContext中声明时,它将自动执行,以便对定义容器的配置元数据应用更改。Spring包括许多预定义的bean工厂后处理器,如PropertyOverrideConfigurer和PropertyPlaceholderConfigurer。例如,还可以使用自定义BeanFactoryPostProcessor来注册自定义属性编辑器。
As with BeanPostProcessor s , you typically do not want to configure BeanFactoryPostProcessor s for lazy initialization. If no other bean references a Bean(Factory)PostProcessor , that post-processor will not get instantiated at all. Thus, marking it for lazy initialization will be ignored, and the Bean(Factory)PostProcessor will be instantiated eagerly even if you set the default-lazy-init attribute to true on the declaration of your <beans /> element. |
|
---|---|
- 与BeanPostProcessors一样,您通常不希望将BeanFactoryPostProcessors配置为延迟初始化。如果没有其他bean引用bean(工厂)后处理器,则该后处理器根本不会实例化。因此,将其标记为延迟初始化将被忽略,并且即使在声明
元素时将default-lazy-init属性设置为true, Bean(工厂)后处理器也将被快速实例化。
Example: the Class name substitution PropertyPlaceholderConfigurer(示例:类名替换)
You use the PropertyPlaceholderConfigurer
to externalize property values from a bean definition in a separate file using the standard Java Properties
format. Doing so enables the person deploying an application to customize environment-specific properties such as database URLs and passwords, without the complexity or risk of modifying the main XML definition file or files for the container.
- 您可以使用PropertyPlaceholderConfigurer将来自bean定义的属性值外部化到使用标准Java属性格式的单独文件中。这样,部署应用程序的人员就可以自定义特定于环境的属性,如数据库url和密码,而无需修改主XML定义文件或容器文件的复杂性或风险。
Consider the following XML-based configuration metadata fragment, where a DataSource
with placeholder values is defined. The example shows properties configured from an external Properties
file. At runtime, a PropertyPlaceholderConfigurer
is applied to the metadata that will replace some properties of the DataSource. The values to replace are specified as placeholders of the form ${property-name}
which follows the Ant / log4j / JSP EL style.
- 考虑以下基于xml的配置元数据片段,其中定义了具有占位符值的数据源。该示例显示了从外部属性文件配置的属性。在运行时,PropertyPlaceholderConfigurer应用于将替换数据源的某些属性的元数据。要替换的值指定为表单${property-name}的占位符,该表单遵循Ant / log4j / JSP EL样式。
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:com/foo/jdbc.properties"/>
</bean>
<bean id="dataSource" destroy-method="close"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
The actual values come from another file in the standard Java Properties
format:
- 实际值来自另一个标准Java属性格式的文件:
jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root
Therefore, the string ${jdbc.username}
is replaced at runtime with the value 'sa', and the same applies for other placeholder values that match keys in the properties file. The PropertyPlaceholderConfigurer
checks for placeholders in most properties and attributes of a bean definition. Furthermore, the placeholder prefix and suffix can be customized.
- 因此,字符串${jdbc。在运行时使用值'sa'替换username},对于匹配属性文件中的键的其他占位符值也适用同样的方法。PropertyPlaceholderConfigurer检查bean定义的大多数属性和属性中的占位符。此外,占位符的前缀和后缀可以定制。
With the context
namespace introduced in Spring 2.5, it is possible to configure property placeholders with a dedicated configuration element. One or more locations can be provided as a comma-separated list in the location
attribute.
- 由于在Spring 2.5中引入了上下文名称空间,所以可以用一个专用的配置元素配置属性占位符。可以在location属性中以逗号分隔的列表形式提供一个或多个位置。
<context:property-placeholder location="classpath:com/foo/jdbc.properties"/>
The PropertyPlaceholderConfigurer
not only looks for properties in the Properties
file you specify. By default it also checks against the Java System
properties if it cannot find a property in the specified properties files. You can customize this behavior by setting the systemPropertiesMode
property of the configurer with one of the following three supported integer values:
-
PropertyPlaceholderConfigurer不仅在您指定的属性文件中查找属性。默认情况下,如果在指定的属性文件中找不到属性,它还会检查Java系统属性。您可以通过使用以下三个支持的整数值之一设置配置器的systemPropertiesMode属性来定制此行为:
-
never (0): Never check system properties
- never(0):永远不要检查系统属性
-
fallback (1): Check system properties if not resolvable in the specified properties files. This is the default.
-
override (2): Check system properties first, before trying the specified properties files. This allows system properties to override any other property source.
- 回退(1):如果在指定的属性文件中无法解析,则检查系统属性。这是默认值。
- override(2):在尝试指定的属性文件之前,先检查系统属性。这允许系统属性覆盖任何其他属性源。
Consult the PropertyPlaceholderConfigurer
javadocs for more information.
- 有关更多信息,请参阅PropertyPlaceholderConfigurer javadocs。
You can use the PropertyPlaceholderConfigurer to substitute class names, which is sometimes useful when you have to pick a particular implementation class at runtime. For example:(您可以使用PropertyPlaceholderConfigurer来替换类名,当您必须在运行时选择特定的实现类时,这有时很有用。例如:)<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <value>classpath:com/foo/strategy.properties</value> </property> <property name="properties"> <value>custom.strategy.class=com.foo.DefaultStrategy</value> </property> </bean> <bean id="serviceStrategy" class="${custom.strategy.class}"/> If the class cannot be resolved at runtime to a valid class, resolution of the bean fails when it is about to be created, which is during the preInstantiateSingletons() phase of an ApplicationContext for a non-lazy-init bean.(如果不能在运行时将类解析为有效类,则在即将创建bean时,即在ApplicationContext非延迟init bean的预实例化esingletons()阶段,对bean的解析将失败。) |
|
---|---|
Example: the PropertyOverrideConfigurer(例子:PropertyOverrideConfigurer)
The PropertyOverrideConfigurer
, another bean factory post-processor, resembles the PropertyPlaceholderConfigurer
, but unlike the latter, the original definitions can have default values or no values at all for bean properties. If an overriding Properties
file does not have an entry for a certain bean property, the default context definition is used.
- PropertyOverrideConfigurer是另一个bean工厂后处理器,它类似于PropertyPlaceholderConfigurer,但与后者不同的是,原始定义可以为bean属性提供默认值,也可以不提供任何值。如果覆盖属性文件没有针对某个bean属性的条目,则使用默认上下文定义。
Note that the bean definition is not aware of being overridden, so it is not immediately obvious from the XML definition file that the override configurer is being used. In case of multiple PropertyOverrideConfigurer
instances that define different values for the same bean property, the last one wins, due to the overriding mechanism.
- 请注意,bean定义不知道被覆盖,因此从XML定义文件中不能立即看出正在使用覆盖配置器。在多个PropertyOverrideConfigurer实例为同一个bean属性定义不同值的情况下,由于覆盖机制,最后一个实例胜出。
Properties file configuration lines take this format:
- 属性文件配置行采用以下格式:
beanName.property=value
For example:
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql:mydb
This example file can be used with a container definition that contains a bean called dataSource, which has driver and url properties.
- 这个示例文件可以与包含名为dataSource的bean的容器定义一起使用,该bean具有驱动程序和url属性。
Compound property names are also supported, as long as every component of the path except the final property being overridden is already non-null (presumably initialized by the constructors). In this example…
- 还支持复合属性名,只要路径的每个组件(除了被覆盖的final属性)都是非空的(假定由构造函数初始化)。在这个例子中…
foo.fred.bob.sammy=123
- the
sammy
property of thebob
property of thefred
property of thefoo
bean is set to the scalar value123
.- foo bean的fred属性的bob属性的sammy属性被设置为标量值123。
Specified override values are always literal values; they are not translated into bean references. This convention also applies when the original value in the XML bean definition specifies a bean reference. | |
---|---|
- 指定的重写值总是文字值;它们没有被转换为bean引用。当XML bean定义中的原始值指定了一个bean引用时,这个约定也适用。
With the context
namespace introduced in Spring 2.5, it is possible to configure property overriding with a dedicated configuration element:
- 随着上下文名称空间在spring2.5中引入,可以用一个专用的配置元素配置属性重写:
<context:property-override location="classpath:override.properties"/>
1.8.3. Customizing instantiation logic with a FactoryBean(使用FactoryBean自定义实例化逻辑)
Implement the org.springframework.beans.factory.FactoryBean
interface for objects that are themselves factories.
- 实现org.springframework.beans.factory。为本身是工厂的对象提供FactoryBean接口。
The FactoryBean
interface is a point of pluggability into the Spring IoC container’s instantiation logic. If you have complex initialization code that is better expressed in Java as opposed to a (potentially) verbose amount of XML, you can create your own FactoryBean
, write the complex initialization inside that class, and then plug your custom FactoryBean
into the container.
- FactoryBean接口是Spring IoC容器实例化逻辑的可插入点。如果您有复杂的初始化代码(用Java来表达比(可能)冗长的XML更好),那么您可以创建自己的FactoryBean,在类中编写复杂的初始化,然后将定制的FactoryBean插入到容器中。
The FactoryBean
interface provides three methods:
-
FactoryBean接口提供了三种方法:
-
Object getObject()
: returns an instance of the object this factory creates. The instance can possibly be shared, depending on whether this factory returns singletons or prototypes.- 对象getObject():返回此工厂创建的对象的实例。实例可能被共享,这取决于这个工厂返回的是单例还是原型。
-
boolean isSingleton()
: returnstrue
if thisFactoryBean
returns singletons,false
otherwise.- boolean isSingleton():如果FactoryBean返回单例,返回true,否则返回false。
-
Class getObjectType()
: returns the object type returned by thegetObject()
method ornull
if the type is not known in advance.- 类getObjectType():返回getObject()方法返回的对象类型,如果事先不知道该类型,则返回null。
The FactoryBean
concept and interface is used in a number of places within the Spring Framework; more than 50 implementations of the FactoryBean
interface ship with Spring itself.
- FactoryBean的概念和接口被用在Spring框架的许多地方;Spring本身附带了50多个FactoryBean接口的实现。
When you need to ask a container for an actual FactoryBean
instance itself instead of the bean it produces, preface the bean’s id with the ampersand symbol ( &
) when calling the getBean()
method of the ApplicationContext
. So for a given FactoryBean
with an id of myBean
, invoking getBean("myBean")
on the container returns the product of the FactoryBean
; whereas, invoking getBean("&myBean")
returns the FactoryBean
instance itself.
- 当您需要向容器请求实际的FactoryBean实例本身而不是它生成的bean时,在调用ApplicationContext的getBean()方法时,在bean的id前面加上&符号(&)。因此,对于id为myBean的给定FactoryBean,在容器上调用getBean(“myBean”)将返回FactoryBean的产品;然而,调用getBean(“&myBean”)返回FactoryBean实例本身。
1.9. Annotation-based container configuration(基于注解的容器配置)
Are annotations better than XML for configuring Spring?
- 在配置Spring时,注释比XML更好吗?
The introduction of annotation-based configurations raised the question of whether this approach is 'better' than XML. The short answer is it depends. The long answer is that each approach has its pros and cons, and usually it is up to the developer to decide which strategy suits them better. Due to the way they are defined, annotations provide a lot of context in their declaration, leading to shorter and more concise configuration. However, XML excels at wiring up components without touching their source code or recompiling them. Some developers prefer having the wiring close to the source while others argue that annotated classes are no longer POJOs and, furthermore, that the configuration becomes decentralized and harder to control.
- 基于注释的配置的引入引发了这样一个问题:这种方法是否比XML“更好”。简短的回答是视情况而定。很长的答案是每种方法都有其优缺点,通常由开发人员决定哪种策略更适合他们。由于其定义方式,注释在其声明中提供了大量上下文,从而使配置更短、更简洁。但是,XML擅长在不改动源代码或重新编译组件的情况下连接组件。一些开发人员更喜欢连接到接近源代码的地方,而另一些人则认为带注释的类不再是pojo,而且配置变得分散且难以控制。
No matter the choice, Spring can accommodate both styles and even mix them together. It’s worth pointing out that through its JavaConfig option, Spring allows annotations to be used in a non-invasive way, without touching the target components source code and that in terms of tooling, all configuration styles are supported by the Spring Tool Suite.
- 无论选择什么,Spring都可以容纳这两种风格,甚至可以将它们混合在一起。值得指出的是,通过它的JavaConfig选项,Spring允许以非侵入性的方式使用注释,而不涉及目标组件的源代码,而且就工具而言,Spring工具套件支持所有配置样式。
An alternative to XML setups is provided by annotation-based configuration which rely on the bytecode metadata for wiring up components instead of angle-bracket declarations. Instead of using XML to describe a bean wiring, the developer moves the configuration into the component class itself by using annotations on the relevant class, method, or field declaration. As mentioned in Example: The RequiredAnnotationBeanPostProcessor, using a BeanPostProcessor
in conjunction with annotations is a common means of extending the Spring IoC container. For example, Spring 2.0 introduced the possibility of enforcing required properties with the @Required annotation. Spring 2.5 made it possible to follow that same general approach to drive Spring’s dependency injection. Essentially, the @Autowired
annotation provides the same capabilities as described in Autowiring collaborators but with more fine-grained control and wider applicability. Spring 2.5 also added support for JSR-250 annotations such as @PostConstruct
, and @PreDestroy
. Spring 3.0 added support for JSR-330 (Dependency Injection for Java) annotations contained in the javax.inject package such as @Inject
and @Named
. Details about those annotations can be found in the relevant section.
- XML设置的另一种选择是基于注释的配置,它依赖字节码元数据来连接组件,而不是使用尖括号声明。开发人员没有使用XML来描述bean连接,而是通过在相关类、方法或字段声明上使用注释,将配置转移到组件类本身。如示例中所述:RequiredAnnotationBeanPostProcessor使用BeanPostProcessor与注释结合使用是扩展Spring IoC容器的常见方法。例如,Spring 2.0引入了使用@Required注释强制执行必需属性的可能性。Spring 2.5使遵循相同的通用方法来驱动Spring的依赖项注入成为可能。从本质上讲,@Autowired注解提供了与Autowiring协作器中描述的相同的功能,但是拥有更细粒度的控制和更广泛的适用性。Spring 2.5还添加了对JSR-250注释的支持,比如@PostConstruct和@PreDestroy。Spring 3.0增加了对javax中包含的JSR-330 (Java依赖注入)注释的支持。注入包,如@Inject和@Named。有关这些注释的详细信息可以在相关部分找到。
Annotation injection is performed before XML injection, thus the latter configuration will override the former for properties wired through both approaches. | |
---|---|
- 注释注入在XML注入之前执行,因此对于通过两种方法连接的属性,后一种配置将覆盖前者。
As always, you can register them as individual bean definitions, but they can also be implicitly registered by including the following tag in an XML-based Spring configuration (notice the inclusion of the context
namespace):
- 和往常一样,你可以将它们注册为单独的bean定义,但是也可以通过在基于xml的Spring配置中包含以下标签(注意包含上下文名称空间)来隐式地注册它们:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
(The implicitly registered post-processors include AutowiredAnnotationBeanPostProcessor
, CommonAnnotationBeanPostProcessor
, PersistenceAnnotationBeanPostProcessor
, as well as the aforementioned RequiredAnnotationBeanPostProcessor
.)
- (隐式注册的后处理器包括AutowiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, PersistenceAnnotationBeanPostProcessor,以及前面提到的RequiredAnnotationBeanPostProcessor。)
<context:annotation-config/> only looks for annotations on beans in the same application context in which it is defined. This means that, if you put <context:annotation-config/> in a WebApplicationContext for a DispatcherServlet , it only checks for @Autowired beans in your controllers, and not your services. See The DispatcherServlet for more information. |
|
---|---|
- context:注解-config/只在定义它的应用程序上下文中的bean上寻找注解。这意味着,如果你在WebApplicationContext中为DispatcherServlet添加context:annotation-config/,它只检查控制器中的@Autowired bean,而不是你的服务。有关更多信息,请参阅DispatcherServlet。
1.9.1. @Required(必须的)
The @Required
annotation applies to bean property setter methods, as in the following example:
- @Required注释适用于bean属性setter方法,如下面的例子所示:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Required
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
This annotation simply indicates that the affected bean property must be populated at configuration time, through an explicit property value in a bean definition or through autowiring. The container throws an exception if the affected bean property has not been populated; this allows for eager and explicit failure, avoiding NullPointerException
s or the like later on. It is still recommended that you put assertions into the bean class itself, for example, into an init method. Doing so enforces those required references and values even when you use the class outside of a container.
- 这个注释只是指出,必须在配置时通过bean定义中的显式属性值或自动装配填充受影响的bean属性。如果未填充受影响的bean属性,容器将抛出异常;这允许出现迫切的和显式的失败,避免了以后出现nullpointerexception或类似的情况。仍然建议您将断言放到bean类本身中,例如,放到init方法中。这样做会强制执行那些必需的引用和值,即使您在容器之外使用该类。
1.9.2. @Autowired(自动装配)
JSR 330’s @Inject annotation can be used in place of Spring’s @Autowired annotation in the examples below. See here for more details. |
|
---|---|
- 在下面的例子中,JSR 330的@Inject注解可以用来代替Spring的@Autowired注解。更多细节请看这里。
You can apply the @Autowired
annotation to constructors:
- 你可以对构造函数应用@Autowired注解:
public class MovieRecommender {
private final CustomerPreferenceDao customerPreferenceDao;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
As of Spring Framework 4.3, an @Autowired annotation on such a constructor is no longer necessary if the target bean only defines one constructor to begin with. However, if several constructors are available, at least one must be annotated to teach the container which one to use. |
|
---|---|
As expected, you can also apply the @Autowired
annotation to "traditional" setter methods:
- 正如所料,你也可以对“传统”setter方法应用@Autowired注解:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
You can also apply the annotation to methods with arbitrary names and/or multiple arguments:
- 你也可以将注释应用到具有任意名称和/或多个参数的方法:
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
You can apply @Autowired
to fields as well and even mix it with constructors:
- 你也可以对字段应用@Autowired表格,甚至可以和构造器混合使用:
public class MovieRecommender {
private final CustomerPreferenceDao customerPreferenceDao;
@Autowired
private MovieCatalog movieCatalog;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
Make sure that your target components (e.g. MovieCatalog , CustomerPreferenceDao ) are consistently declared by the type that you are using for your @Autowired -annotated injection points. Otherwise injection may fail due to no type match found at runtime.For XML-defined beans or component classes found through a classpath scan, the container usually knows the concrete type upfront. However, for @Bean factory methods, you need to make sure that the declared return type is sufficiently expressive. For components implementing several interfaces or for components potentially referred to by their implementation type, consider declaring the most specific return type on your factory method (at least as specific as required by the injection points referring to your bean). |
|
---|---|
- 确保你的目标组件(例如MovieCatalog, CustomerPreferenceDao)由你使用的@ autowire注释的注入点的类型一致地声明。否则,注入可能会因为在运行时没有找到类型匹配而失败。对于通过类路径扫描找到的xml定义的bean或组件类,容器通常预先知道具体的类型。但是,对于@Bean工厂方法,您需要确保声明的返回类型具有足够的表达能力。对于实现多个接口的组件,或者对于可能由其实现类型引用的组件,考虑在您的工厂方法上声明最特定的返回类型(至少与in要求的一样特定)
It is also possible to provide all beans of a particular type from the AppliscationContext
by adding the annotation to a field or method that expects an array of that type:
- 也可以通过向需要该类型数组的字段或方法添加注释,从ApplicationContext中提供特定类型的所有bean:
public class MovieRecommender {
@Autowired
private MovieCatalog[] movieCatalogs;
// ...
}
The same applies for typed collections:
- 类型化集合也同样适用:
public class MovieRecommender {
private Set<MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}
Your target beans can implement the org.springframework.core.Ordered interface or use the @Order or standard @Priority annotation if you want items in the array or list to be sorted in a specific order. Otherwise their order will follow the registration order of the corresponding target bean definitions in the container.The @Order annotation may be declared at target class level but also on @Bean methods, potentially being very individual per bean definition (in case of multiple definitions with the same bean class). @Order values may influence priorities at injection points, but please be aware that they do not influence singleton startup order which is an orthogonal concern determined by dependency relationships and @DependsOn declarations.Note that the standard javax.annotation.Priority annotation is not available at the @Bean level since it cannot be declared on methods. Its semantics can be modeled through @Order values in combination with @Primary on a single bean per type. |
|
---|---|
- 您的目标bean可以实现org.springframework.core。如果希望数组或列表中的项按特定顺序排序,则可以使用@Order或标准@Priority注释。否则,它们的顺序将遵循容器中相应目标bean定义的注册顺序。@Order注释可以在目标类级别声明,也可以在@Bean方法上声明,每个bean定义都可能非常独立(在使用相同bean类的多个定义的情况下)。@Order值可能会影响注入点的优先级,但请注意,它们不会影响单例启动顺序,单例启动顺序是由依赖关系和@DependsOn声明决定的正交关系。请注意标准javax.annotation。优先级注释在@Bean级别不可用,因为它不能在方法上声明。它的语义可以通过在每个类型的单个bean上结合@Order值和@Primary来建模。
Even typed Maps can be autowired as long as the expected key type is String
. The Map values will contain all beans of the expected type, and the keys will contain the corresponding bean names:
- 即使是类型映射也可以自动实现,只要期望的键类型是String。映射值将包含所有期望类型的bean,键将包含相应的bean名称:
public class MovieRecommender {
private Map<String, MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}
By default, the autowiring fails whenever zero candidate beans are available; the default behavior is to treat annotated methods, constructors, and fields as indicating required dependencies. This behavior can be changed as demonstrated below.
- 默认情况下,只要没有候选bean可用,自动装配就会失败;默认行为是将带注释的方法、构造函数和字段视为指示所需的依赖项。此行为可以更改,如下所示。
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired(required = false)
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
Only one annotated constructor per-class can be marked as required, but multiple non-required constructors can be annotated. In that case, each is considered among the candidates and Spring uses the greediest constructor whose dependencies can be satisfied, that is the constructor that has the largest number of arguments.The required attribute of @Autowired is recommended over the @Required annotation. The required attribute indicates that the property is not required for autowiring purposes, the property is ignored if it cannot be autowired. @Required , on the other hand, is stronger in that it enforces the property that was set by any means supported by the container. If no value is injected, a corresponding exception is raised. |
|
---|---|
- 每个类只能将一个带注释的构造函数标记为必需的,但是可以对多个非必需的构造函数进行注释。在这种情况下,每个函数都被考虑在候选函数中,Spring使用可以满足依赖关系的贪婪构造函数,也就是参数数量最多的构造函数。建议在@Required注释上使用@Autowired的required属性。required属性表示该属性对于自动装配目的是不需要的,如果该属性不能自动装配,则忽略它。另一方面,@Required更强大,因为它强制容器支持的任何方式设置的属性。如果没有注入任何值,则会引发相应的异常。
Alternatively, you may express the non-required nature of a particular dependency through Java 8’s java.util.Optional
:或者,你也可以通过Java 8的Java .util. optional来表达某个特定依赖项的非必需性质:
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(Optional<MovieFinder> movieFinder) {
...
}
}
As of Spring Framework 5.0, you may also use an @Nullable
annotation (of any kind in any package, e.g. javax.annotation.Nullable
from JSR-305):
- 在Spring Framework 5.0中,您还可以使用@Nullable注释(在任何包中使用任何类型的注释,例如javax.annotation)。从jsr - 305)可以为空:
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(@Nullable MovieFinder movieFinder) {
...
}
}
You can also use @Autowired
for interfaces that are well-known resolvable dependencies: BeanFactory
, ApplicationContext
, Environment
, ResourceLoader
, ApplicationEventPublisher
, and MessageSource
. These interfaces and their extended interfaces, such as ConfigurableApplicationContext
or ResourcePatternResolver
, are automatically resolved, with no special setup necessary.
- 你也可以使用@Autowired的接口是众所周知的可解析依赖:BeanFactory, ApplicationContext, Environment, ResourceLoader, ApplicationEventPublisher,和MessageSource。这些接口及其扩展接口,如ConfigurableApplicationContext或ResourcePatternResolver,会自动解析,不需要特殊设置。
public class MovieRecommender {
@Autowired
private ApplicationContext context;
public MovieRecommender() {
}
// ...
}
@Autowired , @Inject , @Resource , and @Value annotations are handled by Spring BeanPostProcessor implementations which in turn means that you cannot apply these annotations within your own BeanPostProcessor or BeanFactoryPostProcessor types (if any). These types must be 'wired up' explicitly via XML or using a Spring @Bean method. |
|
---|---|
- @Autowired, @Inject, @Resource,和@Value注解是由Spring BeanPostProcessor实现处理的,这意味着你不能在你自己的BeanPostProcessor或BeanFactoryPostProcessor类型(如果有的话)中应用这些注解。这些类型必须通过XML或使用Spring @Bean方法显式地“连接起来”。
1.9.3. Fine-tuning annotation-based autowiring with @Primary(使用@Primary微调基于注释的自动装配)
Because autowiring by type may lead to multiple candidates, it is often necessary to have more control over the selection process. One way to accomplish this is with Spring’s @Primary
annotation. @Primary
indicates that a particular bean should be given preference when multiple beans are candidates to be autowired to a single-valued dependency. If exactly one 'primary' bean exists among the candidates, it will be the autowired value.
- 由于按类型自动装配可能会导致多个候选,因此通常有必要对选择过程进行更多的控制。实现这一点的一种方法是使用Spring的@Primary注释。@Primary表示当多个bean是要自动传递到单值依赖项的候选bean时,应该优先给予特定bean。如果候选对象中恰好有一个“主要”bean,那么它就是自动生成的值。
Let’s assume we have the following configuration that defines firstMovieCatalog
as the primary MovieCatalog
.
- 让我们假设我们有以下配置,它将firstMovieCatalog定义为主要的MovieCatalog。
@Configuration
public class MovieConfiguration {
@Bean
@Primary
public MovieCatalog firstMovieCatalog() { ... }
@Bean
public MovieCatalog secondMovieCatalog() { ... }
// ...
}
With such configuration, the following MovieRecommender
will be autowired with the firstMovieCatalog
.
- 通过这样的配置,下面的MovieRecommender将使用firstMovieCatalog自动生成
public class MovieRecommender {
@Autowired
private MovieCatalog movieCatalog;
// ...
}
The corresponding bean definitions appear as follows.
- 对应的bean定义如下。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog" primary="true">
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<!-- inject any dependencies required by this bean -->
</bean>
<bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>
1.9.4. Fine-tuning annotation-based autowiring with qualifiers(微调基于注释的自动装配,使用限定符)
@Primary
is an effective way to use autowiring by type with several instances when one primary candidate can be determined. When more control over the selection process is required, Spring’s @Qualifier
annotation can be used. You can associate qualifier values with specific arguments, narrowing the set of type matches so that a specific bean is chosen for each argument. In the simplest case, this can be a plain descriptive value:
- 当一个主要候选对象可以被确定时,@Primary是一种通过类型使用多个实例的自动装配的有效方法。当需要对选择过程进行更多控制时,可以使用Spring s @Qualifier注释。您可以将限定符值与特定的参数相关联,从而缩小类型匹配的范围,以便为每个参数选择特定的bean。在最简单的情况下,这可以是一个普通的描述性值
public class MovieRecommender {
@Autowired
@Qualifier("main")
private MovieCatalog movieCatalog;
// ...
}
The @Qualifier
annotation can also be specified on individual constructor arguments or method parameters:
- @Qualifier注解也可以在单独的构造函数参数或方法参数上指定:
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(@Qualifier("main")MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
The corresponding bean definitions appear as follows. The bean with qualifier value "main" is wired with the constructor argument that is qualified with the same value.
- 对应的bean定义如下。限定符值为“main”的bean与使用相同值限定的构造函数参数连接。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog">
<qualifier value="main"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier value="action"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>
For a fallback match, the bean name is considered a default qualifier value. Thus you can define the bean with an id "main" instead of the nested qualifier element, leading to the same matching result. However, although you can use this convention to refer to specific beans by name, @Autowired
is fundamentally about type-driven injection with optional semantic qualifiers. This means that qualifier values, even with the bean name fallback, always have narrowing semantics within the set of type matches; they do not semantically express a reference to a unique bean id. Good qualifier values are "main" or "EMEA" or "persistent", expressing characteristics of a specific component that are independent from the bean id
, which may be auto-generated in case of an anonymous bean definition like the one in the preceding example.
- 对于回退匹配,bean名称被认为是默认的限定符值。因此,您可以使用id“main”来定义bean,而不是使用嵌套的限定符元素,从而得到相同的匹配结果。然而,尽管您可以使用这种约定来按名称引用特定的bean,但@Autowired基本上是关于类型驱动的注入,带有可选的语义限定符。这意味着,即使使用bean名称回退,限定符值也总是在类型匹配集内具有收缩语义;他们没有语义表达独特的bean的引用id。良好的限定符值是“主要”或“EMEA”或“持续”,表达某个特定组件的特点是独立于bean id,这可能是在匿名的情况下自动生成的bean定义在前面的例子。对于回退匹配,bean名称被认为是默认的限定符值。因此,您可以使用id“main”来定义bean,而不是使用嵌套的限定符元素,从而得到相同的匹配结果。然而,尽管您可以使用这种约定来按名称引用特定的bean,但@Autowired基本上是关于类型驱动的注入,带有可选的语义限定符。这意味着,即使使用bean名称回退,限定符值也总是在类型匹配集内具有收缩语义;它们没有在语义上表达对唯一bean id的引用。
Qualifiers also apply to typed collections, as discussed above, for example, to Set<MovieCatalog>
. In this case, all matching beans according to the declared qualifiers are injected as a collection. This implies that qualifiers do not have to be unique; they rather simply constitute filtering criteria. For example, you can define multiple MovieCatalog
beans with the same qualifier value "action", all of which would be injected into a Set<MovieCatalog>
annotated with @Qualifier("action")
.
- 限定符也适用于类型化集合,如上所述,例如,用于设置
。在这种情况下,根据声明的限定符匹配的所有bean都作为一个集合注入。这意味着限定符不必是唯一的;它们只是构成了过滤标准。例如,您可以定义具有相同限定符值“action”的多个MovieCatalog bean,所有这些bean都将被注入到带有@Qualifier(“action”)注释的 集合中。
Letting qualifier values select against target bean names, within the type-matching candidates, doesn’t even require a @Qualifier annotation at the injection point. If there is no other resolution indicator (e.g. a qualifier or a primary marker), for a non-unique dependency situation, Spring will match the injection point name (i.e. field name or parameter name) against the target bean names and choose the same-named candidate, if any.That said, if you intend to express annotation-driven injection by name, do not primarily use @Autowired , even if is capable of selecting by bean name among type-matching candidates. Instead, use the JSR-250 @Resource annotation, which is semantically defined to identify a specific target component by its unique name, with the declared type being irrelevant for the matching process. @Autowired has rather different semantics: After selecting candidate beans by type, the specified String qualifier value will be considered within those type-selected candidates only, e.g. matching an "account" qualifier against beans marked with the same qualifier label.For beans that are themselves defined as a collection/map or array type, @Resource is a fine solution, referring to the specific collection or array bean by unique name. That said, as of 4.3, collection/map and array types can be matched through Spring’s @Autowired type matching algorithm as well, as long as the element type information is preserved in @Bean return type signatures or collection inheritance hierarchies. In this case, qualifier values can be used to select among same-typed collections, as outlined in the previous paragraph.As of 4.3, @Autowired also considers self references for injection, i.e. references back to the bean that is currently injected. Note that self injection is a fallback; regular dependencies on other components always have precedence. In that sense, self references do not participate in regular candidate selection and are therefore in particular never primary; on the contrary, they always end up as lowest precedence. In practice, use self references as a last resort only, e.g. for calling other methods on the same instance through the bean’s transactional proxy: Consider factoring out the affected methods to a separate delegate bean in such a scenario. Alternatively, use @Resource which may obtain a proxy back to the current bean by its unique name.@Autowired applies to fields, constructors, and multi-argument methods, allowing for narrowing through qualifier annotations at the parameter level. By contrast, @Resource is supported only for fields and bean property setter methods with a single argument. As a consequence, stick with qualifiers if your injection target is a constructor or a multi-argument method. |
|
---|---|
- 让限定符值在类型匹配候选中针对目标bean名称进行选择,甚至不需要在注入点使用@Qualifier注释。如果没有其他解决指标(例如限定符或主标记),对于非唯一依赖情况,Spring将匹配注入点名称(即字段名称或参数名称)与目标bean名称,并选择同名候选(如果有的话)。也就是说,如果您打算通过名称表示注释驱动的注入,请不要主要使用@Autowired,即使它能够通过bean名称在类型匹配的候选者中进行选择。相反,使用JSR-250 @Resource注释,它在语义上定义为通过惟一名称标识特定的目标组件,声明的类型与匹配过程无关。@Autowired有相当不同的语义:在选择了类型的候选bean之后,指定的字符串限定符值将只在那些类型选择的候选者中被考虑,例如匹配一个“account”限定符和用相同的限定符标签标记的bean。对于本身定义为集合/映射或数组类型的bean, @Resource是一个很好的解决方案,它通过惟一的名称引用特定的集合或数组bean。
限定符也适用于类型化集合,如上所述,例如,用于设置。在这种情况下,根据声明的限定符匹配的所有bean都作为一个集合注入。这意味着限定符不必是唯一的;它们只是构成了过滤标准。例如,您可以定义具有相同限定符值“action”的多个MovieCatalog bean,所有这些bean都将被注入到带有@Qualifier(“action”)注释的 集合中。
也就是说,在4.3中,只要元素类型信息保存在@Bean返回类型签名或集合继承层次结构中,集合/映射和数组类型也可以通过Spring s @Autowired类型匹配算法来匹配。在这种情况下,可以使用限定符值在相同类型的集合中进行选择,如上一段所述。在4.3中,@Autowired也考虑注入的自我引用,也就是对当前注入的bean的引用。请注意,自注入是一种退路;对其他组件的常规依赖始终具有优先级。从这个意义上说,自我参照不参与定期的候选人选择,因此尤其不作为首选;相反,它们总是优先级最低的。在实践中,仅将self引用作为最后的手段,例如,在同一个实例上通过bean s事务代理调用其他方法:在这种情况下,考虑将受影响的方法分解到单独的委托bean中。或者,使用@Resource,它可以通过当前bean的唯一名称获得回它的代理。@Autowired适用于领域,构造器,和多参数方法,允许通过限定符注解在参数级别上缩小范围。相比之下,@Resource只支持具有单个参数的字段和bean属性设置器方法。因此,如果注入目标是构造函数或多参数方法,请坚持使用限定符。
You can create your own custom qualifier annotations. Simply define an annotation and provide the @Qualifier
annotation within your definition:
- 您可以创建自己的自定义限定符注释。只需定义一个注释并在定义中提供@Qualifier注释:
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Genre {
String value();
}
Then you can provide the custom qualifier on autowired fields and parameters:
- 然后你可以提供自定义限定在autowired领域和参数:
public class MovieRecommender {
@Autowired
@Genre("Action")
private MovieCatalog actionCatalog;
private MovieCatalog comedyCatalog;
@Autowired
public void setComedyCatalog(@Genre("Comedy") MovieCatalog comedyCatalog) {
this.comedyCatalog = comedyCatalog;
}
// ...
}
Next, provide the information for the candidate bean definitions. You can add <qualifier/>
tags as sub-elements of the <bean/>
tag and then specify the type
and value
to match your custom qualifier annotations. The type is matched against the fully-qualified class name of the annotation. Or, as a convenience if no risk of conflicting names exists, you can use the short class name. Both approaches are demonstrated in the following example.
- 接下来,提供候选bean定义的信息。您可以添加
标记作为 标记的子元素,然后指定类型和值来匹配您的自定义qualifier注释。该类型与注释的全限定类名匹配。或者,为了方便起见(如果不存在名称冲突的风险),您可以使用简短的类名。下面的示例将演示这两种方法。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog">
<qualifier type="Genre" value="Action"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier type="example.Genre" value="Comedy"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>
In Classpath scanning and managed components, you will see an annotation-based alternative to providing the qualifier metadata in XML. Specifically, see Providing qualifier metadata with annotations.
- 在类路径扫描和托管组件中,您将看到以XML提供限定符元数据的基于注释的替代方法。具体地说,请参见提供带有注释的限定符元数据。
In some cases, it may be sufficient to use an annotation without a value. This may be useful when the annotation serves a more generic purpose and can be applied across several different types of dependencies. For example, you may provide an offline catalog that would be searched when no Internet connection is available. First define the simple annotation:
- :在某些情况下,使用没有值的注释就足够了。当注释用于更通用的目的,并且可以跨几种不同类型的依赖项应用时,这可能很有用。例如,您可以提供一个离线目录,当没有可用的Internet连接时将搜索该目录。首先定义简单注释:
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Offline {
}
Then add the annotation to the field or property to be autowired:
- 然后将注释添加到要自动实现的字段或属性:
public class MovieRecommender {
@Autowired
@Offline
private MovieCatalog offlineCatalog;
// ...
}
Now the bean definition only needs a qualifier type
:
- 现在bean定义只需要一个限定符类型:
<bean class="example.SimpleMovieCatalog">
<qualifier type="Offline"/>
<!-- inject any dependencies required by this bean -->
</bean>
You can also define custom qualifier annotations that accept named attributes in addition to or instead of the simple value
attribute. If multiple attribute values are then specified on a field or parameter to be autowired, a bean definition must match all such attribute values to be considered an autowire candidate. As an example, consider the following annotation definition:
- 您还可以定义自定义限定符注释,这些注释除了简单的value属性外,还接受指定的属性。如果在要自动装配的字段或参数上指定了多个属性值,那么bean定义必须匹配所有这些属性值,才能被认为是自动装配的候选者。作为一个例子,考虑下面的注释定义:
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MovieQualifier {
String genre();
Format format();
}
In this case Format
is an enum:
- 在这种情况下,格式是枚举:
public enum Format {
VHS, DVD, BLURAY
}
The fields to be autowired are annotated with the custom qualifier and include values for both attributes: genre
and format
.
- 要自动实现的字段使用自定义限定符进行注释,并包含两个属性的值:genre和format。
public class MovieRecommender {
@Autowired
@MovieQualifier(format=Format.VHS, genre="Action")
private MovieCatalog actionVhsCatalog;
@Autowired
@MovieQualifier(format=Format.VHS, genre="Comedy")
private MovieCatalog comedyVhsCatalog;
@Autowired
@MovieQualifier(format=Format.DVD, genre="Action")
private MovieCatalog actionDvdCatalog;
@Autowired
@MovieQualifier(format=Format.BLURAY, genre="Comedy")
private MovieCatalog comedyBluRayCatalog;
// ...
}
Finally, the bean definitions should contain matching qualifier values. This example also demonstrates that bean meta attributes may be used instead of the <qualifier/>
sub-elements. If available, the <qualifier/>
and its attributes take precedence, but the autowiring mechanism falls back on the values provided within the <meta/>
tags if no such qualifier is present, as in the last two bean definitions in the following example.
- 最后,bean定义应该包含匹配的限定符值。这个例子还演示了可以使用bean元属性来代替
子元素。如果可用, 及其属性优先,但是如果没有这样的限定符,自动装配机制就会回到标签中提供的值上,如下面的例子中最后两个bean定义所示。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog">
<qualifier type="MovieQualifier">
<attribute key="format" value="VHS"/>
<attribute key="genre" value="Action"/>
</qualifier>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier type="MovieQualifier">
<attribute key="format" value="VHS"/>
<attribute key="genre" value="Comedy"/>
</qualifier>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<meta key="format" value="DVD"/>
<meta key="genre" value="Action"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<meta key="format" value="BLURAY"/>
<meta key="genre" value="Comedy"/>
<!-- inject any dependencies required by this bean -->
</bean>
</beans>
1.9.5. Using generics as autowiring qualifiers(使用泛型作为自动装配限定符)
In addition to the @Qualifier
annotation, it is also possible to use Java generic types as an implicit form of qualification. For example, suppose you have the following configuration:
- 除了@Qualifier注释之外,还可以使用Java泛型类型作为一种隐式限定形式。例如,假设您有以下配置:
@Configuration
public class MyConfiguration {
@Bean
public StringStore stringStore() {
return new StringStore();
}
@Bean
public IntegerStore integerStore() {
return new IntegerStore();
}
}
Assuming that beans above implement a generic interface, i.e. Store<String>
and Store<Integer>
, you can @Autowire
the Store
interface and the generic will be used as a qualifier:
- 假设上面的bean实现了一个通用接口,即Store
和Store ,您可以@Autowire Store接口,该通用将用作一个限定符:
@Autowired
private Store<String> s1; // <String> qualifier, injects the stringStore bean
@Autowired
private Store<Integer> s2; // <Integer> qualifier, injects the integerStore bean
Generic qualifiers also apply when autowiring Lists, Maps and Arrays:
- 泛型限定符也适用于自动装配列表,映射和数组:
// Inject all Store beans as long as they have an <Integer> generic
// Store<String> beans will not appear in this list
@Autowired
private List<Store<Integer>> s;
1.9.6. CustomAutowireConfigurer(定义自动装配置)
The CustomAutowireConfigurer
is a BeanFactoryPostProcessor
that enables you to register your own custom qualifier annotation types even if they are not annotated with Spring’s @Qualifier
annotation.
- customautowiresfigurer是一个BeanFactoryPostProcessor,它允许您注册自己的自定义qualifier注释类型,即使它们没有使用Spring的@Qualifier注释。
<bean id="customAutowireConfigurer"
class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
<property name="customQualifierTypes">
<set>
<value>example.CustomQualifier</value>
</set>
</property>
</bean>
The AutowireCandidateResolver
determines autowire candidates by:
-
- AutowireCandidateResolver通过以下方式确定autowire候选者:
-
the
autowire-candidate
value of each bean definition- 每个bean定义的自动候选值
-
any
default-autowire-candidates
pattern(s) available on the<beans/>
element元素上可用的任何默认自动候选模式
-
the presence of
@Qualifier
annotations and any custom annotations registered with theCustomAutowireConfigurer
- @Qualifier注解和任何在customautowiresfigurer注册的自定义注解的存在
When multiple beans qualify as autowire candidates, the determination of a "primary" is the following: if exactly one bean definition among the candidates has a primary
attribute set to true
, it will be selected.
- 当多个bean符合自动装配候选时,确定“主”的方法如下:如果候选中的一个bean定义的主属性被设置为true,那么它将被选择。
1.9.7. @Resource
Spring also supports injection using the JSR-250 @Resource
annotation on fields or bean property setter methods. This is a common pattern in Java EE 5 and 6, for example in JSF 1.2 managed beans or JAX-WS 2.0 endpoints. Spring supports this pattern for Spring-managed objects as well.
- Spring还支持在字段或bean属性设置器方法上使用JSR-250 @Resource注释进行注入。这是Java EE 5和6中的常见模式,例如在JSF 1.2托管bean或JAX-WS 2.0端点中。Spring也为Spring管理的对象支持此模式。****
@Resource
takes a name attribute, and by default Spring interprets that value as the bean name to be injected. In other words, it follows by-name semantics, as demonstrated in this example:
- @Resource接受一个name属性,默认情况下,Spring将该值解释为要注入的bean名。换句话说,它遵循了名称语义,如下例所示:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Resource(name="myMovieFinder")
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
If no name is specified explicitly, the default name is derived from the field name or setter method. In case of a field, it takes the field name; in case of a setter method, it takes the bean property name. So the following example is going to have the bean with name "movieFinder" injected into its setter method:
- 如果没有显式指定名称,则默认名称派生自字段名称或setter方法。如果是字段,它采用字段名;对于setter方法,它采用bean属性名。因此,下面的例子将把名为“movieFinder”的bean注入到它的setter方法中:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Resource
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
The name provided with the annotation is resolved as a bean name by the ApplicationContext of which the CommonAnnotationBeanPostProcessor is aware. The names can be resolved through JNDI if you configure Spring’s SimpleJndiBeanFactory explicitly. However, it is recommended that you rely on the default behavior and simply use Spring’s JNDI lookup capabilities to preserve the level of indirection. |
|
---|---|
- 随注释提供的名称由CommonAnnotationBeanPostProcessor感知的ApplicationContext解析为一个bean名称。如果显式配置Spring的SimpleJndiBeanFactory,则可以通过JNDI解析名称。但是,建议您依赖于默认行为,并简单地使用Spring的JNDI查找功能来保持间接级别。
In the exclusive case of @Resource
usage with no explicit name specified, and similar to @Autowired
, @Resource
finds a primary type match instead of a specific named bean and resolves well-known resolvable dependencies: the BeanFactory
, ApplicationContext
, ResourceLoader
, ApplicationEventPublisher
, and MessageSource
interfaces.
- 在使用@Resource没有指定显式名称的独占情况下,类似于@Autowired, @Resource找到一个主类型匹配而不是一个特定的命名bean,并解析众所周知的可解析依赖项:BeanFactory, ApplicationContext, ResourceLoader, ApplicationEventPublisher,和MessageSource接口。
Thus in the following example, the customerPreferenceDao
field first looks for a bean named customerPreferenceDao, then falls back to a primary type match for the type CustomerPreferenceDao
. The "context" field is injected based on the known resolvable dependency type ApplicationContext
.
- 此,在下例中,customerPreferenceDao字段首先查找名为customerPreferenceDao的bean,然后返回到与customerPreferenceDao类型匹配的主类型。“上下文”字段是基于已知的可解析依赖类型ApplicationContext注入的。
public class MovieRecommender {
@Resource
private CustomerPreferenceDao customerPreferenceDao;
@Resource
private ApplicationContext context;
public MovieRecommender() {
}
// ...
}
1.9.8. @PostConstruct and @PreDestroy
The CommonAnnotationBeanPostProcessor
not only recognizes the @Resource
annotation but also the JSR-250 lifecycle annotations. Introduced in Spring 2.5, the support for these annotations offers yet another alternative to those described in initialization callbacks and destruction callbacks. Provided that the CommonAnnotationBeanPostProcessor
is registered within the Spring ApplicationContext
, a method carrying one of these annotations is invoked at the same point in the lifecycle as the corresponding Spring lifecycle interface method or explicitly declared callback method. In the example below, the cache will be pre-populated upon initialization and cleared upon destruction.
- CommonAnnotationBeanPostProcessor不仅可以识别@Resource注释,还可以识别JSR-250生命周期注释。Spring 2.5中引入的对这些注释的支持提供了另一种选择,可以替代初始化回调和销毁回调中描述的那些注释。如果在Spring ApplicationContext中注册了CommonAnnotationBeanPostProcessor,那么在生命周期中与对应的Spring生命周期接口方法或显式声明的回调方法在同一点调用携带这些注释之一的方法。在下面的示例中,缓存将在初始化时预填充,在销毁时清除。
public class CachingMovieLister {
@PostConstruct
public void populateMovieCache() {
// populates the movie cache upon initialization...
}
@PreDestroy
public void clearMovieCache() {
// clears the movie cache upon destruction...
}
}
For details about the effects of combining various lifecycle mechanisms, see Combining lifecycle mechanisms. | |
---|---|
- 有关组合各种生命周期机制的效果的详细信息,请参见组合生命周期机制。
1.10. Classpath scanning and managed components(类路径扫描和托管组件)
Most examples in this chapter use XML to specify the configuration metadata that produces each BeanDefinition
within the Spring container. The previous section (Annotation-based container configuration) demonstrates how to provide a lot of the configuration metadata through source-level annotations. Even in those examples, however, the "base" bean definitions are explicitly defined in the XML file, while the annotations only drive the dependency injection. This section describes an option for implicitly detecting the candidate components by scanning the classpath. Candidate components are classes that match against a filter criteria and have a corresponding bean definition registered with the container. This removes the need to use XML to perform bean registration; instead you can use annotations (for example @Component
), AspectJ type expressions, or your own custom filter criteria to select which classes will have bean definitions registered with the container.
- 本章中的大多数示例使用XML指定在Spring容器中生成每个BeanDefinition的配置元数据。上一节(基于注释的容器配置)演示了如何通过源代码级注释提供大量配置元数据。然而,即使在这些示例中,“基本”bean定义也显式地定义在XML文件中,而注释仅驱动依赖项注入。本节描述通过扫描类路径隐式检测候选组件的选项。候选组件是与筛选标准匹配的类,并有相应的bean定义注册到容器中。这样就不需要使用XML来执行bean注册;相反,您可以使用注释(例如@Component)、AspectJ类型表达式或您自己的自定义筛选标准来选择哪些类将bean定义注册到容器中。
Starting with Spring 3.0, many features provided by the Spring JavaConfig project are part of the core Spring Framework. This allows you to define beans using Java rather than using the traditional XML files. Take a look at the @Configuration , @Bean , @Import , and @DependsOn annotations for examples of how to use these new features. |
|
---|---|
- 从Spring 3.0开始,Spring JavaConfig项目提供的许多特性都是核心Spring框架的一部分。这允许您使用Java而不是传统的XML文件定义bean。查看@Configuration、@Bean、@Import和@DependsOn注释,了解如何使用这些新特性。
1.10.1. @Component and further stereotype annotations(组件和进一步的原型注释)
The @Repository
annotation is a marker for any class that fulfills the role or stereotype of a repository (also known as Data Access Object or DAO). Among the uses of this marker is the automatic translation of exceptions as described in Exception translation.
- @Repository注释是满足存储库角色或构造型的任何类的标记(也称为数据访问对象或DAO)。该标记的使用包括异常翻译中描述的异常自动转换。
Spring provides further stereotype annotations: @Component
, @Service
, and @Controller
. @Component
is a generic stereotype for any Spring-managed component. @Repository
, @Service
, and @Controller
are specializations of @Component
for more specific use cases, for example, in the persistence, service, and presentation layers, respectively. Therefore, you can annotate your component classes with @Component
, but by annotating them with @Repository
, @Service
, or @Controller
instead, your classes are more properly suited for processing by tools or associating with aspects. For example, these stereotype annotations make ideal targets for pointcuts. It is also possible that @Repository
, @Service
, and @Controller
may carry additional semantics in future releases of the Spring Framework. Thus, if you are choosing between using @Component
or @Service
for your service layer, @Service
is clearly the better choice. Similarly, as stated above, @Repository
is already supported as a marker for automatic exception translation in your persistence layer.
- Spring提供了进一步的构造型注解:@Component, @Service和@Controller。@Component是任何spring管理组件的通用原型。@Repository、@Service和@Controller是@Component针对更具体用例的专门化,例如,分别在持久性、服务和表示层中。因此,您可以使用@Component来注释组件类,但是通过使用@Repository、@Service或@Controller来注释它们,您的类更适合通过工具进行处理或与方面关联。例如,这些构造型注释是切入点的理想目标。@Repository、@Service和@Controller也可能在Spring框架的未来版本中附带额外的语义。因此,如果您要在您的服务层使用@Component或@Service之间进行选择,那么@Service显然是更好的选择。类似地,如上所述,@Repository已经被支持作为持久化层中自动异常转换的标记。
1.10.2. Meta-annotations(原注解)
Many of the annotations provided by Spring can be used as meta-annotations in your own code. A meta-annotation is simply an annotation that can be applied to another annotation. For example, the @Service
annotation mentioned above is meta-annotated with @Component
:
- Spring提供的许多注释都可以在您自己的代码中用作元注释。元注释只是可以应用于另一个注释的注释。例如,上面提到的@Service注释是用@Component元注释的:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // Spring will see this and treat @Service in the same way as @Component
public @interface Service {
// ....
}
Meta-annotations can also be combined to create composed annotations. For example, the @RestController
annotation from Spring MVC is composed of @Controller
and @ResponseBody
.
- 元注释还可以组合起来创建组合注释。例如,Spring MVC的@RestController注释由@Controller和@ResponseBody组成。
In addition, composed annotations may optionally redeclare attributes from meta-annotations to allow user customization. This can be particularly useful when you want to only expose a subset of the meta-annotation’s attributes. For example, Spring’s @SessionScope
annotation hardcodes the scope name to session
but still allows customization of the proxyMode
.
- 此外,组合注释可以选择重新声明元注释的属性,以允许用户定制。当您只想公开元注释属性的一个子集时,这可能特别有用。例如,Spring的@SessionScope注释将作用域名称硬编码为session,但仍然允许定制proxyMode。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Scope(WebApplicationContext.SCOPE_SESSION)
public @interface SessionScope {
/**
* Alias for {@link Scope#proxyMode}.
* <p>Defaults to {@link ScopedProxyMode#TARGET_CLASS}.
*/
@AliasFor(annotation = Scope.class)
ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}
@SessionScope
can then be used without declaring the proxyMode
as follows:
- @SessionScope可以不用声明proxyMode,如下所示:
@Service
@SessionScope
public class SessionScopedService {
// ...
}
Or with an overridden value for the proxyMode
as follows:
- 或者为proxyMode设置如下覆盖值:
@Service
@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)
public class SessionScopedUserService implements UserService {
// ...
}
For further details, consult the Spring Annotation Programming Model wiki page.
- 要了解更多细节,请参考Spring Annotation编程模型wiki页面。
1.10.3. Automatically detecting classes and registering bean definitions(自动检测类并注册bean定义)
Spring can automatically detect stereotyped classes and register corresponding BeanDefinition
s with the ApplicationContext
. For example, the following two classes are eligible for such autodetection:
- Spring可以自动检测原型类,并将相应的beandefinition注册到ApplicationContext中。例如,以下两个类符合这种自动检测的条件:
@Service
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
@Repository
public class JpaMovieFinder implements MovieFinder {
// implementation elided for clarity
}
To autodetect these classes and register the corresponding beans, you need to add @ComponentScan
to your @Configuration
class, where the basePackages
attribute is a common parent package for the two classes. (Alternatively, you can specify a comma/semicolon/space-separated list that includes the parent package of each class.)
- 要自动检测这些类并注册相应的bean,您需要将@ComponentScan添加到您的@Configuration类中,其中basePackages属性是这两个类的公共父包。(或者,您可以指定一个逗号/分号/空格分隔的列表,其中包含每个类的父包。)
@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig {
...
}
For concision, the above may have used the value attribute of the annotation, i.e. @ComponentScan("org.example") |
|
---|---|
- 为了简洁起见,上面可能使用了注释的value属性,即@ComponentScan("org.example")。
The following is an alternative using XML
- 下面是使用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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.example"/>
</beans>
The use of <context:component-scan> implicitly enables the functionality of <context:annotation-config> . There is usually no need to include the <context:annotation-config> element when using <context:component-scan> . |
|
---|---|
The scanning of classpath packages requires the presence of corresponding directory entries in the classpath. When you build JARs with Ant, make sure that you do not activate the files-only switch of the JAR task. Also, classpath directories may not get exposed based on security policies in some environments, e.g. standalone apps on JDK 1.7.0_45 and higher (which requires 'Trusted-Library' setup in your manifests; see http://stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources).On JDK 9’s module path (Jigsaw), Spring’s classpath scanning generally works as expected. However, please make sure that your component classes are exported in your module-info descriptors; if you expect Spring to invoke non-public members of your classes, make sure that they are 'opened' (i.e. using an opens declaration instead of an exports declaration in your module-info descriptor). |
|
---|---|
-
使用context:component-scan隐式地启用了context:annotation-config的功能。在使用<context: componentent -scan>时,通常不需要包含context:annotation-config元素。
-
类路径包的扫描要求类路径中存在相应的目录项。当您使用Ant构建JAR时,请确保没有激活JAR任务的文件切换。另外,在某些环境中,基于安全策略,类路径目录可能不会暴露出来,例如JDK 1.7.0_45或更高版本的独立应用程序(需要在清单中设置“Trusted-Library”;见http://stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources)。在JDK 9的模块路径(Jigsaw)上,Spring的类路径扫描通常按预期工作。但是,请确保在模块信息描述符中导出组件类;如果您希望Spring调用类的非公共成员,请确保它们是“打开的”(例如,在您的模块信息描述符中使用open声明而不是export声明)。
Furthermore, the AutowiredAnnotationBeanPostProcessor
and CommonAnnotationBeanPostProcessor
are both included implicitly when you use the component-scan element. That means that the two components are autodetected and wired together - all without any bean configuration metadata provided in XML.
- 此外,当您使用组件扫描元素时,AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor都是隐式包含的。这意味着这两个组件是自动检测并连接在一起的——所有这些都不需要XML提供任何bean配置元数据。
You can disable the registration of AutowiredAnnotationBeanPostProcessor and CommonAnnotationBeanPostProcessor by including the annotation-config attribute with a value of false . |
|
---|---|
- 你可以禁用AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor的注册,方法是将注解-配置属性的值设为false。
1.10.4. Using filters to customize scanning(使用过滤器自定义扫描)
By default, classes annotated with @Component
, @Repository
, @Service
, @Controller
, or a custom annotation that itself is annotated with @Component
are the only detected candidate components. However, you can modify and extend this behavior simply by applying custom filters. Add them as includeFilters or excludeFilters parameters of the @ComponentScan
annotation (or as include-filter or exclude-filter sub-elements of the component-scan
element). Each filter element requires the type
and expression
attributes. The following table describes the filtering options.
- 默认情况下,仅检测到用@Component、@Repository、@Service、@Controller注释的类或本身用@Component注释的自定义注释。但是,您可以通过应用自定义过滤器简单地修改和扩展此行为。将它们作为@ComponentScan注释的includeFilters或excludeFilters参数添加(或作为组件扫描元素的include-filter或exclude-filter子元素添加)。每个筛选器元素都需要类型和表达式属性。下表描述了筛选选项。
Filter Type | Example Expression | Description |
---|---|---|
annotation (default) | org.example.SomeAnnotation |
An annotation to be present at the type level in target components.(在目标组件的类型级别上出现的注释。) |
assignable | org.example.SomeClass |
A class (or interface) that the target components are assignable to (extend/implement).(目标组件可分配给(扩展/实现)的类(或接口)。) |
aspectj | org.example..*Service+ |
An AspectJ type expression to be matched by the target components.(目标组件匹配的AspectJ类型表达式。) |
regex | org\.example\.Default.* |
A regex expression to be matched by the target components class names.(由目标组件类名匹配的正则表达式。) |
custom | org.example.MyTypeFilter |
A custom implementation of the org.springframework.core.type .TypeFilter interface.(org.springframework.core的自定义实现。类型.TypeFilter”界面。) |
The following example shows the configuration ignoring all @Repository
annotations and using "stub" repositories instead.
- 下面的示例显示了忽略所有@Repository注释并使用“存根”存储库的配置。
@Configuration
@ComponentScan(basePackages = "org.example",
includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
excludeFilters = @Filter(Repository.class))
public class AppConfig {
...
}
and the equivalent using XML(使用XML的等价)
<beans>
<context:component-scan base-package="org.example">
<context:include-filter type="regex"
expression=".*Stub.*Repository"/>
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
</beans>
You can also disable the default filters by setting useDefaultFilters=false on the annotation or providing use-default-filters="false" as an attribute of the <component-scan/> element. This will in effect disable automatic detection of classes annotated with @Component , @Repository , @Service , @Controller , or @Configuration . |
|
---|---|
- 您还可以通过在注释上设置useDefaultFilters=false或提供use-default-filters="false"作为
元素的属性来禁用默认过滤器。这实际上将禁用对带有@Component、@Repository、@Service、@Controller或@Configuration注释的类的自动检测。
1.10.5. Defining bean metadata within components(在组件中定义bean元数据)
Spring components can also contribute bean definition metadata to the container. You do this with the same @Bean
annotation used to define bean metadata within @Configuration
annotated classes. Here is a simple example:
- Spring组件还可以向容器提供bean定义元数据。您可以使用与在@Configuration注释类中定义bean元数据相同的@Bean注释来完成此操作。这里有一个简单的例子:
@Component
public class FactoryMethodComponent {
@Bean
@Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
public void doWork() {
// Component method implementation omitted
}
}
This class is a Spring component that has application-specific code contained in its doWork()
method. However, it also contributes a bean definition that has a factory method referring to the method publicInstance()
. The @Bean
annotation identifies the factory method and other bean definition properties, such as a qualifier value through the @Qualifier
annotation. Other method level annotations that can be specified are @Scope
, @Lazy
, and custom qualifier annotations.
- 这个类是一个Spring组件,它的doWork()方法中包含特定于应用程序的代码。但是,它也提供了一个bean定义,其中有一个引用方法publicInstance()的工厂方法。@Bean注释标识工厂方法和其他bean定义属性,例如通过@Qualifier注释标识的限定符值。可以指定的其他方法级注释是@Scope、@Lazy和自定义限定符注释。
In addition to its role for component initialization, the @Lazy annotation may also be placed on injection points marked with @Autowired or @Inject . In this context, it leads to the injection of a lazy-resolution proxy. |
|
---|---|
- 除了用于组件初始化的角色外,@Lazy注释还可以放在用@Autowired或@Inject标记的注入点上。在这个上下文中,它会导致注入一个延迟解析代理。
Autowired fields and methods are supported as previously discussed, with additional support for autowiring of @Bean
methods:
- 如前所述,支持自动生成的字段和方法,另外还支持@Bean方法的自动生成:
@Component
public class FactoryMethodComponent {
private static int i;
@Bean
@Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
// use of a custom qualifier and autowiring of method parameters
@Bean
protected TestBean protectedInstance(
@Qualifier("public") TestBean spouse,
@Value("#{privateInstance.age}") String country) {
TestBean tb = new TestBean("protectedInstance", 1);
tb.setSpouse(spouse);
tb.setCountry(country);
return tb;
}
@Bean
private TestBean privateInstance() {
return new TestBean("privateInstance", i++);
}
@Bean
@RequestScope
public TestBean requestScopedInstance() {
return new TestBean("requestScopedInstance", 3);
}
}
The example autowires the String
method parameter country
to the value of the age
property on another bean named privateInstance
. A Spring Expression Language element defines the value of the property through the notation #{ <expression> }
. For @Value
annotations, an expression resolver is preconfigured to look for bean names when resolving expression text.
- 该示例将字符串方法参数country自动转换为另一个名为privateInstance的bean上的age属性的值。Spring Expression语言元素通过符号#{< Expression >}定义属性的值。对于@Value注释,表达式解析器被预先配置为在解析表达式文本时查找bean名称。
As of Spring Framework 4.3, you may also declare a factory method parameter of type InjectionPoint
(or its more specific subclass DependencyDescriptor
) in order to access the requesting injection point that triggers the creation of the current bean. Note that this will only apply to the actual creation of bean instances, not to the injection of existing instances. As a consequence, this feature makes most sense for beans of prototype scope. For other scopes, the factory method will only ever see the injection point which triggered the creation of a new bean instance in the given scope: for example, the dependency that triggered the creation of a lazy singleton bean. Use the provided injection point metadata with semantic care in such scenarios.
- 在Spring Framework 4.3中,您还可以声明一个类型为InjectionPoint的工厂方法参数(或者它更具体的子类DependencyDescriptor),以便访问触发当前bean创建的请求注入点。注意,这只适用于bean实例的实际创建,而不适用于现有实例的注入。因此,这个特性对原型范围的bean最有意义。对于其他范围,工厂方法只会看到在给定范围内触发新bean实例创建的注入点:例如,触发惰性单例bean创建的依赖项。在这样的场景中使用提供的注入点元数据,并注意语义。
@Component
public class FactoryMethodComponent {
@Bean @Scope("prototype")
public TestBean prototypeInstance(InjectionPoint injectionPoint) {
return new TestBean("prototypeInstance for " + injectionPoint.getMember());
}
}
The @Bean
methods in a regular Spring component are processed differently than their counterparts inside a Spring @Configuration
class. The difference is that @Component
classes are not enhanced with CGLIB to intercept the invocation of methods and fields. CGLIB proxying is the means by which invoking methods or fields within @Bean
methods in @Configuration
classes creates bean metadata references to collaborating objects; such methods are not invoked with normal Java semantics but rather go through the container in order to provide the usual lifecycle management and proxying of Spring beans even when referring to other beans via programmatic calls to @Bean
methods. In contrast, invoking a method or field in an @Bean
method within a plain @Component
class has standard Java semantics, with no special CGLIB processing or other constraints applying.
- 常规Spring组件中的@Bean方法与Spring @Configuration类中的对应方法处理方式不同。区别在于@Component类没有通过CGLIB增强来拦截方法和字段的调用。CGLIB代理是通过调用@Configuration类中@Bean方法中的方法或字段来创建对协作对象的bean元数据引用的方法;这样的方法不是用普通的Java语义调用的,而是通过容器来提供通常的生命周期管理和Spring bean的代理,即使在通过编程调用@Bean方法引用其他bean时也是如此。相反,在普通的@Component类中调用@Bean方法中的方法或字段具有标准的Java语义,不应用特殊的CGLIB处理或其他约束。
You may declare @Bean methods as static , allowing for them to be called without creating their containing configuration class as an instance. This makes particular sense when defining post-processor beans, e.g. of type BeanFactoryPostProcessor or BeanPostProcessor , since such beans will get initialized early in the container lifecycle and should avoid triggering other parts of the configuration at that point.Note that calls to static @Bean methods will never get intercepted by the container, not even within @Configuration classes (see above). This is due to technical limitations: CGLIB subclassing can only override non-static methods. As a consequence, a direct call to another @Bean method will have standard Java semantics, resulting in an independent instance being returned straight from the factory method itself.The Java language visibility of @Bean methods does not have an immediate impact on the resulting bean definition in Spring’s container. You may freely declare your factory methods as you see fit in non-@Configuration classes and also for static methods anywhere. However, regular @Bean methods in @Configuration classes need to be overridable, i.e. they must not be declared as private or final .@Bean methods will also be discovered on base classes of a given component or configuration class, as well as on Java 8 default methods declared in interfaces implemented by the component or configuration class. This allows for a lot of flexibility in composing complex configuration arrangements, with even multiple inheritance being possible through Java 8 default methods as of Spring 4.2.Finally, note that a single class may hold multiple @Bean methods for the same bean, as an arrangement of multiple factory methods to use depending on available dependencies at runtime. This is the same algorithm as for choosing the "greediest" constructor or factory method in other configuration scenarios: The variant with the largest number of satisfiable dependencies will be picked at construction time, analogous to how the container selects between multiple @Autowired constructors. |
|
---|---|
- 您可以将@Bean方法声明为静态的,允许在不将其包含的配置类创建为实例的情况下调用它们。这在定义后处理器bean时特别有意义,例如类型为BeanFactoryPostProcessor或BeanPostProcessor的bean,因为这样的bean将在容器生命周期的早期得到初始化,应该避免在此时触发配置的其他部分。注意,对静态@Bean方法的调用永远不会被容器拦截,甚至在@Configuration类中也不会(见上面)。这是由于技术上的限制:CGLIB子类化只能覆盖非静态方法。因此,对另一个@Bean方法的直接调用将具有标准的Java语义,从而导致直接从工厂方法本身返回一个独立的实例。Java语言中@Bean方法的可见性对Spring s容器中生成的bean定义没有直接影响。您可以自由地在non-@Configuration类中声明您的工厂方法,也可以在任何地方声明静态方法。但是,@Configuration类中的常规@Bean方法需要被重写,也就是说,它们不能被声明为private或final。@Bean方法也会在给定组件或配置类的基类中被发现,在组件或配置类实现的接口中声明的Java 8默认方法也是如此。这为组合复杂配置安排提供了很大的灵活性,甚至可以通过Spring 4.2中的Java 8默认方法实现多重继承。最后,请注意,一个类可能为同一个bean保留多个@Bean方法,这是一个在运行时根据可用依赖项使用的多个工厂方法的安排。这与在其他配置场景中选择“贪婪的”构造函数或工厂方法的算法是相同的:可满足依赖关系最多的变量将在构建时选择,类似于容器在多个@Autowired构造函数之间进行选择。
1.10.6. Naming autodetected components(命名个组件)
When a component is autodetected as part of the scanning process, its bean name is generated by the BeanNameGenerator
strategy known to that scanner. By default, any Spring stereotype annotation (@Component
, @Repository
, @Service
, and @Controller
) that contains a name value
will thereby provide that name to the corresponding bean definition.
- 当一个组件作为扫描过程的一部分被自动检测时,它的bean名称是由扫描器知道的BeanNameGenerator策略生成的。默认情况下,任何包含name值的Spring原型注释(@Component, @Repository, @Service,和@Controller)将因此将该名称提供给相应的bean定义。
If such an annotation contains no name value
or for any other detected component (such as those discovered by custom filters), the default bean name generator returns the uncapitalized non-qualified class name. For example, if the following component classes were detected, the names would be myMovieLister
and movieFinderImpl
:
- 如果这样的注释不包含任何名称值,或者不包含任何其他检测到的组件(比如那些由自定义过滤器发现的组件),那么默认的bean名称生成器将返回未大写且不合格的类名。例如,如果检测到以下组件类,名称将是myMovieLister和movieFinderImpl:
@Service("myMovieLister")
public class SimpleMovieLister {
// ...
}
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
If you do not want to rely on the default bean-naming strategy, you can provide a custom bean-naming strategy. First, implement the BeanNameGenerator interface, and be sure to include a default no-arg constructor. Then, provide the fully-qualified class name when configuring the scanner: |
|
---|---|
- 如果不希望依赖默认的bean命名策略,可以提供自定义bean命名策略。首先,实现BeanNameGenerator接口,并确保包含默认的无参数构造函数。然后,在配置扫描器时提供完全限定的类名:
@Configuration
@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)
public class AppConfig {
...
}
<beans>
<context:component-scan base-package="org.example"
name-generator="org.example.MyNameGenerator" />
</beans>
As a general rule, consider specifying the name with the annotation whenever other components may be making explicit references to it. On the other hand, the auto-generated names are adequate whenever the container is responsible for wiring.
- 作为一般规则,当其他组件可能显式地引用该注释时,请考虑使用该注释指定名称。另一方面,只要容器负责连接,自动生成的名称就足够了。
1.10.7. Providing a scope for autodetected components(为自动检测的组件提供范围)
As with Spring-managed components in general, the default and most common scope for autodetected components is singleton
. However, sometimes you need a different scope which can be specified via the @Scope
annotation. Simply provide the name of the scope within the annotation:
- 与一般的spring管理组件一样,自动检测组件的默认和最常见的作用域是singleton。但是,有时您需要通过@Scope注释指定不同的作用域。只需在注释中提供作用域的名称:
@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
@Scope annotations are only introspected on the concrete bean class (for annotated components) or the factory method (for @Bean methods). In contrast to XML bean definitions, there is no notion of bean definition inheritance, and inheritance hierarchies at the class level are irrelevant for metadata purposes. |
|
---|---|
- @Scope注释仅在具体bean类(对于带注释的组件)或工厂方法(对于@Bean方法)上自省。与XML bean定义相反,不存在bean定义继承的概念,而且类级别的继承层次结构与元数据目的无关。
For details on web-specific scopes such as "request"/"session" in a Spring context, see Request, session, application, and WebSocket scopes. Like the pre-built annotations for those scopes, you may also compose your own scoping annotations using Spring’s meta-annotation approach: e.g. a custom annotation meta-annotated with @Scope("prototype")
, possibly also declaring a custom scoped-proxy mode.
- 有关特定于web的作用域的详细信息,如在Spring上下文中的“请求”/“会话”,请参阅请求、会话、应用程序和WebSocket作用域。与为这些作用域预先构建的注释一样,您也可以使用Spring的元注释方法来编写自己的作用域注释:例如,使用@Scope(“prototype”)注释的自定义注释元注释,也可能声明一个自定义作用域-代理模式。
To provide a custom strategy for scope resolution rather than relying on the annotation-based approach, implement the ScopeMetadataResolver interface, and be sure to include a default no-arg constructor. Then, provide the fully-qualified class name when configuring the scanner: |
|
---|---|
- 要为范围解析提供自定义策略,而不是依赖于基于注释的方法,请实现ScopeMetadataResolver接口,并确保包含默认的无参数构造函数。然后,在配置扫描器时提供完全限定的类名:
@Configuration
@ComponentScan(basePackages = "org.example", scopeResolver = MyScopeResolver.class)
public class AppConfig {
...
}
<beans>
<context:component-scan base-package="org.example" scope-resolver="org.example.MyScopeResolver"/>
</beans>
When using certain non-singleton scopes, it may be necessary to generate proxies for the scoped objects. The reasoning is described in Scoped beans as dependencies. For this purpose, a scoped-proxy attribute is available on the component-scan element. The three possible values are: no, interfaces, and targetClass. For example, the following configuration will result in standard JDK dynamic proxies:
- 在使用某些非单例作用域时,可能需要为作用域对象生成代理。其原因在作用域bean中描述为依赖关系。为此,component-scan元素上有一个作用域代理属性。三个可能的值是:no、interface和targetClass。例如,以下配置将导致标准JDK动态代理:
@Configuration
@ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)
public class AppConfig {
...
}
<beans>
<context:component-scan base-package="org.example" scoped-proxy="interfaces"/>
</beans>
1.10.8. Providing qualifier metadata with annotations(提供带有注释的限定符元数据)
The @Qualifier
annotation is discussed in Fine-tuning annotation-based autowiring with qualifiers. The examples in that section demonstrate the use of the @Qualifier
annotation and custom qualifier annotations to provide fine-grained control when you resolve autowire candidates. Because those examples were based on XML bean definitions, the qualifier metadata was provided on the candidate bean definitions using the qualifier
or meta
sub-elements of the bean
element in the XML. When relying upon classpath scanning for autodetection of components, you provide the qualifier metadata with type-level annotations on the candidate class. The following three examples demonstrate this technique:
- @Qualifier注解将在基于注释的微调自动装配限定符中讨论。这一节中的示例演示了@Qualifier注释和custom qualifier注释的使用,以在解析自动装配候选时提供细粒度的控制。因为这些示例基于XML bean定义,所以限定符元数据是使用XML中bean元素的限定符或元子元素在候选bean定义上提供的。当依赖于类路径扫描来自动检测组件时,您可以在候选类上提供带有类型级别注释的限定符元数据。下面的三个示例演示了这种技术
@Component
@Qualifier("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
}
@Component
@Genre("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
}
@Component
@Offline
public class CachingMovieCatalog implements MovieCatalog {
// ...
}
As with most annotation-based alternatives, keep in mind that the annotation metadata is bound to the class definition itself, while the use of XML allows for multiple beans of the same type to provide variations in their qualifier metadata, because that metadata is provided per-instance rather than per-class. | |
---|---|
- 与大多数基于注释的替代方法一样,请记住,注释元数据绑定到类定义本身,而XML的使用允许相同类型的多个bean在其限定符元数据中提供变体,因为元数据是按实例而不是按类提供的。
1.10.9. Generating an index of candidate components(生成候选组件的索引)
While classpath scanning is very fast, it is possible to improve the startup performance of large applications by creating a static list of candidates at compilation time. In this mode, all modules of the application must use this mechanism as, when the ApplicationContext
detects such index, it will automatically use it rather than scanning the classpath.(虽然类路径扫描非常快,但是可以通过在编译时创建一个静态候选列表来提高大型应用程序的启动性能。在这种模式下,应用程序的所有模块都必须使用这种机制,因为当ApplicationContext检测到这样的索引时,它将自动使用它,而不是扫描类路径。)
To generate the index, simply add an additional dependency to each module that contains components that are target for component scan directives:
- 要生成索引,只需向每个模块添加额外的依赖项,该模块包含组件扫描指令的目标组件:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-indexer</artifactId>
<version>5.0.8.RELEASE</version>
<optional>true</optional>
</dependency>
</dependencies>
Or, using Gradle:(或者,使用它:)
dependencies {
compileOnly("org.springframework:spring-context-indexer:5.0.8.RELEASE")
}
That process will generate a META-INF/spring.components
file that is going to be included in the jar.
- 该过程将生成一个META-INF/spring.components文件,该文件将包含在jar中。
When working with this mode in your IDE, the spring-context-indexer must be registered as an annotation processor to make sure the index is up to date when candidate components are updated. |
|
---|---|
The index is enabled automatically when a META-INF/spring.components is found on the classpath. If an index is partially available for some libraries (or use cases) but couldn’t be built for the whole application, you can fallback to a regular classpath arrangement (i.e. as no index was present at all) by setting spring.index.ignore to true , either as a system property or in a spring.properties file at the root of the classpath. |
|
---|---|
-
在IDE中使用此模式时,必须将spring-context-indexer注册为注释处理程序,以确保在更新候选组件时索引是最新的。
-
当在类路径中找到META-INF/spring.components时,索引会自动启用。如果某个索引对某些库(或用例)是部分可用的,但不能为整个应用程序构建,那么通过设置spring.index,你可以回到常规的类路径安排(即根本没有索引)。忽略为真,无论是作为系统属性还是在spring中。属性文件位于类路径的根。
1.11. Using JSR 330 Standard Annotations(使用JSR 330标准注释)
Starting with Spring 3.0, Spring offers support for JSR-330 standard annotations (Dependency Injection). Those annotations are scanned in the same way as the Spring annotations. You just need to have the relevant jars in your classpath.
- 从Spring 3.0开始,Spring提供了对JSR-330标准注解(依赖注入)的支持。这些注释的扫描方式与Spring注释相同。您只需要在类路径中包含相关的jar。
If you are using Maven, the javax.inject artifact is available in the standard Maven repository ( http://repo1.maven.org/maven2/javax/inject/javax.inject/1/). You can add the following dependency to your file pom.xml:<dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency> |
|
---|---|
- 如果您正在使用Maven,则使用javax。注入构件可以在标准Maven存储库中获得(http://repo1.maven.org/maven2/javax/inject/javax.inject/1/)。您可以将以下依赖项添加到您的文件pom.xml
1.11.1. Dependency Injection with @Inject and @Named(使用@Inject和@Named进行依赖注入)
Instead of @Autowired
, @javax.inject.Inject
may be used as follows:
- @javax.inject代替@Autowired。注射可以使用如下:
import javax.inject.Inject;
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Inject
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
public void listMovies() {
this.movieFinder.findMovies(...);
...
}
}
As with @Autowired
, it is possible to use @Inject
at the field level, method level and constructor-argument level. Furthermore, you may declare your injection point as a Provider
, allowing for on-demand access to beans of shorter scopes or lazy access to other beans through a Provider.get()
call. As a variant of the example above:
- 与@Autowired一样,可以在字段级、方法级和构造参数级使用@Inject。此外,您可以将注入点声明为提供者,从而允许按需访问作用域较短的bean,或者通过Provider.get()调用延迟访问其他bean。作为上述例子的一种变体:
import javax.inject.Inject;
import javax.inject.Provider;
public class SimpleMovieLister {
private Provider<MovieFinder> movieFinder;
@Inject
public void setMovieFinder(Provider<MovieFinder> movieFinder) {
this.movieFinder = movieFinder;
}
public void listMovies() {
this.movieFinder.get().findMovies(...);
...
}
}
If you would like to use a qualified name for the dependency that should be injected, you should use the @Named
annotation as follows:
- 如果您想为要注入的依赖项使用一个限定名,您应该使用@Named注释,如下所示:
import javax.inject.Inject;
import javax.inject.Named;
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Inject
public void setMovieFinder(@Named("main") MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
Like @Autowired
, @Inject
can also be used with java.util.Optional
or @Nullable
. This is even more applicable here since @Inject
does not have a required
attribute.
- 与@Autowired一样,@Inject也可以与java.util一起使用。可选或@Nullable。这在这里甚至更适用,因为@Inject没有required属性。
public class SimpleMovieLister {
@Inject
public void setMovieFinder(Optional<MovieFinder> movieFinder) {
...
}
}
public class SimpleMovieLister {
@Inject
public void setMovieFinder(@Nullable MovieFinder movieFinder) {
...
}
}
1.11.2. @Named and @ManagedBean: standard equivalents to the @Component annotation(@Named和@ManagedBean:与@Component注释的标准等价物)
Instead of @Component
, @javax.inject.Named
or javax.annotation.ManagedBean
may be used as follows:
- nstead of @Component, @javax.inject。或javax.annotation命名。ManagedBean的使用方式如下:
import javax.inject.Inject;
import javax.inject.Named;
@Named("movieListener") // @ManagedBean("movieListener") could be used as well
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Inject
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
It is very common to use @Component
without specifying a name for the component. @Named
can be used in a similar fashion:
- 在不指定组件名称的情况下使用@Component是很常见的。@Named也可以以类似的方式使用:
import javax.inject.Inject;
import javax.inject.Named;
@Named
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Inject
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
When using @Named
or @ManagedBean
, it is possible to use component scanning in the exact same way as when using Spring annotations:
- 当使用@Named或@ManagedBean时,可以使用与使用Spring注释完全相同的方式来使用组件扫描:
@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig {
...
}
In contrast to @Component , the JSR-330 @Named and the JSR-250 ManagedBean annotations are not composable. Please use Spring’s stereotype model for building custom component annotations. |
|
---|---|
- 与@Component相反,JSR-330 @Named和JSR-250 ManagedBean注释是不可组合的。请使用Spring的原型模型来构建定制的组件注解。
1.11.3. Limitations of JSR-330 standard annotations(JSR-330标准注释的限制)
When working with standard annotations, it is important to know that some significant features are not available as shown in the table below:
- 当使用标准注释时,需要知道一些重要的特性是不可用的,如下表所示:
Spring | javax.inject.* | javax.inject restrictions / comments |
---|---|---|
@Autowired | @Inject | @Inject has no 'required' attribute; can be used with Java 8’s Optional instead. |
@Component | @Named / @ManagedBean | JSR-330 does not provide a composable model, just a way to identify named components. |
@Scope("singleton") | @Singleton | The JSR-330 default scope is like Spring’s prototype . However, in order to keep it consistent with Spring’s general defaults, a JSR-330 bean declared in the Spring container is a singleton by default. In order to use a scope other than singleton , you should use Spring’s @Scope annotation. javax.inject also provides a @Scope annotation. Nevertheless, this one is only intended to be used for creating your own annotations. |
@Qualifier | @Qualifier / @Named | javax.inject.Qualifier is just a meta-annotation for building custom qualifiers. Concrete String qualifiers (like Spring’s @Qualifier with a value) can be associated through javax.inject.Named . |
@Value | - | no equivalent |
@Required | - | no equivalent |
@Lazy | - | no equivalent |
ObjectFactory | Provider | javax.inject.Provider is a direct alternative to Spring’s ObjectFactory , just with a shorter get() method name. It can also be used in combination with Spring’s @Autowired or with non-annotated constructors and setter methods. |
1.12. Java-based container configuration(基于java的容器配置)
1.12.1. Basic concepts: @Bean and @Configuration(基本概念:@Bean和@Configuration)
The central artifacts in Spring’s new Java-configuration support are @Configuration
-annotated classes and @Bean
-annotated methods.
- Spring的新的java配置支持中的核心构件是@ configuration注释的类和@ bean注释的方法。
The @Bean
annotation is used to indicate that a method instantiates, configures and initializes a new object to be managed by the Spring IoC container. For those familiar with Spring’s <beans/>
XML configuration the @Bean
annotation plays the same role as the <bean/>
element. You can use @Bean
annotated methods with any Spring @Component
, however, they are most often used with @Configuration
beans.
- @Bean注释用于指示方法实例化、配置和初始化将由Spring IoC容器管理的新对象。对于那些熟悉Spring的
XML配置的人来说,@Bean注释扮演着与 元素相同的角色。您可以对任何Spring @Component使用@Bean注释的方法,但是,它们最常与@Configuration bean一起使用。
Annotating a class with @Configuration
indicates that its primary purpose is as a source of bean definitions. Furthermore, @Configuration
classes allow inter-bean dependencies to be defined by simply calling other @Bean
methods in the same class. The simplest possible @Configuration
class would read as follows:
- 用@Configuration注释类表明它的主要用途是作为bean定义的源。此外,@Configuration类允许通过调用同一个类中的其他@Bean方法来定义bean间的依赖关系。最简单的@Configuration类如下所示:
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
}
The AppConfig
class above would be equivalent to the following Spring <beans/>
XML:
- 上面的AppConfig类将相当于下面的Spring
XML:
<beans>
<bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>
Full @Configuration vs 'lite' @Bean mode?
When @Bean
methods are declared within classes that are not annotated with @Configuration
they are referred to as being processed in a 'lite' mode. Bean methods declared in a @Component
or even in a plain old class will be considered 'lite', with a different primary purpose of the containing class and an @Bean
method just being a sort of bonus there. For example, service components may expose management views to the container through an additional @Bean
method on each applicable component class. In such scenarios, @Bean
methods are a simple general-purpose factory method mechanism.
- 当@Bean方法在没有使用@Configuration注释的类中声明时,它们被称为在“lite”模式下处理。在@Component甚至普通旧类中声明的Bean方法将被认为是“lite”,因为包含类的主要目的不同,而@Bean方法只是一种奖励而已。例如,服务组件可以通过每个适用组件类上的附加@Bean方法向容器公开管理视图。在这种情况下,@Bean方法是一种简单的通用工厂方法机制。
Unlike full @Configuration
, lite @Bean
methods cannot declare inter-bean dependencies. Instead, they operate on their containing component’s internal state and optionally on arguments that they may declare. Such an @Bean
method should therefore not invoke other @Bean
methods; each such method is literally just a factory method for a particular bean reference, without any special runtime semantics. The positive side-effect here is that no CGLIB subclassing has to be applied at runtime, so there are no limitations in terms of class design (i.e. the containing class may nevertheless be final
etc).
- 与完整的@Configuration不同,lite @Bean方法不能声明bean之间的依赖关系。相反,它们对包含它们的组件的内部状态进行操作,并可选地对它们可能声明的参数进行操作。因此,这样的@Bean方法不应该调用其他@Bean方法;每个这样的方法字面上只是一个特定bean引用的工厂方法,没有任何特殊的运行时语义。这样做的正面副作用是,在运行时不需要应用CGLIB子类,所以在类设计方面没有限制(例如,包含的类可能是final等)
In common scenarios, @Bean
methods are to be declared within @Configuration
classes, ensuring that 'full' mode is always used and that cross-method references will therefore get redirected to the container’s lifecycle management. This will prevent the same @Bean
method from accidentally being invoked through a regular Java call which helps to reduce subtle bugs that can be hard to track down when operating in 'lite' mode.
- 在常见的场景中,@Bean方法将在@Configuration类中声明,以确保始终使用“full”模式,并因此将跨方法引用重定向到容器的生命周期管理。这将防止同一个@Bean方法被常规Java调用意外调用,这有助于减少在“lite”模式下操作时难以跟踪的细微bug。
The @Bean
and @Configuration
annotations will be discussed in depth in the sections below. First, however, we’ll cover the various ways of creating a spring container using Java-based configuration.
- @Bean和@Configuration注释将在下面的部分中进行深入讨论。但是,首先,我们将介绍使用基于java的配置创建spring容器的各种方法
1.12.2. Instantiating the Spring container using AnnotationConfigApplicationContext(使用AnnotationConfigApplicationContext实例化Spring容器)
The sections below document Spring’s AnnotationConfigApplicationContext
, new in Spring 3.0. This versatile ApplicationContext
implementation is capable of accepting not only @Configuration
classes as input, but also plain @Component
classes and classes annotated with JSR-330 metadata.
- 下面的小节记录了Spring 3.0中新添加的AnnotationConfigApplicationContext。这个通用的ApplicationContext实现不仅能够接受@Configuration类作为输入,还能够接受普通的@Component类和用JSR-330元数据注释的类。
When @Configuration
classes are provided as input, the @Configuration
class itself is registered as a bean definition, and all declared @Bean
methods within the class are also registered as bean definitions.
- 当提供@Configuration类作为输入时,@Configuration类本身被注册为bean定义,类中声明的所有@Bean方法也被注册为bean定义。
When @Component
and JSR-330 classes are provided, they are registered as bean definitions, and it is assumed that DI metadata such as @Autowired
or @Inject
are used within those classes where necessary.
- 当提供了@Component和JSR-330类时,它们被注册为bean定义,并且假设在需要时在这些类中使用DI元数据,如@Autowired或@Inject。
Simple construction(结构简介)
In much the same way that Spring XML files are used as input when instantiating a ClassPathXmlApplicationContext
, @Configuration
classes may be used as input when instantiating an AnnotationConfigApplicationContext
. This allows for completely XML-free usage of the Spring container:
- 与实例化ClassPathXmlApplicationContext时使用Spring XML文件作为输入的方式非常相似,在实例化AnnotationConfigApplicationContext时可以使用@Configuration类作为输入。这允许Spring容器完全无xml的使用:
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
As mentioned above, AnnotationConfigApplicationContext
is not limited to working only with @Configuration
classes. Any @Component
or JSR-330 annotated class may be supplied as input to the constructor. For example:
- :如上所述,AnnotationConfigApplicationContext并不局限于只处理@Configuration类。任何@Component或JSR-330注释类都可以作为输入提供给构造函数。例如:
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
The above assumes that MyServiceImpl
, Dependency1
and Dependency2
use Spring dependency injection annotations such as @Autowired
.
- 上面假设MyServiceImpl、Dependency1和Dependency2使用Spring依赖注入注释,如@Autowired。
Building the container programmatically using register(Class…)(使用register以编程方式构建容器(Class…)
An AnnotationConfigApplicationContext
may be instantiated using a no-arg constructor and then configured using the register()
method. This approach is particularly useful when programmatically building an AnnotationConfigApplicationContext
.
- 可以使用无参数构造函数实例化AnnotationConfigApplicationContext,然后使用register()方法进行配置。当以编程方式构建AnnotationConfigApplicationContext时,这种方法特别有用。
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class, OtherConfig.class);
ctx.register(AdditionalConfig.class);
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
Enabling component scanning with scan(String…) (使用scan启用组件扫描(字符串…)
To enable component scanning, just annotate your @Configuration
class as follows:
- 要启用组件扫描,只需按如下方式注释您的@Configuration类:
@Configuration
@ComponentScan(basePackages = "com.acme")
public class AppConfig {
...
}
Experienced Spring users will be familiar with the XML declaration equivalent from Spring’s context: namespace<beans> <context:component-scan base-package="com.acme"/> </beans> |
|
---|---|
- 有经验的Spring用户应该熟悉Spring上下文中的等价XML声明:名称空间
In the example above, the com.acme
package will be scanned, looking for any @Component
-annotated classes, and those classes will be registered as Spring bean definitions within the container. AnnotationConfigApplicationContext
exposes the scan(String…)
method to allow for the same component-scanning functionality:
- 在上面的例子中,com。acme包将被扫描,寻找任何@ component注释的类,这些类将被注册为容器内的Spring bean定义。AnnotationConfigApplicationContext暴露了scan(String…)方法,允许相同的组件扫描功能:
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("com.acme");
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
}
Remember that @Configuration classes are meta-annotated with @Component , so they are candidates for component-scanning! In the example above, assuming that AppConfig is declared within the com.acme package (or any package underneath), it will be picked up during the call to scan() , and upon refresh() all its @Bean methods will be processed and registered as bean definitions within the container. |
|
---|---|
- 请记住,@Configuration类是用@Component进行元注释的,因此它们是组件扫描的候选对象!在上面的示例中,假设AppConfig是在com中声明的。acme包(或下面的任何包),它将在调用scan()期间被拾取,在refresh()时,它的所有@Bean方法将被处理并在容器中注册为bean定义。
Support for web applications with AnnotationConfigWebApplicationContext(支持带有注释的web应用程序
A WebApplicationContext
variant of AnnotationConfigApplicationContext
is available with AnnotationConfigWebApplicationContext
. This implementation may be used when configuring the Spring ContextLoaderListener
servlet listener, Spring MVC DispatcherServlet
, etc. What follows is a web.xml
snippet that configures a typical Spring MVC web application. Note the use of the contextClass
context-param and init-param:
- AnnotationConfigApplicationContext的WebApplicationContext变体可以通过AnnotationConfigWebApplicationContext获得。这个实现可以在配置Spring ContextLoaderListener servlet监听器、Spring MVC DispatcherServlet等时使用。下面是一个web.xml代码片段,它配置了一个典型的Spring MVC web应用程序。注意contextClass上下文参数和init参数的使用:
<web-app>
<!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<!-- Configuration locations must consist of one or more comma- or space-delimited
fully-qualified @Configuration classes. Fully-qualified packages may also be
specified for component-scanning -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.acme.AppConfig</param-value>
</context-param>
<!-- Bootstrap the root application context as usual using ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Declare a Spring MVC DispatcherServlet as usual -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<!-- Again, config locations must consist of one or more comma- or space-delimited
and fully-qualified @Configuration classes -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.acme.web.MvcConfig</param-value>
</init-param>
</servlet>
<!-- map all requests for /app/* to the dispatcher servlet -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>
1.12.3. Using the @Bean annotation(使用@Bean注释)
@Bean
is a method-level annotation and a direct analog of the XML <bean/>
element. The annotation supports some of the attributes offered by <bean/>
, such as: init-method, destroy-method, autowiring and name
.
- @Bean是一个方法级注释,是XML
元素的直接模拟。该注释支持 提供的一些属性,如:init-method、destroy-method、自动装配和名称。
You can use the @Bean
annotation in a @Configuration
-annotated or in a @Component
-annotated class.
- 您可以在注释了@ configuration或注释了@ component的类中使用@Bean注释。
Declaring a bean(声明一个bean)
To declare a bean, simply annotate a method with the @Bean
annotation. You use this method to register a bean definition within an ApplicationContext
of the type specified as the method’s return value. By default, the bean name will be the same as the method name. The following is a simple example of a @Bean
method declaration:
- 要声明一个bean,只需用@Bean注释注释一个方法。您可以使用此方法在一个ApplicationContext中注册一个指定为方法返回值的类型的bean定义。默认情况下,bean名称将与方法名称相同。下面是一个简单的@Bean方法声明示例:
@Configuration
public class AppConfig {
@Bean
public TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
The preceding configuration is exactly equivalent to the following Spring XML:
- 前面的配置与下面的Spring XML完全相同:
<beans>
<bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>
Both declarations make a bean named transferService
available in the ApplicationContext
, bound to an object instance of type TransferServiceImpl
:
- 这两个声明都使一个名为transferService的bean在ApplicationContext中可用,它绑定到一个类型为TransferServiceImpl的对象实例:
transferService -> com.acme.TransferServiceImpl
You may also declare your @Bean
method with an interface (or base class) return type:
- 你也可以用一个接口(或基类)返回类型来声明你的@Bean方法:
@Configuration
public class AppConfig {
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
However, this limits the visibility for advance type prediction to the specified interface type (TransferService
) then, with the full type (TransferServiceImpl
) only known to the container once the affected singleton bean has been instantiated. Non-lazy singleton beans get instantiated according to their declaration order, so you may see different type matching results depending on when another component tries to match by a non-declared type (such as @Autowired TransferServiceImpl
which will only resolve once the "transferService" bean has been instantiated).
- 然而,这将预先类型预测的可见性限制为指定的接口类型(TransferService),只有在实例化了受影响的单例bean之后,容器才知道完整的类型(TransferServiceImpl)。非惰性的单例bean根据它们的声明顺序被实例化,所以您可能会看到不同的类型匹配结果,这取决于其他组件何时尝试用一个未声明的类型进行匹配(例如@Autowired TransferServiceImpl,它只会在实例化了“transferService”bean之后才会解析)。
If you consistently refer to your types by a declared service interface, your @Bean return types may safely join that design decision. However, for components implementing several interfaces or for components potentially referred to by their implementation type, it is safer to declare the most specific return type possible (at least as specific as required by the injection points referring to your bean). |
|
---|---|
- 如果您始终通过声明的服务接口引用您的类型,那么您的@Bean返回类型可以安全地加入设计决策。但是,对于实现多个接口的组件,或者对于可能由其实现类型引用的组件,声明可能最特定的返回类型(至少与引用bean的注入点所要求的特定程度相同)更为安全。
Bean dependencies(Bean的依赖关系)
A @Bean
annotated method can have an arbitrary number of parameters describing the dependencies required to build that bean. For instance if our TransferService
requires an AccountRepository
we can materialize that dependency via a method parameter:
- 带@Bean注释的方法可以有任意数量的参数,用于描述构建该bean所需的依赖关系。例如,如果我们的TransferService需要AccountRepository,我们可以通过一个方法参数来实现这个依赖:
@Configuration
public class AppConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
The resolution mechanism is pretty much identical to constructor-based dependency injection, see the relevant section for more details.
- 解析机制与基于构造器的依赖项注入几乎相同,更多细节请参阅相关部分。
Receiving lifecycle callbacks(接受生命周期回调)
Any classes defined with the @Bean
annotation support the regular lifecycle callbacks and can use the @PostConstruct
and @PreDestroy
annotations from JSR-250, see JSR-250 annotations for further details.
- 任何用@Bean注释定义的类都支持常规的生命周期回调,并且可以使用JSR-250注释中的@PostConstruct和@PreDestroy注释,更多细节请参阅JSR-250注释。
The regular Spring lifecycle callbacks are fully supported as well. If a bean implements InitializingBean
, DisposableBean
, or Lifecycle
, their respective methods are called by the container.
- 常规的Spring生命周期回调也得到了完全支持。如果一个bean实现了InitializingBean、DisposableBean或Lifecycle,容器将调用它们各自的方法。
The standard set of *Aware
interfaces such as BeanFactoryAware, BeanNameAware, MessageSourceAware, ApplicationContextAware, and so on are also fully supported.
- 标准的感知接口集,如BeanFactoryAware、BeanNameAware、MessageSourceAware、applicationcontext taware等,也得到了完全的支持。
The @Bean
annotation supports specifying arbitrary initialization and destruction callback methods, much like Spring XML’s init-method
and destroy-method
attributes on the bean
element:
- @Bean注释支持指定任意的初始化和销毁回调方法,很像Spring XML在bean元素上的init-method和destroy-method属性:
public class Foo {
public void init() {
// initialization logic
}
}
public class Bar {
public void cleanup() {
// destruction logic
}
}
@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public Foo foo() {
return new Foo();
}
@Bean(destroyMethod = "cleanup")
public Bar bar() {
return new Bar();
}
}
By default, beans defined using Java config that have a public close or shutdown method are automatically enlisted with a destruction callback. If you have a public close or shutdown method and you do not wish for it to be called when the container shuts down, simply add @Bean(destroyMethod="") to your bean definition to disable the default (inferred) mode.((((默认情况下,使用Java config定义的具有公共关闭或关闭方法的bean将与销毁回调一起自动征用。如果您有一个公共的关闭或关闭方法,并且不希望在容器关闭时调用它,那么只需在bean定义中添加@Bean(destroyMethod="")来禁用默认的(inferred)模式。)))))You may want to do that by default for a resource that you acquire via JNDI as its lifecycle is managed outside the application. In particular, make sure to always do it for a DataSource as it is known to be problematic on Java EE application servers.((默认情况下,你可能想对通过JNDI获得的资源这样做,因为它的生命周期是在应用程序之外管理的。特别是,确保始终对数据源执行此操作,因为在Java EE应用程序服务器上它是有问题的。)))@Bean(destroyMethod="") public DataSource dataSource() throws NamingException { return (DataSource) jndiTemplate.lookup("MyDS"); } Also, with @Bean methods, you will typically choose to use programmatic JNDI lookups: either using Spring’s JndiTemplate /JndiLocatorDelegate helpers or straight JNDI InitialContext usage, but not the JndiObjectFactoryBean variant which would force you to declare the return type as the FactoryBean type instead of the actual target type, making it harder to use for cross-reference calls in other @Bean methods that intend to refer to the provided resource here.((((交响乐团,@ bean方法,你通常会选择使用程序化的JNDI查找:直接使用Spring的JndiTemplate / JndiLocatorDelegate助手或者JNDI InitialContext使用,但不是JndiObjectFactoryBean变体这将迫使你声明返回类型作为FactoryBean类型,而不是实际的目标类型,因此很难使用交叉引用调用@ bean方法,打算在其他参考所提供的资源。))) |
|
---|---|
Of course, in the case of Foo
above, it would be equally as valid to call the init()
method directly during construction:
- 然,在上述Foo的情况下,在构造过程中直接调用init()方法同样有效:
@Configuration
public class AppConfig {
@Bean
public Foo foo() {
Foo foo = new Foo();
foo.init();
return foo;
}
// ...
}
When you work directly in Java, you can do anything you like with your objects and do not always need to rely on the container lifecycle! | |
---|---|
- 当您直接在Java中工作时,您可以对对象做任何您喜欢的事情,而不总是需要依赖容器的生命周期!
Specifying bean scope(指定bean范围)
Using the @Scope annotation(使用@Scope注释)
You can specify that your beans defined with the @Bean
annotation should have a specific scope. You can use any of the standard scopes specified in the Bean Scopes section.
- 可以指定用@Bean注释定义的bean应该具有特定的范围。您可以使用Bean作用域部分中指定的任何标准作用域。
The default scope is singleton
, but you can override this with the @Scope
annotation:
- 默认的作用域是singleton,但是你可以用@Scope注释覆盖它:
@Configuration
public class MyConfiguration {
@Bean
@Scope("prototype")
public Encryptor encryptor() {
// ...
}
}
@Scope and scoped-proxy(范围和作用域内的代理)
Spring offers a convenient way of working with scoped dependencies through scoped proxies. The easiest way to create such a proxy when using the XML configuration is the <aop:scoped-proxy/>
element. Configuring your beans in Java with a @Scope annotation offers equivalent support with the proxyMode attribute. The default is no proxy ( ScopedProxyMode.NO
), but you can specify ScopedProxyMode.TARGET_CLASS
or ScopedProxyMode.INTERFACES
.
- Spring提供了一种通过作用域代理处理作用域依赖关系的方便方法。在使用XML配置时,创建这样一个代理的最简单方法是aop:作用域代理/元素。用@Scope注释配置Java中的bean可以提供与proxyMode属性同等的支持。默认是没有代理(ScopedProxyMode. no),但是您可以指定ScopedProxyMode。TARGET_CLASS或ScopedProxyMode.INTERFACES。
If you port the scoped proxy example from the XML reference documentation (see preceding link) to our @Bean
using Java, it would look like the following:
- 如果您使用Java将范围代理示例从XML参考文档(参见前面的链接)移植到我们的@Bean,它看起来就像下面这样:
// an HTTP Session-scoped bean exposed as a proxy
@Bean
@SessionScope
public UserPreferences userPreferences() {
return new UserPreferences();
}
@Bean
public Service userService() {
UserService service = new SimpleUserService();
// a reference to the proxied userPreferences bean
service.setUserPreferences(userPreferences());
return service;
}
Customizing bean naming(定制bean命名)
By default, configuration classes use a @Bean
method’s name as the name of the resulting bean. This functionality can be overridden, however, with the name
attribute.
- 默认情况下,配置类使用@Bean方法的名称作为生成的bean的名称。但是,可以使用name属性覆盖此功能。
@Configuration
public class AppConfig {
@Bean(name = "myFoo")
public Foo foo() {
return new Foo();
}
}
Bean aliasing(bean混叠)
As discussed in Naming beans, it is sometimes desirable to give a single bean multiple names, otherwise known as bean aliasing. The name
attribute of the @Bean
annotation accepts a String array for this purpose.
- 正如在命名bean中所讨论的,有时希望给单个bean起多个名称,否则称为bean混叠。为此,@Bean注释的name属性接受一个字符串数组。
@Configuration
public class AppConfig {
@Bean(name = { "dataSource", "subsystemA-dataSource", "subsystemB-dataSource" })
public DataSource dataSource() {
// instantiate, configure and return DataSource bean...
}
}
Bean description (Bean描述)
Sometimes it is helpful to provide a more detailed textual description of a bean. This can be particularly useful when beans are exposed (perhaps via JMX) for monitoring purposes.
- 有时,提供bean的更详细的文本描述是有帮助的。当为了监视目的而公开bean(可能通过JMX)时,这可能特别有用。
To add a description to a @Bean
the @Description
annotation can be used:
- 要向@Bean添加描述,可以使用@Description注释:
@Configuration
public class AppConfig {
@Bean
@Description("Provides a basic example of a bean")
public Foo foo() {
return new Foo();
}
}
1.12.4. Using the @Configuration annotation(使用@Configuration注释)
@Configuration
is a class-level annotation indicating that an object is a source of bean definitions. @Configuration
classes declare beans via public @Bean
annotated methods. Calls to @Bean
methods on @Configuration
classes can also be used to define inter-bean dependencies. See Basic concepts: @Bean and @Configuration for a general introduction.
- @Configuration是一个类级注释,指示对象是bean定义的源。@Configuration类通过公共的@Bean注释方法声明bean。在@Configuration类上调用@Bean方法也可以用来定义bean间的依赖关系。有关一般介绍,请参阅基本概念:@Bean和@Configuration。
Injecting inter-bean dependencies(注入inter-bean依赖性)
When @Bean
s have dependencies on one another, expressing that dependency is as simple as having one bean method call another:
- 当@ bean相互依赖时,表达这种依赖就像让一个bean方法调用另一个bean方法一样简单:
@Configuration
public class AppConfig {
@Bean
public Foo foo() {
return new Foo(bar());
}
@Bean
public Bar bar() {
return new Bar();
}
}
In the example above, the foo
bean receives a reference to bar
via constructor injection.
- 在上面的例子中,foo bean通过构造函数注入接收到bar的引用。
This method of declaring inter-bean dependencies only works when the @Bean method is declared within a @Configuration class. You cannot declare inter-bean dependencies using plain @Component classes. |
|
---|---|
- 只有在@Bean方法在@Configuration类中声明时,这种声明bean间依赖关系的方法才有效。不能使用纯@Component类声明bean之间的依赖关系。
Lookup method injection(查找方法注入)
As noted earlier, lookup method injection is an advanced feature that you should use rarely. It is useful in cases where a singleton-scoped bean has a dependency on a prototype-scoped bean. Using Java for this type of configuration provides a natural means for implementing this pattern.
- 如前所述,查找方法注入是一种高级特性,应该很少使用。在单例作用域bean与原型作用域bean有依赖关系的情况下,它非常有用。将Java用于这种类型的配置提供了一种实现这种模式的自然方法。
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();
}
Using Java-configuration support , you can create a subclass of CommandManager
where the abstract createCommand()
method is overridden in such a way that it looks up a new (prototype) command object:
- 使用java配置支持,你可以创建CommandManager的一个子类,其中抽象的createCommand()方法被重写,这样它会查找一个新的(原型)命令对象:
@Bean
@Scope("prototype")
public AsyncCommand asyncCommand() {
AsyncCommand command = new AsyncCommand();
// inject dependencies here as required
return command;
}
@Bean
public CommandManager commandManager() {
// return new anonymous implementation of CommandManager with command() overridden
// to return a new prototype Command object
return new CommandManager() {
protected Command createCommand() {
return asyncCommand();
}
}
}
Further information about how Java-based configuration works internally(关于基于java的配置如何在内部工作的进一步信息)
The following example shows a @Bean
annotated method being called twice:
- 下面的例子显示了被调用两次的@Bean注释方法:
@Configuration
public class AppConfig {
@Bean
public ClientService clientService1() {
ClientServiceImpl clientService = new ClientServiceImpl();
clientService.setClientDao(clientDao());
return clientService;
}
@Bean
public ClientService clientService2() {
ClientServiceImpl clientService = new ClientServiceImpl();
clientService.setClientDao(clientDao());
return clientService;
}
@Bean
public ClientDao clientDao() {
return new ClientDaoImpl();
}
}
clientDao()
has been called once in clientService1()
and once in clientService2()
. Since this method creates a new instance of ClientDaoImpl
and returns it, you would normally expect having 2 instances (one for each service). That definitely would be problematic: in Spring, instantiated beans have a singleton
scope by default. This is where the magic comes in: All @Configuration
classes are subclassed at startup-time with CGLIB
. In the subclass, the child method checks the container first for any cached (scoped) beans before it calls the parent method and creates a new instance. Note that as of Spring 3.2, it is no longer necessary to add CGLIB to your classpath because CGLIB classes have been repackaged under org.springframework.cglib
and included directly within the spring-core JAR.
- 在clientService1()和clientService2()中分别调用了一次clientDao()。由于此方法创建了ClientDaoImpl的一个新实例并返回它,因此通常需要两个实例(每个服务一个)。这肯定是有问题的:在Spring中,实例化的bean在默认情况下有一个singleton作用域。这就是神奇之处:所有@Configuration类在启动时都由CGLIB生成子类。在子类中,子方法在调用父方法并创建一个新实例之前,首先检查容器是否有缓存的(作用域限定的)bean。注意,从Spring 3.2开始,不再需要将CGLIB添加到类路径中,因为CGLIB类已经在org.springframework下重新打包。并直接包含在spring-core JAR中。
The behavior could be different according to the scope of your bean. We are talking about singletons here. | |
---|---|
There are a few restrictions due to the fact that CGLIB dynamically adds features at startup-time, in particular that configuration classes must not be final. However, as of 4.3, any constructors are allowed on configuration classes, including the use of @Autowired or a single non-default constructor declaration for default injection.If you prefer to avoid any CGLIB-imposed limitations, consider declaring your @Bean methods on non-@Configuration classes, e.g. on plain @Component classes instead. Cross-method calls between @Bean methods won’t get intercepted then, so you’ll have to exclusively rely on dependency injection at the constructor or method level there. |
|
---|---|
-
根据bean的范围,行为可能不同。我们在这里讨论的是单例。
-
由于CGLIB在启动时动态添加特性,因此存在一些限制,特别是配置类不能是最终的。然而,在4.3中,配置类允许使用任何构造函数,包括使用@Autowired或为默认注入使用单一的非默认构造函数声明。如果您希望避免任何cglib强加的限制,可以考虑在非@配置类上声明您的@Bean方法,例如在纯@Component类上声明。这样,@Bean方法之间的交叉方法调用就不会被拦截,因此您将不得不在构造函数或方法级别上独家依赖于依赖注入。
1.12.5. Composing Java-based configurations(编写基于java的配置)
Using the @Import annotation(使用@Import注释)
Much as the <import/>
element is used within Spring XML files to aid in modularizing configurations, the @Import
annotation allows for loading @Bean
definitions from another configuration class:
- 就像在Spring XML文件中使用
元素来帮助模块化配置一样,@Import注释允许从另一个配置类加载@Bean定义:
@Configuration
public class ConfigA {
@Bean
public A a() {
return new A();
}
}
@Configuration
@Import(ConfigA.class)
public class ConfigB {
@Bean
public B b() {
return new B();
}
}
Now, rather than needing to specify both ConfigA.class
and ConfigB.class
when instantiating the context, only ConfigB
needs to be supplied explicitly:
- 现在,在实例化上下文时,不需要同时指定config .class和config .class,只需要显式地提供ConfigB:
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);
// now both beans A and B will be available...
A a = ctx.getBean(A.class);
B b = ctx.getBean(B.class);
}
This approach simplifies container instantiation, as only one class needs to be dealt with, rather than requiring the developer to remember a potentially large number of @Configuration
classes during construction.
- 这种方法简化了容器实例化,因为只需要处理一个类,而不需要开发人员在构造期间记住可能大量的@Configuration类。
As of Spring Framework 4.2, @Import also supports references to regular component classes, analogous to the AnnotationConfigApplicationContext.register method. This is particularly useful if you’d like to avoid component scanning, using a few configuration classes as entry points for explicitly defining all your components. |
|
---|---|
- 在Spring Framework 4.2中,@Import还支持对常规组件类的引用,类似于注释configapplicationcontext。注册方法。如果您想要避免组件扫描,使用一些配置类作为显式定义所有组件的入口点,这一点特别有用。
Injecting dependencies on imported @Bean definitions(注入导入的@Bean定义的依赖项)
The example above works, but is simplistic. In most practical scenarios, beans will have dependencies on one another across configuration classes. When using XML, this is not an issue, per se, because there is no compiler involved, and one can simply declare ref="someBean"
and trust that Spring will work it out during container initialization. Of course, when using @Configuration
classes, the Java compiler places constraints on the configuration model, in that references to other beans must be valid Java syntax.
- 上面的例子是可行的,但是过于简单。在大多数实际场景中,bean将跨配置类相互依赖。在使用XML时,这本身不是问题,因为不涉及编译器,可以简单地声明ref="someBean",并相信Spring会在容器初始化期间解决这个问题。当然,在使用@Configuration类时,Java编译器会对配置模型施加约束,因为对其他bean的引用必须是有效的Java语法。
Fortunately, solving this problem is simple. As we already discussed, @Bean
method can have an arbitrary number of parameters describing the bean dependencies. Let’s consider a more real-world scenario with several @Configuration
classes, each depending on beans declared in the others:
- 幸运的是,解决这个问题很简单。正如我们已经讨论过的,@Bean方法可以有任意数量的描述bean依赖关系的参数。让我们考虑一个更真实的场景,有几个@Configuration类,每个类都依赖于其他类中声明的bean:
@Configuration
public class ServiceConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
@Configuration
public class RepositoryConfig {
@Bean
public AccountRepository accountRepository(DataSource dataSource) {
return new JdbcAccountRepository(dataSource);
}
}
@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {
@Bean
public DataSource dataSource() {
// return new DataSource
}
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
// everything wires up across configuration classes...
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
There is another way to achieve the same result. Remember that @Configuration
classes are ultimately just another bean in the container: This means that they can take advantage of @Autowired
and @Value
injection etc just like any other bean!
- 还有另一种方法可以达到同样的效果。请记住,@Configuration类最终只是容器中的另一个bean:这意味着它们可以像任何其他bean一样利用@Autowired和@Value注入等等!
Make sure that the dependencies you inject that way are of the simplest kind only. @Configuration classes are processed quite early during the initialization of the context and forcing a dependency to be injected this way may lead to unexpected early initialization. Whenever possible, resort to parameter-based injection as in the example above.Also, be particularly careful with BeanPostProcessor and BeanFactoryPostProcessor definitions via @Bean . Those should usually be declared as static @Bean methods, not triggering the instantiation of their containing configuration class. Otherwise, @Autowired and @Value won’t work on the configuration class itself since it is being created as a bean instance too early. |
|
---|---|
- 确保以这种方式注入的依赖项只属于最简单的类型。@Configuration类在上下文初始化过程中很早就被处理,强制以这种方式注入依赖项可能会导致意外的早期初始化。只要有可能,就像上面的例子那样使用基于参数的注入。另外,对于通过@Bean定义的BeanPostProcessor和BeanFactoryPostProcessor要特别小心。这些方法通常应该声明为静态的@Bean方法,而不是触发其包含的配置类的实例化。否则,@Autowired和@Value将不能在配置类本身上工作,因为它被过早地创建为一个bean实例。
@Configuration
public class ServiceConfig {
@Autowired
private AccountRepository accountRepository;
@Bean
public TransferService transferService() {
return new TransferServiceImpl(accountRepository);
}
}
@Configuration
public class RepositoryConfig {
private final DataSource dataSource;
@Autowired
public RepositoryConfig(DataSource dataSource) {
this.dataSource = dataSource;
}
@Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository(dataSource);
}
}
@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {
@Bean
public DataSource dataSource() {
// return new DataSource
}
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
// everything wires up across configuration classes...
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
Constructor injection in @Configuration classes is only supported as of Spring Framework 4.3. Note also that there is no need to specify @Autowired if the target bean defines only one constructor; in the example above, @Autowired is not necessary on the RepositoryConfig constructor. |
|
---|---|
- 在Spring Framework 4.3中只支持@Configuration类中的构造函数注入。还要注意的是,如果目标bean只定义了一个构造函数,就没有必要指定@Autowired;在上面的例子中,RepositoryConfig构造函数中不需要使用@Autowired。
Fully-qualifying imported beans for ease of navigation(完全限定导入的bean以方便导航)
In the scenario above, using @Autowired
works well and provides the desired modularity, but determining exactly where the autowired bean definitions are declared is still somewhat ambiguous. For example, as a developer looking at ServiceConfig
, how do you know exactly where the @Autowired AccountRepository
bean is declared? It’s not explicit in the code, and this may be just fine. Remember that the Spring Tool Suite provides tooling that can render graphs showing how everything is wired up - that may be all you need. Also, your Java IDE can easily find all declarations and uses of the AccountRepository
type, and will quickly show you the location of @Bean
methods that return that type.
- 在上面的场景中,使用@Autowired工作得很好并且提供了想要的模块化,但是确定autowired bean定义在哪里声明仍然有点不明确。例如,作为一个正在查看ServiceConfig的开发人员,您如何知道@Autowired AccountRepository bean在哪里声明?这在代码中并不明确,这样可能就可以了。请记住,Spring工具套件提供了一些工具,可以呈现显示如何连接所有内容的图形—这可能就是您所需要的全部。而且,您的Java IDE可以轻松地找到AccountRepository类型的所有声明和使用,并将快速地向您显示返回该类型的@Bean方法的位置。
In cases where this ambiguity is not acceptable and you wish to have direct navigation from within your IDE from one @Configuration
class to another, consider autowiring the configuration classes themselves:
- 如果这种模棱两可是不可接受的,并且你希望在IDE中直接从一个@Configuration类导航到另一个,考虑自动装配配置类本身:
@Configuration
public class ServiceConfig {
@Autowired
private RepositoryConfig repositoryConfig;
@Bean
public TransferService transferService() {
// navigate 'through' the config class to the @Bean method!
return new TransferServiceImpl(repositoryConfig.accountRepository());
}
}
In the situation above, it is completely explicit where AccountRepository
is defined. However, ServiceConfig
is now tightly coupled to RepositoryConfig
; that’s the tradeoff. This tight coupling can be somewhat mitigated by using interface-based or abstract class-based @Configuration
classes. Consider the following:
- 在上述情况下,AccountRepository的定义是完全明确的。但是,ServiceConfig现在与RepositoryConfig紧密耦合;这是一种折衷。这种紧密耦合可以通过使用基于接口或基于抽象类的@Configuration类得到一定程度的缓解。考虑以下:
@Configuration
public class ServiceConfig {
@Autowired
private RepositoryConfig repositoryConfig;
@Bean
public TransferService transferService() {
return new TransferServiceImpl(repositoryConfig.accountRepository());
}
}
@Configuration
public interface RepositoryConfig {
@Bean
AccountRepository accountRepository();
}
@Configuration
public class DefaultRepositoryConfig implements RepositoryConfig {
@Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository(...);
}
}
@Configuration
@Import({ServiceConfig.class, DefaultRepositoryConfig.class}) // import the concrete config!
public class SystemTestConfig {
@Bean
public DataSource dataSource() {
// return DataSource
}
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
Now ServiceConfig
is loosely coupled with respect to the concrete DefaultRepositoryConfig
, and built-in IDE tooling is still useful: it will be easy for the developer to get a type hierarchy of RepositoryConfig
implementations. In this way, navigating @Configuration
classes and their dependencies becomes no different than the usual process of navigating interface-based code.
- 现在ServiceConfig相对于具体的DefaultRepositoryConfig是松散耦合的,而且内置的IDE工具仍然很有用:开发者可以很容易地获得RepositoryConfig实现的类型层次结构。通过这种方式,导航@Configuration类及其依赖项与导航基于接口的代码的通常过程没有什么不同。****
If you would like to influence the startup creation order of certain beans, consider declaring some of them as @Lazy (for creation on first access instead of on startup) or as @DependsOn on certain other beans (making sure that specific other beans will be created before the current bean, beyond what the latter’s direct dependencies imply). |
|
---|---|
- 如果你想影响某些豆类的启动创建订单,考虑将其中一些声明为@Lazy(用于创建在第一次访问,而不是在启动时)或@DependsOn在某些其他bean(确保特定的其他bean创建当前bean之前,超出后者的直接依赖关系暗示)。
Conditionally include @Configuration classes or @Bean methods(有条件地包括@Configuration类或@Bean方法)
It is often useful to conditionally enable or disable a complete @Configuration
class, or even individual @Bean
methods, based on some arbitrary system state. One common example of this is to use the @Profile
annotation to activate beans only when a specific profile has been enabled in the Spring Environment
(see Bean definition profiles for details).
- 根据任意的系统状态,有条件地启用或禁用一个完整的@Configuration类,甚至是单个的@Bean方法,通常是很有用的。一个常见的例子是只有在Spring环境中启用了特定的概要文件时才使用@Profile注释来激活Bean(参见Bean定义概要文件了解详细信息)。
The @Profile
annotation is actually implemented using a much more flexible annotation called @Conditional
. The @Conditional
annotation indicates specific org.springframework.context.annotation.Condition
implementations that should be consulted before a @Bean
is registered.
- @Profile注释实际上是使用名为@Conditional的更加灵活的注释实现的。@Conditional注释表示特定的org.springframework.context.annotation。在注册@Bean之前应该咨询的条件实现。
Implementations of the Condition
interface simply provide a matches(…)
method that returns true
or false
. For example, here is the actual Condition
implementation used for @Profile
:
- 条件接口的实现只提供一个matches(…)方法,该方法返回true或false。例如,下面是用于@Profile的实际条件实现:
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
if (context.getEnvironment() != null) {
// Read the @Profile annotation attributes
MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
if (attrs != null) {
for (Object value : attrs.get("value")) {
if (context.getEnvironment().acceptsProfiles(((String[]) value))) {
return true;
}
}
return false;
}
}
return true;
}
See the @Conditional
javadocs for more detail.(有关更多细节,请参阅@Conditional javadocs。)
Combining Java and XML configuration(结合Java和XML配置)
Spring’s @Configuration
class support does not aim to be a 100% complete replacement for Spring XML. Some facilities such as Spring XML namespaces remain an ideal way to configure the container. In cases where XML is convenient or necessary, you have a choice: either instantiate the container in an "XML-centric" way using, for example, ClassPathXmlApplicationContext
, or in a "Java-centric" fashion using AnnotationConfigApplicationContext
and the @ImportResource
annotation to import XML as needed.
- Spring的@Configuration类支持并不是要完全替代Spring XML。一些工具(如Spring XML名称空间)仍然是配置容器的理想方式。在XML方便或必要的情况下,你有一个选择:要么在容器实例化在一个“以XML为中心”的方式使用,例如,ClassPathXmlApplicationContext或“以java为中心”的方式使用所和@ImportResource注释导入XML。
XML-centric use of @Configuration classes(使用以xml为中心的@Configuration类)
It may be preferable to bootstrap the Spring container from XML and include @Configuration
classes in an ad-hoc fashion. For example, in a large existing codebase that uses Spring XML, it will be easier to create @Configuration
classes on an as-needed basis and include them from the existing XML files. Below you’ll find the options for using @Configuration
classes in this kind of "XML-centric" situation.
- 最好是从XML引导Spring容器,并以特别的方式包含@Configuration类。例如,在使用Spring XML的大型现有代码库中,根据需要创建@Configuration类并从现有XML文件中包含它们会更容易。下面您将看到在这种“以xml为中心”的情况下使用@Configuration类的选项。
Declaring @Configuration classes as plain Spring <bean/>
elements(将@Configuration类声明为普通Spring
Remember that @Configuration
classes are ultimately just bean definitions in the container. In this example, we create a @Configuration
class named AppConfig
and include it within system-test-config.xml
as a <bean/>
definition. Because <context:annotation-config/>
is switched on, the container will recognize the @Configuration
annotation and process the @Bean
methods declared in AppConfig
properly.
- 请记住,@Configuration类最终只是容器中的bean定义。在本例中,我们创建了一个名为AppConfig的@Configuration类,并将其作为
定义包含在system-test-config.xml中。因为context:annotation-config/是打开的,容器将识别@Configuration注释并正确处理在AppConfig中声明的@Bean方法。
@Configuration
public class AppConfig {
@Autowired
private DataSource dataSource;
@Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository(dataSource);
}
@Bean
public TransferService transferService() {
return new TransferService(accountRepository());
}
}
system-test-config.xml:
<beans>
<!-- enable processing of annotations such as @Autowired and @Configuration -->
<context:annotation-config/>
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
<bean class="com.acme.AppConfig"/>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
jdbc.properties:
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml");
TransferService transferService = ctx.getBean(TransferService.class);
// ...
}
In system-test-config.xml above, the AppConfig <bean/> does not declare an id element. While it would be acceptable to do so, it is unnecessary given that no other bean will ever refer to it, and it is unlikely that it will be explicitly fetched from the container by name. Likewise with the DataSource bean - it is only ever autowired by type, so an explicit bean id is not strictly required. |
|
---|---|
- 在上面的system-test-config.xml中,AppConfig
没有声明id元素。虽然这样做是可以接受的,但是没有必要这样做,因为没有其他bean会引用它,而且不太可能通过名称显式地从容器中获取它。与DataSource bean类似——它只是根据类型自动生成的,因此显式bean id不是严格要求的。
Using context:component-scan/ to pick up @Configuration
classes (使用context:component-scan/获取@Configuration类)
Because @Configuration
is meta-annotated with @Component
, @Configuration
-annotated classes are automatically candidates for component scanning. Using the same scenario as above, we can redefine system-test-config.xml
to take advantage of component-scanning. Note that in this case, we don’t need to explicitly declare <context:annotation-config/>
, because <context:component-scan/>
enables the same functionality.
- 因为@Configuration是用@Component元注释的,所以带有@Configuration注释的类是组件扫描的自动候选者。使用与上面相同的场景,我们可以重新定义system-test-config.xml,以利用组件扫描的优势。注意,在本例中,我们不需要显式地声明<context:annotation-config/>,因为<context:component-scan/>启用相同的功能
system-test-config.xml:
<beans>
<!-- picks up and registers AppConfig as a bean definition -->
<context:component-scan base-package="com.acme"/>
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
@Configuration class-centric use of XML with @ImportResource
In applications where @Configuration
classes are the primary mechanism for configuring the container, it will still likely be necessary to use at least some XML. In these scenarios, simply use @ImportResource
and define only as much XML as is needed. Doing so achieves a "Java-centric" approach to configuring the container and keeps XML to a bare minimum.
- 在以@Configuration类作为配置容器的主要机制的应用程序中,仍然可能需要使用至少一些XML。在这些场景中,只需使用@ImportResource并只定义所需的XML即可。这样做可以实现一种“以java为中心”的方法来配置容器,并将XML保持在最低限度。
@Configuration
@ImportResource("classpath:/com/acme/properties-config.xml")
public class AppConfig {
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource() {
return new DriverManagerDataSource(url, username, password);
}
}
properties-config.xml
<beans>
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
</beans>
jdbc.properties
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
TransferService transferService = ctx.getBean(TransferService.class);
// ...
}
1.13. Environment abstraction(环境抽象)
The Environment
is an abstraction integrated in the container that models two key aspects of the application environment: profiles and properties.
- 环境是集成在容器中的抽象,它为应用程序环境的两个关键方面建模:概要文件和属性。
A profile is a named, logical group of bean definitions to be registered with the container only if the given profile is active. Beans may be assigned to a profile whether defined in XML or via annotations. The role of the Environment
object with relation to profiles is in determining which profiles (if any) are currently active, and which profiles (if any) should be active by default.
- 概要文件是一个命名的bean定义逻辑组,只有在给定的概要文件处于活动状态时才向容器注册。bean可以被分配给一个配置文件,无论这个配置文件是在XML中定义的还是通过注释定义的。与概要文件相关的Environment对象的作用是确定哪些概要文件(如果有的话)当前处于活动状态,以及默认情况下哪些概要文件(如果有的话)应该处于活动状态。
Properties play an important role in almost all applications, and may originate from a variety of sources: properties files, JVM system properties, system environment variables, JNDI, servlet context parameters, ad-hoc Properties objects, Maps, and so on. The role of the Environment
object with relation to properties is to provide the user with a convenient service interface for configuring property sources and resolving properties from them.
- 属性在几乎所有的应用程序中都扮演着重要的角色,并且可以来自各种来源:属性文件、JVM系统属性、系统环境变量、JNDI、servlet上下文参数、特别属性对象、映射等等。与属性相关的环境对象的作用是为用户提供一个方便的服务接口,用于配置属性源和从属性源解析属性。
1.13.1. Bean definition profiles(Bean定义概要文件)
Bean definition profiles is a mechanism in the core container that allows for registration of different beans in different environments. The word environment can mean different things to different users and this feature can help with many use cases, including:
-
- Bean定义概要文件是核心容器中的一种机制,它允许在不同的环境中注册不同的Bean。对于不同的用户,环境这个词可能意味着不同的东西,这个特性可以帮助很多用例,包括:
-
working against an in-memory datasource in development vs looking up that same datasource from JNDI when in QA or production
- 在开发中使用内存中的数据源vs在QA或生产中从JNDI查找相同的数据源
-
registering monitoring infrastructure only when deploying an application into a performance environment
- 仅在将应用程序部署到性能环境中时才注册监视基础设施
-
registering customized implementations of beans for customer A vs. customer B deployments
- 为客户A和客户B部署注册定制的bean实现
Let’s consider the first use case in a practical application that requires a DataSource
. In a test environment, the configuration may look like this:
- 让我们考虑需要数据源的实际应用程序中的第一个用例。在测试环境中,配置可能像这样:
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("my-schema.sql")
.addScript("my-test-data.sql")
.build();
}
Let’s now consider how this application will be deployed into a QA or production environment, assuming that the datasource for the application will be registered with the production application server’s JNDI directory. Our dataSource
bean now looks like this:
- 现在让我们考虑如何将该应用程序部署到QA或生产环境中,假设应用程序的数据源将注册到生产应用程序服务器的JNDI目录中。我们的数据源bean现在看起来像这样:
@Bean(destroyMethod="")
public DataSource dataSource() throws Exception {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
The problem is how to switch between using these two variations based on the current environment. Over time, Spring users have devised a number of ways to get this done, usually relying on a combination of system environment variables and XML <import/>
statements containing ${placeholder}
tokens that resolve to the correct configuration file path depending on the value of an environment variable. Bean definition profiles is a core container feature that provides a solution to this problem.
- 问题是如何根据当前环境在使用这两种变体之间切换。随着时间的推移,Spring用户已经设计了许多方法来实现这一点,通常依赖于系统环境变量和XML import/>包含${占位符}标记的语句,根据环境变量的值解析为正确的配置文件路径。Bean定义概要文件是为这个问题提供解决方案的核心容器特性
If we generalize the example use case above of environment-specific bean definitions, we end up with the need to register certain bean definitions in certain contexts, while not in others. You could say that you want to register a certain profile of bean definitions in situation A, and a different profile in situation B. Let’s first see how we can update our configuration to reflect this need.
- :如果我们一般化上面环境特定bean定义的示例用例,我们最终需要在特定上下文中注册特定bean定义,而不是在其他上下文中。您可以说,您希望在情形a中注册某个bean定义的概要文件,在情形b中注册一个不同的概要文件。让我们首先看看如何更新配置以反映这一需求。
@Profile(配置文件)
The @Profile
annotation allows you to indicate that a component is eligible for registration when one or more specified profiles are active. Using our example above, we can rewrite the dataSource
configuration as follows:
- 当一个或多个指定的概要文件处于活动状态时,@Profile注释允许您指示组件有资格注册。使用上面的例子,我们可以重写数据源配置如下:
@Configuration
@Profile("development")
public class StandaloneDataConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.addScript("classpath:com/bank/config/sql/test-data.sql")
.build();
}
}
@Configuration
@Profile("production")
public class JndiDataConfig {
@Bean(destroyMethod="")
public DataSource dataSource() throws Exception {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
}
As mentioned before, with @Bean methods, you will typically choose to use programmatic JNDI lookups: either using Spring’s JndiTemplate /JndiLocatorDelegate helpers or the straight JNDI InitialContext usage shown above, but not the JndiObjectFactoryBean variant which would force you to declare the return type as the FactoryBean type. |
|
---|---|
- @ bean方法,如前所述,您通常会选择使用程序化的JNDI查找:使用Spring的JndiTemplate / JndiLocatorDelegate助手或直接使用JNDI InitialContext如上所示,但不是JndiObjectFactoryBean变体这将迫使你声明返回类型作为FactoryBean类型。
@Profile
can be used as a meta-annotation for the purpose of creating a custom composed annotation. The following example defines a custom @Production
annotation that can be used as a drop-in replacement for @Profile("production")
:
- @Profile可以用作元注释,用于创建定制的组合注释。下面的例子定义了一个自定义的@Production注释,可以作为@Profile(“production”)的临时替代:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Profile("production")
public @interface Production {
}
If a @Configuration class is marked with @Profile , all of the @Bean methods and @Import annotations associated with that class will be bypassed unless one or more of the specified profiles are active. If a @Component or @Configuration class is marked with @Profile({"p1", "p2"}) , that class will not be registered/processed unless profiles 'p1' and/or 'p2' have been activated. If a given profile is prefixed with the NOT operator (! ), the annotated element will be registered if the profile is not active. For example, given @Profile({"p1", "!p2"}) , registration will occur if profile 'p1' is active or if profile 'p2' is not active. |
|
---|---|
- 如果一个@Configuration类被标记为@Profile,那么所有与该类关联的@Bean方法和@Import注释都将被绕过,除非一个或多个指定的概要文件是活动的。如果一个@Component或@Configuration类被标记为@Profile({"p1", "p2"}),那么这个类将不会被注册/处理,除非配置文件'p1'和/或'p2'已经被激活。如果给定的概要文件以NOT操作符(!)作为前缀,那么在概要文件不活动的情况下,注释元素将被注册。例如,给定@Profile({“p1”,“!p2”}),如果配置文件“p1”是活动的,或者配置文件“p2”不是活动的,就会进行注册。
@Profile
can also be declared at the method level to include only one particular bean of a configuration class, e.g. for alternative variants of a particular bean:
- 也可以在方法级别声明,以只包含配置类的一个特定bean,例如一个特定bean的可选变体:
@Configuration
public class AppConfig {
@Bean("dataSource")
@Profile("development")
public DataSource standaloneDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.addScript("classpath:com/bank/config/sql/test-data.sql")
.build();
}
@Bean("dataSource")
@Profile("production")
public DataSource jndiDataSource() throws Exception {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
}
With @Profile on @Bean methods, a special scenario may apply: In the case of overloaded @Bean methods of the same Java method name (analogous to constructor overloading), an @Profile condition needs to be consistently declared on all overloaded methods. If the conditions are inconsistent, only the condition on the first declaration among the overloaded methods will matter. @Profile can therefore not be used to select an overloaded method with a particular argument signature over another; resolution between all factory methods for the same bean follows Spring’s constructor resolution algorithm at creation time.If you would like to define alternative beans with different profile conditions, use distinct Java method names pointing to the same bean name via the @Bean name attribute, as indicated in the example above. If the argument signatures are all the same (e.g. all of the variants have no-arg factory methods), this is the only way to represent such an arrangement in a valid Java class in the first place (since there can only be one method of a particular name and argument signature). |
|
---|---|
- 对于@Bean方法上的@Profile,可能会应用一种特殊的场景:在重载了相同Java方法名的@Bean方法的情况下(类似于构造函数重载),需要在所有重载的方法上一致地声明一个@Profile条件。如果条件不一致,那么只有重载方法中第一个声明的条件才会起作用。因此,@Profile不能用于选择具有特定参数签名的重载方法;同一个bean的所有工厂方法之间的解析在创建时遵循Spring构造函数解析算法。如果您想定义具有不同配置文件条件的可选bean,可以使用不同的Java方法名称通过@Bean name属性指向相同的bean名称,如上例所示。如果参数签名都是相同的(例如,所有的变体都有无参数工厂方法),这是在一个有效的Java类中首先表示这样一种安排的唯一方法(因为一个特定的名称和参数签名只能有一种方法)。
XML bean definition profiles(XML bean定义配置文件)
The XML counterpart is the profile
attribute of the <beans>
element. Our sample configuration above can be rewritten in two XML files as follows:
- XML对应元素是
元素的profile属性。我们上面的示例配置可以重写为两个XML文件如下:
<beans profile="development"
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="...">
<jdbc:embedded-database id="dataSource">
<jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
<jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>
</jdbc:embedded-database>
</beans>
<beans profile="production"
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="...">
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
</beans>
It is also possible to avoid that split and nest <beans/>
elements within the same file:
- 也可以避免在同一个文件中分割和嵌套
元素:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="...">
<!-- other bean definitions -->
<beans profile="development">
<jdbc:embedded-database id="dataSource">
<jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
<jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>
</jdbc:embedded-database>
</beans>
<beans profile="production">
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
</beans>
</beans>
The spring-bean.xsd
has been constrained to allow such elements only as the last ones in the file. This should help provide flexibility without incurring clutter in the XML files.
- spring bean。xsd已经被限制为只允许这样的元素作为文件中的最后一个元素。这将有助于提供灵活性,而不会导致XML文件的混乱。
Activating a profile(激活一个概要文件)
Now that we have updated our configuration, we still need to instruct Spring which profile is active. If we started our sample application right now, we would see a NoSuchBeanDefinitionException
thrown, because the container could not find the Spring bean named dataSource
.
- 现在我们已经更新了配置,我们仍然需要指示Spring哪个配置文件是活动的。如果我们现在启动示例应用程序,我们将看到抛出NoSuchBeanDefinitionException异常,因为容器无法找到名为dataSource的Spring bean。
Activating a profile can be done in several ways, but the most straightforward is to do it programmatically against the Environment
API which is available via an ApplicationContext
:
- 激活一个配置文件可以在几个方式,但最直接的是做它编程对环境API,这是可通过一个ApplicationContext:
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("development");
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
ctx.refresh();
In addition, profiles may also be activated declaratively through the spring.profiles.active
property which may be specified through system environment variables, JVM system properties, servlet context parameters in web.xml
, or even as an entry in JNDI (see PropertySource abstraction). In integration tests, active profiles can be declared via the @ActiveProfiles
annotation in the spring-test
module (see Context configuration with environment profiles).
- 此外,还可以通过spring.profiles声明性地激活配置文件。活动属性,可以通过系统环境变量、JVM系统属性、web中的servlet上下文参数来指定。xml,或者甚至作为JNDI中的一个条目(请参阅PropertySource抽象)。在集成测试中,可以通过spring-test模块中的@ActiveProfiles注释声明活动概要文件(请参阅环境概要文件的上下文配置)。
Note that profiles are not an "either-or" proposition; it is possible to activate multiple profiles at once. Programmatically, simply provide multiple profile names to the setActiveProfiles()
method, which accepts String…
varargs:
- 请注意,简历不是一个“非此即彼”的命题;一次激活多个配置文件是可能的。通过编程,只需为setActiveProfiles()方法提供多个配置文件名称,该方法接受字符串…可变参数:
ctx.getEnvironment().setActiveProfiles("profile1", "profile2");
Declaratively, spring.profiles.active
may accept a comma-separated list of profile names:
- 声明,spring.profiles。活动可以接受一个逗号分隔的配置文件名称列表:
-Dspring.profiles.active="profile1,profile2"
Default profile(默认配置文件)
The default profile represents the profile that is enabled by default. Consider the following:(默认配置文件表示默认情况下启用的配置文件。考虑以下:)
@Configuration
@Profile("default")
public class DefaultDataConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.build();
}
}
If no profile is active, the dataSource
above will be created; this can be seen as a way to provide a default definition for one or more beans. If any profile is enabled, the default profile will not apply.
- 如果没有配置文件是活动的,上面的数据源将被创建;这可以看作是为一个或多个bean提供默认定义的一种方法。如果任何配置文件被启用,默认的配置文件将不适用。
The name of the default profile can be changed using setDefaultProfiles()
on the Environment
or declaratively using the spring.profiles.default
property.
- 默认配置文件的名称可以在环境中使用setDefaultProfiles()或声明性地使用spring.profile .default属性来更改。
1.13.2. PropertySource abstraction(PropertySource抽象)
Spring’s Environment
abstraction provides search operations over a configurable hierarchy of property sources. To explain fully, consider the following:
- Spring的环境抽象提供了在属性源的可配置层次结构上的搜索操作。为了充分解释,请考虑以下几点:
ApplicationContext ctx = new GenericApplicationContext();
Environment env = ctx.getEnvironment();
boolean containsFoo = env.containsProperty("foo");
System.out.println("Does my environment contain the 'foo' property? " + containsFoo);
In the snippet above, we see a high-level way of asking Spring whether the foo
property is defined for the current environment. To answer this question, the Environment
object performs a search over a set of PropertySource
objects. A PropertySource
is a simple abstraction over any source of key-value pairs, and Spring’s StandardEnvironment
is configured with two PropertySource objects — one representing the set of JVM system properties (a la System.getProperties()
) and one representing the set of system environment variables (a la System.getenv()
).
- 在上面的代码片段中,我们看到了一种询问Spring是否为当前环境定义了foo属性的高级方法。要回答这个问题,环境对象对一组PropertySource对象执行搜索。PropertySource是一个简单的抽象在任何键-值对的来源,和春天年代StandardEnvironment配置了两个PropertySource对象代表一个JVM系统属性的集合(la System.getProperties())和一个代表系统环境变量的设置(la System.getenv())。
These default property sources are present for StandardEnvironment , for use in standalone applications. StandardServletEnvironment is populated with additional default property sources including servlet config and servlet context parameters. It can optionally enable a JndiPropertySource . See the javadocs for details. |
|
---|---|
- 这些默认属性源是为StandardEnvironment提供的,用于独立应用程序。StandardServletEnvironment使用其他默认属性源进行填充,包括servlet配置和servlet上下文参数。它可以选择启用JndiPropertySource。有关详细信息,请参阅javadocs。
Concretely, when using the StandardEnvironment
, the call to env.containsProperty("foo")
will return true if a foo
system property or foo
environment variable is present at runtime.
- 具体地说,当使用StandardEnvironment时,如果foo系统属性或foo环境变量在运行时出现,那么对env.containsProperty("foo")的调用将返回true。
The search performed is hierarchical. By default, system properties have precedence over environment variables, so if the foo property happens to be set in both places during a call to env.getProperty("foo") , the system property value will 'win' and be returned preferentially over the environment variable. Note that property values will not get merged but rather completely overridden by a preceding entry.For a common StandardServletEnvironment , the full hierarchy looks as follows, with the highest-precedence entries at the top:ServletConfig parameters (if applicable, e.g. in case of a DispatcherServlet context)ServletContext parameters (web.xml context-param entries)JNDI environment variables ("java:comp/env/" entries)JVM system properties ("-D" command-line arguments)JVM system environment (operating system environment variables) |
|
---|---|
- 所执行的搜索是分层的。默认情况下,系统属性优先于环境变量,因此,如果foo属性在调用env.getProperty("foo")期间恰好在两个位置都设置了,系统属性值将'win'并优先于环境变量返回。注意,属性值不会被合并,而是被前面的条目完全覆盖。为共同StandardServletEnvironment,完整的层次结构如下,顶部的highest-precedence条目:ServletConfig参数(如果适用,例如对于DispatcherServlet上下文)ServletContext参数(web . xml context-param条目)JNDI环境变量(java: comp / env /条目)JVM系统属性(“- d”命令行参数)JVM系统环境(操作系统环境变量)
Most importantly, the entire mechanism is configurable. Perhaps you have a custom source of properties that you’d like to integrate into this search. No problem — simply implement and instantiate your own PropertySource
and add it to the set of PropertySources
for the current Environment
:
- 最重要的是,整个机制是可配置的。也许您有一个想要集成到这个搜索中的自定义属性源。没有问题-只需实现和实例化你自己的PropertySource,并将其添加到当前环境的PropertySources集合:
ConfigurableApplicationContext ctx = new GenericApplicationContext();
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
sources.addFirst(new MyPropertySource());
In the code above, MyPropertySource
has been added with highest precedence in the search. If it contains a foo
property, it will be detected and returned ahead of any foo
property in any other PropertySource
. The MutablePropertySources
API exposes a number of methods that allow for precise manipulation of the set of property sources.
- 在上面的代码中,MyPropertySource以最高的优先级添加到搜索中。如果它包含一个foo属性,它将被检测到并在任何其他PropertySource中的任何foo属性之前返回。MutablePropertySources API公开了许多允许精确操作属性源集的方法。
1.13.3. @PropertySource(源日志)
The @PropertySource
annotation provides a convenient and declarative mechanism for adding a PropertySource
to Spring’s Environment
.
- @PropertySource注释提供了一种方便的声明机制,可以将PropertySource添加到Spring的环境中。
Given a file "app.properties" containing the key/value pair testbean.name=myTestBean
, the following @Configuration
class uses @PropertySource
in such a way that a call to testBean.getName()
will return "myTestBean".
- 给定一个包含键/值对testbean.name=myTestBean的文件“app.properties”,下面的@Configuration类使用@PropertySource,这样,对testBean.getName()的调用将返回“myTestBean”。
@Configuration
@PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {
@Autowired
Environment env;
@Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
testBean.setName(env.getProperty("testbean.name"));
return testBean;
}
}
Any ${…}
placeholders present in a @PropertySource
resource location will be resolved against the set of property sources already registered against the environment. For example:
- 任何出现在@PropertySource资源位置中的${…}占位符将根据已针对环境注册的属性源集进行解析。例如:
@Configuration
@PropertySource("classpath:/com/${my.placeholder:default/path}/app.properties")
public class AppConfig {
@Autowired
Environment env;
@Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
testBean.setName(env.getProperty("testbean.name"));
return testBean;
}
}
Assuming that "my.placeholder" is present in one of the property sources already registered, e.g. system properties or environment variables, the placeholder will be resolved to the corresponding value. If not, then "default/path" will be used as a default. If no default is specified and a property cannot be resolved, an IllegalArgumentException
will be thrown.
- 我的假设”。“占位符”出现在一个已注册的属性源中,例如系统属性或环境变量,占位符将解析为相应的值。如果不是,那么将使用“default/path”作为默认值。如果没有指定默认值,且无法解析属性,将抛出一个IllegalArgumentException。
The @PropertySource annotation is repeatable according to Java 8 conventions. However, all such @PropertySource annotations need to be declared at the same level: either directly on the configuration class or as meta-annotations within the same custom annotation. Mixing of direct annotations and meta-annotations is not recommended since direct annotations will effectively override meta-annotations. |
|
---|---|
- 根据Java 8的约定,@PropertySource注释是可重复的。但是,所有这样的@PropertySource注释都需要在同一级别声明:要么直接在配置类上声明,要么作为同一自定义注释中的元注释声明。不建议混合使用直接注释和元注释,因为直接注释会有效地覆盖元注释。
1.13.4. Placeholder resolution in statements(语句中的占位符解析)
Historically, the value of placeholders in elements could be resolved only against JVM system properties or environment variables. No longer is this the case. Because the Environment abstraction is integrated throughout the container, it’s easy to route resolution of placeholders through it. This means that you may configure the resolution process in any way you like: change the precedence of searching through system properties and environment variables, or remove them entirely; add your own property sources to the mix as appropriate.
- 过去,元素中的占位符的值只能根据JVM系统属性或环境变量解析。现在情况已经不一样了。因为环境抽象集成在整个容器中,所以很容易通过它来解析占位符。这意味着您可以按照自己喜欢的方式配置解析过程:更改搜索系统属性和环境变量的优先级,或者完全删除它们;将您自己的属性源添加到适当的组合中。
Concretely, the following statement works regardless of where the customer
property is defined, as long as it is available in the Environment
:
- 具体地说,无论客户属性定义在哪里,只要它在环境中可用,以下语句都适用:
<beans>
<import resource="com/bank/service/${customer}-config.xml"/>
</beans>
1.14. Registering a LoadTimeWeaver(注册一个LoadTimeWeaver
The LoadTimeWeaver
is used by Spring to dynamically transform classes as they are loaded into the Java virtual machine (JVM).
- 当类装入Java虚拟机(JVM)时,Spring使用LoadTimeWeaver动态地转换类。
To enable load-time weaving add the @EnableLoadTimeWeaving
to one of your @Configuration
classes:
- 要启用加载时编织,添加@ enableloadtime织造到您的一个@Configuration类:
@Configuration
@EnableLoadTimeWeaving
public class AppConfig {
}
Alternatively for XML configuration use the context:load-time-weaver
element:
- 对于XML配置,也可以使用上下文:load-time-weaver元素:
<beans>
<context:load-time-weaver/>
</beans>
Once configured for the ApplicationContext
. Any bean within that ApplicationContext
may implement LoadTimeWeaverAware
, thereby receiving a reference to the load-time weaver instance. This is particularly useful in combination with Spring’s JPA support where load-time weaving may be necessary for JPA class transformation. Consult the LocalContainerEntityManagerFactoryBean
javadocs for more detail. For more on AspectJ load-time weaving, see Load-time weaving with AspectJ in the Spring Framework.
- 为ApplicationContext配置好之后。该ApplicationContext中的任何bean都可以实现LoadTimeWeaverAware,从而接收到加载时weaver实例的引用。这在与Spring的JPA支持相结合时特别有用,其中加载时编织对于JPA类转换可能是必要的。有关更多细节,请参阅LocalContainerEntityManagerFactoryBean javadocs。有关AspectJ加载时编织的更多信息,请参见Spring框架中使用AspectJ进行的加载时编织。
1.15. Additional capabilities of the ApplicationContext(ApplicationContext的附加功能)
As was discussed in the chapter introduction, the org.springframework.beans.factory
package provides basic functionality for managing and manipulating beans, including in a programmatic way. The org.springframework.context
package adds the ApplicationContext
interface, which extends the BeanFactory
interface, in addition to extending other interfaces to provide additional functionality in a more application framework-oriented style. Many people use the ApplicationContext
in a completely declarative fashion, not even creating it programmatically, but instead relying on support classes such as ContextLoader
to automatically instantiate an ApplicationContext
as part of the normal startup process of a Java EE web application.
- 正如在引言中所讨论的,org.springframework.beans。工厂包提供了管理和操作bean的基本功能,包括以编程的方式。org.springframework。上下文包添加了ApplicationContext接口,该接口扩展了BeanFactory接口,此外还扩展了其他接口,以更面向应用程序框架的风格提供额外的功能。许多人以一种完全声明式的方式使用ApplicationContext,甚至不是通过编程来创建它,而是依赖于支持类(如ContextLoader)来自动实例化一个ApplicationContext,作为Java EE web应用程序的正常启动过程的一部分。
To enhance BeanFactory
functionality in a more framework-oriented style the context package also provides the following functionality:
-
- 为了以更面向框架的风格增强BeanFactory功能,上下文包还提供了以下功能:
-
Access to messages in i18n-style, through the
MessageSource
interface.- 通过MessageSource接口访问i18n风格的消息。
-
Access to resources, such as URLs and files, through the
ResourceLoader
interface.- 通过ResourceLoader接口访问资源,例如url和文件。
-
Event publication to namely beans implementing the
ApplicationListener
interface, through the use of theApplicationEventPublisher
interface.- 通过使用ApplicationEventPublisher接口,将事件发布到实现ApplicationListener接口的bean。
-
Loading of multiple (hierarchical) contexts, allowing each to be focused on one particular layer, such as the web layer of an application, through the
HierarchicalBeanFactory
interface.- 通过HierarchicalBeanFactory接口加载多个(分层的)上下文,允许每个上下文都关注于一个特定的层,比如应用程序的web层。
1.15.1. Internationalization using MessageSource(使用MessageSource国际化)
The ApplicationContext
interface extends an interface called MessageSource
, and therefore provides internationalization (i18n) functionality. Spring also provides the interface HierarchicalMessageSource
, which can resolve messages hierarchically. Together these interfaces provide the foundation upon which Spring effects message resolution. The methods defined on these interfaces include:
-
- ApplicationContext接口扩展了一个名为MessageSource的接口,因此提供了国际化(i18n)功能。Spring还提供了接口HierarchicalMessageSource,该接口可以分层解析消息。这些接口一起提供了Spring实现消息解析的基础。在这些接口上定义的方法包括:
-
String getMessage(String code, Object[] args, String default, Locale loc)
: The basic method used to retrieve a message from theMessageSource
. When no message is found for the specified locale, the default message is used. Any arguments passed in become replacement values, using theMessageFormat
functionality provided by the standard library.- getMessage(String code, Object[] args, String default, Locale loc):用于从MessageSource检索消息的基本方法。如果未找到指定语言环境的消息,则使用默认消息。通过使用标准库提供的MessageFormat功能,传入的任何参数都将成为替换值。
-
String getMessage(String code, Object[] args, Locale loc)
: Essentially the same as the previous method, but with one difference: no default message can be specified; if the message cannot be found, aNoSuchMessageException
is thrown.- getMessage(String code, Object[] args, Locale loc):本质上与前面的方法相同,但有一个区别:不能指定默认消息;如果找不到消息,则抛出NoSuchMessageException。
-
String getMessage(MessageSourceResolvable resolvable, Locale locale)
: All properties used in the preceding methods are also wrapped in a class namedMessageSourceResolvable
, which you can use with this method.- 字符串getMessage(MessageSourceResolvable, Locale Locale):前面方法中使用的所有属性也包装在一个名为MessageSourceResolvable类中,可与此方法一起使用。
When an ApplicationContext
is loaded, it automatically searches for a MessageSource
bean defined in the context. The bean must have the name messageSource
. If such a bean is found, all calls to the preceding methods are delegated to the message source. If no message source is found, the ApplicationContext
attempts to find a parent containing a bean with the same name. If it does, it uses that bean as the MessageSource
. If the ApplicationContext
cannot find any source for messages, an empty DelegatingMessageSource
is instantiated in order to be able to accept calls to the methods defined above.
- 加载ApplicationContext时,它会自动搜索上下文中定义的MessageSource bean。bean的名称必须是messageSource。如果找到这样一个bean,对前面方法的所有调用都将委托给消息源。如果没有找到消息源,ApplicationContext将尝试查找包含同名bean的父消息源。如果是,则使用该bean作为消息源。如果ApplicationContext找不到任何消息源,则实例化一个空的DelegatingMessageSource,以便能够接受对上面定义的方法的调用。
Spring provides two MessageSource
implementations, ResourceBundleMessageSource
and StaticMessageSource
. Both implement HierarchicalMessageSource
in order to do nested messaging. The StaticMessageSource
is rarely used but provides programmatic ways to add messages to the source. The ResourceBundleMessageSource
is shown in the following example:
- Spring提供了两个消息源实现,ResourceBundleMessageSource和StaticMessageSource。两者都实现了HierarchicalMessageSource以执行嵌套消息传递。很少使用StaticMessageSource,但它提供了将消息添加到源的编程方法。ResourceBundleMessageSource如下所示:
<beans>
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>format</value>
<value>exceptions</value>
<value>windows</value>
</list>
</property>
</bean>
</beans>
In the example it is assumed you have three resource bundles defined in your classpath called format
, exceptions
and windows
. Any request to resolve a message will be handled in the JDK standard way of resolving messages through ResourceBundles. For the purposes of the example, assume the contents of two of the above resource bundle files are…
- 在本例中,假设您在类路径中定义了三个资源包,分别是format、exceptions和windows。任何解析消息的请求都将以通过resourcebundle解析消息的JDK标准方式处理。出于示例的目的,假设上述两个资源包文件的内容是…
# in format.properties
message=Alligators rock!
# in exceptions.properties
argument.required=The {0} argument is required.
A program to execute the MessageSource
functionality is shown in the next example. Remember that all ApplicationContext
implementations are also MessageSource
implementations and so can be cast to the MessageSource
interface.
- 下一个示例将显示执行MessageSource功能的程序。记住,所有ApplicationContext实现也是MessageSource实现,因此可以cast到MessageSource接口。
public static void main(String[] args) {
MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
String message = resources.getMessage("message", null, "Default", null);
System.out.println(message);
}
The resulting output from the above program will be…
- 以上程序的结果输出将是…
Alligators rock!
So to summarize, the MessageSource
is defined in a file called beans.xml
, which exists at the root of your classpath. The messageSource
bean definition refers to a number of resource bundles through its basenames
property. The three files that are passed in the list to the basenames
property exist as files at the root of your classpath and are called format.properties
, exceptions.properties
, and windows.properties
respectively.
- 总之,MessageSource是在一个名为bean的文件中定义的。xml,它存在于类路径的根。messageSource bean定义通过其basenames属性引用大量资源包。在列表中传递给basenames属性的三个文件作为类路径的根文件存在,它们被称为format。属性,例外。属性,和windows。属性分别。
The next example shows arguments passed to the message lookup; these arguments will be converted into Strings and inserted into placeholders in the lookup message.
- 下一个示例显示了传递给消息查找的参数;这些参数将被转换为字符串,并插入到查找消息中的占位符中。
<beans>
<!-- this MessageSource is being used in a web application -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="exceptions"/>
</bean>
<!-- lets inject the above MessageSource into this POJO -->
<bean id="example" class="com.foo.Example">
<property name="messages" ref="messageSource"/>
</bean>
</beans>
public class Example {
private MessageSource messages;
public void setMessages(MessageSource messages) {
this.messages = messages;
}
public void execute() {
String message = this.messages.getMessage("argument.required",
new Object [] {"userDao"}, "Required", null);
System.out.println(message);
}
}
The resulting output from the invocation of the execute()
method will be…
- 调用execute()方法的结果输出将是…
The userDao argument is required.
With regard to internationalization (i18n), Spring’s various MessageSource
implementations follow the same locale resolution and fallback rules as the standard JDK ResourceBundle
. In short, and continuing with the example messageSource
defined previously, if you want to resolve messages against the British (en-GB
) locale, you would create files called format_en_GB.properties
, exceptions_en_GB.properties
, and windows_en_GB.properties
respectively.
- 关于国际化(i18n), Spring的各种MessageSource实现遵循与标准JDK ResourceBundle相同的语言环境解析和回退规则。简而言之,继续前面定义的示例messageSource,如果您希望根据英国(en-GB)地区解析消息,您将创建名为format_en_GB的文件。属性,exceptions_en_GB。属性和windows_en_GB。属性分别。
Typically, locale resolution is managed by the surrounding environment of the application. In this example, the locale against which (British) messages will be resolved is specified manually.
- 通常,语言环境解析由应用程序的周围环境管理。在本例中,将手动指定消息解析所依据的地区(英国)。
# in exceptions_en_GB.properties
argument.required=Ebagum lad, the {0} argument is required, I say, required.
public static void main(final String[] args) {
MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
String message = resources.getMessage("argument.required",
new Object [] {"userDao"}, "Required", Locale.UK);
System.out.println(message);
}
The resulting output from the running of the above program will be…
- 运行上述程序的结果将是…
Ebagum lad, the 'userDao' argument is required, I say, required.
You can also use the MessageSourceAware
interface to acquire a reference to any MessageSource
that has been defined. Any bean that is defined in an ApplicationContext
that implements the MessageSourceAware
interface is injected with the application context’s MessageSource
when the bean is created and configured.
- 您还可以使用MessageSourceAware接口来获取对已定义的任何消息源的引用。当创建和配置bean时,在实现MessageSourceAware接口的ApplicationContext中定义的任何bean都被注入应用上下文的MessageSourceAware接口。
As an alternative to ResourceBundleMessageSource , Spring provides a ReloadableResourceBundleMessageSource class. This variant supports the same bundle file format but is more flexible than the standard JDK based ResourceBundleMessageSource implementation. In particular, it allows for reading files from any Spring resource location (not just from the classpath) and supports hot reloading of bundle property files (while efficiently caching them in between). Check out the ReloadableResourceBundleMessageSource javadocs for details. |
|
---|---|
- :作为ResourceBundleMessageSource的替代方案,Spring提供了一个ReloadableResourceBundleMessageSource类。这个变体支持相同的bundle文件格式,但是比基于JDK的标准ResourceBundleMessageSource实现更加灵活。特别是,它允许从任何Spring资源位置读取文件(而不仅仅是从类路径),并支持bundle属性文件的热重新加载(同时有效地缓存它们)。查看ReloadableResourceBundleMessageSource javadocs以获得详细信息。
1.15.2. Standard and custom events(标准和自定义事件)
Event handling in the ApplicationContext
is provided through the ApplicationEvent
class and ApplicationListener
interface. If a bean that implements the ApplicationListener
interface is deployed into the context, every time an ApplicationEvent
gets published to the ApplicationContext
, that bean is notified. Essentially, this is the standard Observer design pattern.
- ApplicationContext中的事件处理是通过ApplicationEvent类和ApplicationListener接口提供的。如果实现ApplicationListener接口的bean被部署到上下文中,那么每当一个ApplicationEvent被发布到ApplicationContext时,该bean就会得到通知。本质上,这就是标准的观察者设计模式。
As of Spring 4.2, the event infrastructure has been significantly improved and offer an annotation-based model as well as the ability to publish any arbitrary event, that is an object that does not necessarily extend from ApplicationEvent . When such an object is published we wrap it in an event for you. |
|
---|---|
- 从Spring 4.2开始,事件基础设施已经得到了显著改进,并提供了基于注释的模型以及发布任意事件的能力,而任意事件不一定是从ApplicationEvent扩展而来的。当这样的对象被发布时,我们为您将其包装在事件中。
Spring provides the following standard events:
- Spring提供了以下标准事件:
Event | Explanation |
---|---|
ContextRefreshedEvent |
Published when the ApplicationContext is initialized or refreshed, for example, using the refresh() method on the ConfigurableApplicationContext interface. "Initialized" here means that all beans are loaded, post-processor beans are detected and activated, singletons are pre-instantiated, and the ApplicationContext object is ready for use. As long as the context has not been closed, a refresh can be triggered multiple times, provided that the chosen ApplicationContext actually supports such "hot" refreshes. For example, XmlWebApplicationContext supports hot refreshes, but GenericApplicationContext does not.【在初始化或刷新ApplicationContext时发布,例如,使用ConfigurableApplicationContext接口上的refresh()方法。这里的“初始化”意味着加载所有bean,检测并激活后处理器bean,预实例化单例,并且ApplicationContext对象已经准备好可以使用了。只要上下文没有被关闭,刷新就可以被触发多次,前提是所选的ApplicationContext实际上支持这种“热”刷新。例如,XmlWebApplicationContext支持热刷新,而GenericApplicationContext不支持。】 |
ContextStartedEvent |
Published when the ApplicationContext is started, using the start() method on the ConfigurableApplicationContext interface. "Started" here means that all Lifecycle beans receive an explicit start signal. Typically this signal is used to restart beans after an explicit stop, but it may also be used to start components that have not been configured for autostart , for example, components that have not already started on initialization.【在启动ApplicationContext时发布,使用ConfigurableApplicationContext接口上的start()方法。这里的“Started”意味着所有生命周期bean都收到一个显式的启动信号。通常,该信号用于在显式停止后重新启动bean,但也可以用于启动尚未配置为自动启动的组件,例如,尚未在初始化时启动的组件。】 |
ContextStoppedEvent |
Published when the ApplicationContext is stopped, using the stop() method on the ConfigurableApplicationContext interface. "Stopped" here means that all Lifecycle beans receive an explicit stop signal. A stopped context may be restarted through a start() call.【在停止ApplicationContext时发布,使用ConfigurableApplicationContext接口上的stop()方法。这里的“Stopped”意味着所有生命周期bean都接收到一个显式的停止信号。一个停止的上下文可以通过一个start()调用重新启动。】 |
ContextClosedEvent |
Published when the ApplicationContext is closed, using the close() method on the ConfigurableApplicationContext interface. "Closed" here means that all singleton beans are destroyed. A closed context reaches its end of life; it cannot be refreshed or restarted.【使用ConfigurableApplicationContext接口上的close()方法,在关闭ApplicationContext时发布。这里的“关闭”意味着所有单例bean都被销毁。一个封闭的环境到达它生命的尽头;它无法刷新或重新启动。】 |
RequestHandledEvent |
A web-specific event telling all beans that an HTTP request has been serviced. This event is published after the request is complete. This event is only applicable to web applications using Spring’s DispatcherServlet .【一个特定于web的事件,告诉所有bean一个HTTP请求已经得到服务。此事件在请求完成后发布。此事件仅适用于使用Spring的DispatcherServlet的web应用程序。】 |
You can also create and publish your own custom events. This example demonstrates a simple class that extends Spring’s ApplicationEvent
base class:
- 您还可以创建和发布自己的自定义事件。这个例子演示了一个简单的类,它扩展了Spring的ApplicationEvent基类:
public class BlackListEvent extends ApplicationEvent {
private final String address;
private final String test;
public BlackListEvent(Object source, String address, String test) {
super(source);
this.address = address;
this.test = test;
}
// accessor and other methods...
}
To publish a custom ApplicationEvent
, call the publishEvent()
method on an ApplicationEventPublisher
. Typically this is done by creating a class that implements ApplicationEventPublisherAware
and registering it as a Spring bean. The following example demonstrates such a class:
- :要发布自定义ApplicationEvent,请调用ApplicationEventPublisher上的publishEvent()方法。通常,这是通过创建实现ApplicationEventPublisherAware的类并将其注册为Spring bean来完成的。下面的例子演示了这样一个类:
public class EmailService implements ApplicationEventPublisherAware {
private List<String> blackList;
private ApplicationEventPublisher publisher;
public void setBlackList(List<String> blackList) {
this.blackList = blackList;
}
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void sendEmail(String address, String text) {
if (blackList.contains(address)) {
BlackListEvent event = new BlackListEvent(this, address, text);
publisher.publishEvent(event);
return;
}
// send email...
}
}
At configuration time, the Spring container will detect that EmailService
implements ApplicationEventPublisherAware
and will automatically call setApplicationEventPublisher()
. In reality, the parameter passed in will be the Spring container itself; you’re simply interacting with the application context via its ApplicationEventPublisher
interface.
- 在配置时,Spring容器将检测EmailService实现了ApplicationEventPublisherAware,并将自动调用setApplicationEventPublisher()。实际上,传入的参数将是Spring容器本身;您只是通过应用程序的ApplicationEventPublisher接口与应用程序上下文交互。
To receive the custom ApplicationEvent
, create a class that implements ApplicationListener
and register it as a Spring bean. The following example demonstrates such a class:
- 要接收自定义ApplicationEvent,需要创建一个实现ApplicationListener的类,并将其注册为一个Spring bean。下面的例子演示了这样一个类:
public class BlackListNotifier implements ApplicationListener<BlackListEvent> {
private String notificationAddress;
public void setNotificationAddress(String notificationAddress) {
this.notificationAddress = notificationAddress;
}
public void onApplicationEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress...
}
}
Notice that ApplicationListener
is generically parameterized with the type of your custom event, BlackListEvent
. This means that the onApplicationEvent()
method can remain type-safe, avoiding any need for downcasting. You may register as many event listeners as you wish, but note that by default event listeners receive events synchronously. This means the publishEvent()
method blocks until all listeners have finished processing the event. One advantage of this synchronous and single-threaded approach is that when a listener receives an event, it operates inside the transaction context of the publisher if a transaction context is available. If another strategy for event publication becomes necessary, refer to the javadoc for Spring’s ApplicationEventMulticaster
interface.
- 注意,ApplicationListener通常是用自定义事件的类型BlackListEvent参数化的。这意味着onApplicationEvent()方法可以保持类型安全,避免向下强制转换。您可以注册任意多的事件监听器,但是请注意,默认情况下,事件监听器是同步接收事件的。这意味着publishEvent()方法会阻塞,直到所有监听器都完成了事件的处理。这种同步和单线程方法的一个优点是,当侦听器接收到事件时,如果事务上下文可用,它将在发布程序的事务上下文内操作。如果需要另一种事件发布策略,请参考Spring的ApplicationEventMulticaster接口的javadoc。
The following example shows the bean definitions used to register and configure each of the classes above:
- 下面的例子显示了用于注册和配置上面每个类的bean定义:
<bean id="emailService" class="example.EmailService">
<property name="blackList">
<list>
<value>known.spammer@example.org</value>
<value>known.hacker@example.org</value>
<value>john.doe@example.org</value>
</list>
</property>
</bean>
<bean id="blackListNotifier" class="example.BlackListNotifier">
<property name="notificationAddress" value="blacklist@example.org"/>
</bean>
Putting it all together, when the sendEmail()
method of the emailService
bean is called, if there are any emails that should be blacklisted, a custom event of type BlackListEvent
is published. The blackListNotifier
bean is registered as an ApplicationListener
and thus receives the BlackListEvent
, at which point it can notify appropriate parties.
- 将这些放在一起,当调用emailService bean的sendEmail()方法时,如果有任何电子邮件应该被列入黑名单,则发布一个BlackListEvent类型的自定义事件。blackListNotifier bean被注册为一个ApplicationListener,从而接收BlackListEvent,在这一点上它可以通知相关方。
Spring’s eventing mechanism is designed for simple communication between Spring beans within the same application context. However, for more sophisticated enterprise integration needs, the separately-maintained Spring Integration project provides complete support for building lightweight, pattern-oriented, event-driven architectures that build upon the well-known Spring programming model. | |
---|---|
- Spring的事件机制是为相同应用程序上下文中的Spring bean之间的简单通信而设计的。然而,对于更复杂的企业集成需求,独立维护的Spring integration项目提供了对构建轻量级、面向模式、事件驱动架构的完整支持,这些架构构建在众所周知的Spring编程模型之上。
Annotation-based event listeners(基于注解的事件监听器)
As of Spring 4.2, an event listener can be registered on any public method of a managed bean via the EventListener
annotation. The BlackListNotifier
can be rewritten as follows:
- 从Spring 4.2开始,事件监听器可以通过EventListener注释在托管bean的任何公共方法上注册。BlackListNotifier可以重写如下:
public class BlackListNotifier {
private String notificationAddress;
public void setNotificationAddress(String notificationAddress) {
this.notificationAddress = notificationAddress;
}
@EventListener
public void processBlackListEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress...
}
}
As you can see above, the method signature once again declares the event type it listens to, but this time with a flexible name and without implementing a specific listener interface. The event type can also be narrowed through generics as long as the actual event type resolves your generic parameter in its implementation hierarchy.
- 正如您在上面看到的,方法签名再次声明它侦听的事件类型,但这次使用了灵活的名称,并且没有实现特定的侦听器接口。只要实际事件类型在其实现层次结构中解析泛型参数,就可以通过泛型缩小事件类型。
If your method should listen to several events or if you want to define it with no parameter at all, the event type(s) can also be specified on the annotation itself:
- 如果你的方法需要监听多个事件,或者你想在没有任何参数的情况下定义它,事件类型也可以在注释本身上指定:
@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
public void handleContextStart() {
...
}
It is also possible to add additional runtime filtering via the condition
attribute of the annotation that defines a SpEL
expression that should match to actually invoke the method for a particular event.
- 还可以通过注释的条件属性添加额外的运行时过滤,该注释定义了一个SpEL表达式,该表达式应该与针对特定事件实际调用方法相匹配。
For instance, our notifier can be rewritten to be only invoked if the test
attribute of the event is equal to foo
:
- 例如,我们的通知可以被重写,只有在事件的测试属性等于foo时才被调用:
@EventListener(condition = "#blEvent.test == 'foo'")
public void processBlackListEvent(BlackListEvent blEvent) {
// notify appropriate parties via notificationAddress...
}
Each SpEL
expression evaluates again a dedicated context. The next table lists the items made available to the context so one can use them for conditional event processing:
- 每个SpEL表达式再次计算一个专用上下文。下一个表列出了上下文可用的项目,以便人们可以使用它们进行条件事件处理:
Name | Location | Description | Example |
---|---|---|---|
Event | root object | The actual ApplicationEvent |
#root.event |
Arguments array | root object | The arguments (as array) used for invoking the target | #root.args[0] |
Argument name | evaluation context | Name of any of the method arguments. If for some reason the names are not available (e.g. no debug information), the argument names are also available under the #a<#arg> where #arg stands for the argument index (starting from 0).【任何方法参数的名称。如果由于某些原因,名称不可用(例如,没有调试信息),参数名称也可以在#a<#arg>下使用,其中#arg表示参数索引(从0开始)。】 |
#blEvent or #a0 (one can also use #p0 or #p<#arg> notation as an alias). |
Note that #root.event
allows you to access to the underlying event, even if your method signature actually refers to an arbitrary object that was published.
- 请注意,#根。事件允许您访问底层事件,即使您的方法签名实际上引用了已发布的任意对象。
If you need to publish an event as the result of processing another, just change the method signature to return the event that should be published, something like:
- 如果你需要发布一个事件作为处理另一个事件的结果,只需改变方法签名来返回应该发布的事件,类似于:
@EventListener
public ListUpdateEvent handleBlackListEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress and
// then publish a ListUpdateEvent...
}
This feature is not supported for asynchronous listeners. | |
---|---|
This new method will publish a new ListUpdateEvent
for every BlackListEvent
handled by the method above. If you need to publish several events, just return a Collection
of events instead.
- 这个新方法将为上述方法处理的每个BlackListEvent发布一个新的ListUpdateEvent。如果需要发布多个事件,只需返回一个事件集合即可。
Asynchronous Listeners(异步的听众)
If you want a particular listener to process events asynchronously, simply reuse the regular @Async
support:
- :如果你想要一个特定的监听器异步处理事件,只需重用常规的@Async支持:
@EventListener
@Async
public void processBlackListEvent(BlackListEvent event) {
// BlackListEvent is processed in a separate thread
}
Be aware of the following limitations when using asynchronous events:
- 在使用异步事件时要注意以下限制:
- If the event listener throws an
Exception
it will not be propagated to the caller, checkAsyncUncaughtExceptionHandler
for more details.- 如果事件侦听器抛出一个异常,它将不会传播到调用者,请检查AsyncUncaughtExceptionHandler以获得更多细节。
- Such event listener cannot send replies. If you need to send another event as the result of the processing, inject
ApplicationEventPublisher
to send the event manually.- 此类事件侦听器无法发送应答。如果您需要发送另一个事件作为处理的结果,注入ApplicationEventPublisher以手动发送事件。
Ordering listeners()
If you need the listener to be invoked before another one, just add the @Order
annotation to the method declaration:
- 如果需要在调用另一个监听器之前先调用它,只需在方法声明中添加@Order注释:
@EventListener
@Order(42)
public void processBlackListEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress...
}
Generic events(通用的事件)
You may also use generics to further define the structure of your event. Consider an EntityCreatedEvent<T>
where T
is the type of the actual entity that got created. You can create the following listener definition to only receive EntityCreatedEvent
for a Person
:
- 您还可以使用泛型来进一步定义事件的结构。考虑EntityCreatedEvent
,其中T是所创建的实际实体的类型。您可以创建以下侦听器定义来只接收一个人的EntityCreatedEvent:
@EventListener
public void onPersonCreated(EntityCreatedEvent<Person> event) {
...
}
Due to type erasure, this will only work if the event that is fired resolves the generic parameter(s) on which the event listener filters on (that is something like class PersonCreatedEvent extends EntityCreatedEvent<Person> { … }
).
- 由于类型擦除,只有在触发的事件解析了事件侦听器所过滤的泛型参数(类似于类PersonCreatedEvent扩展了EntityCreatedEvent
{…})时,这种方法才有效。
In certain circumstances, this may become quite tedious if all events follow the same structure (as it should be the case for the event above). In such a case, you can implement ResolvableTypeProvider
to guide the framework beyond what the runtime environment provides:
- 在某些情况下,如果所有的事件都遵循相同的结构(上面的事件也应该如此),这可能会变得非常乏味。在这种情况下,你可以实现ResolvableTypeProvider来指导框架超出运行时环境提供的:
public class EntityCreatedEvent<T>
extends ApplicationEvent implements ResolvableTypeProvider {
public EntityCreatedEvent(T entity) {
super(entity);
}
@Override
public ResolvableType getResolvableType() {
return ResolvableType.forClassWithGenerics(getClass(),
ResolvableType.forInstance(getSource()));
}
}
This works not only for ApplicationEvent but any arbitrary object that you’d send as an event. |
|
---|---|
- 这不仅适用于ApplicationEvent,也适用于任何作为事件发送的对象。
1.15.3. Convenient access to low-level resources(方便地访问底层资源)
For optimal usage and understanding of application contexts, users should generally familiarize themselves with Spring’s Resource
abstraction, as described in the chapter Resources.
- 为了优化使用和理解应用程序上下文,用户通常应该熟悉Spring的资源抽象,如参考资料一章所述。
An application context is a ResourceLoader
, which can be used to load Resource
s. A Resource
is essentially a more feature rich version of the JDK class java.net.URL
, in fact, the implementations of the Resource
wrap an instance of java.net.URL
where appropriate. A Resource
can obtain low-level resources from almost any location in a transparent fashion, including from the classpath, a filesystem location, anywhere describable with a standard URL, and some other variations. If the resource location string is a simple path without any special prefixes, where those resources come from is specific and appropriate to the actual application context type.
- 应用程序上下文是一个ResourceLoader,可用于加载资源。资源本质上是JDK类java.net.URL的一个功能更丰富的版本,事实上,资源的实现在适当的地方包装了一个java.net.URL的实例。资源可以以透明的方式从几乎任何位置获取底层资源,包括类路径、文件系统位置、可用标准URL描述的任何位置,以及其他一些变体。如果资源位置字符串是没有任何特殊前缀的简单路径,那么这些资源的来源是特定的,并且适合于实际的应用程序上下文类型。
You can configure a bean deployed into the application context to implement the special callback interface, ResourceLoaderAware
, to be automatically called back at initialization time with the application context itself passed in as the ResourceLoader
. You can also expose properties of type Resource
, to be used to access static resources; they will be injected into it like any other properties. You can specify those Resource
properties as simple String paths, and rely on a special JavaBean PropertyEditor
that is automatically registered by the context, to convert those text strings to actual Resource
objects when the bean is deployed.
- 应用程序上下文是一个ResourceLoader,可用于加载资源。资源本质上是JDK类java.net.URL的一个功能更丰富的版本,事实上,资源的实现在适当的地方包装了一个java.net.URL的实例。资源可以以透明的方式从几乎任何位置获取底层资源,包括类路径、文件系统位置、可用标准URL描述的任何位置,以及其他一些变体。如果资源位置字符串是没有任何特殊前缀的简单路径,那么这些资源的来源是特定的,并且适合于实际的应用程序上下文类型。
The location path or paths supplied to an ApplicationContext
constructor are actually resource strings, and in simple form are treated appropriately to the specific context implementation. ClassPathXmlApplicationContext
treats a simple location path as a classpath location. You can also use location paths (resource strings) with special prefixes to force loading of definitions from the classpath or a URL, regardless of the actual context type.
- 提供给ApplicationContext构造函数的位置路径或路径实际上是资源字符串,并以简单的形式适当地处理特定上下文实现。ClassPathXmlApplicationContext将简单的位置路径视为类路径位置。您还可以使用带有特殊前缀的位置路径(资源字符串)来强制从类路径或URL加载定义,而不管实际上下文类型是什么。
1.15.4. Convenient ApplicationContext instantiation for web applications(方便的ApplicationContext实例化web应用程序)
You can create ApplicationContext
instances declaratively by using, for example, a ContextLoader
. Of course you can also create ApplicationContext
instances programmatically by using one of the ApplicationContext
implementations.
- 您可以通过使用ContextLoader来声明式地创建ApplicationContext实例。当然,您也可以通过使用一个ApplicationContext实现以编程方式创建ApplicationContext实例。
You can register an ApplicationContext
using the ContextLoaderListener
as follows:
- 你可以注册一个ApplicationContext使用ContextLoaderListener如下:****
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
The listener inspects the contextConfigLocation
parameter. If the parameter does not exist, the listener uses /WEB-INF/applicationContext.xml
as a default. When the parameter does exist, the listener separates the String by using predefined delimiters (comma, semicolon and whitespace) and uses the values as locations where application contexts will be searched. Ant-style path patterns are supported as well. Examples are /WEB-INF/*Context.xml
for all files with names ending with "Context.xml", residing in the "WEB-INF" directory, and /WEB-INF/**/*Context.xml
, for all such files in any subdirectory of "WEB-INF".
- 侦听器检查contextConfigLocation参数。如果该参数不存在,侦听器将使用/WEB-INF/applicationContext.xml作为默认值。当参数确实存在时,侦听器将使用预定义的分隔符(逗号、分号和空格)分隔字符串,并将这些值用作搜索应用程序上下文的位置。也支持ant样式的路径模式。例如,/WEB-INF/Context.xml适用于所有名称以“Context”结尾的文件。和/WEB-INF/**/上下文。对于WEB-INF的任何子目录中的所有这些文件。
1.15.5. Deploying a Spring ApplicationContext as a Java EE RAR file(将Spring ApplicationContext部署为Java EE RAR文件)
It is possible to deploy a Spring ApplicationContext as a RAR file, encapsulating the context and all of its required bean classes and library JARs in a Java EE RAR deployment unit. This is the equivalent of bootstrapping a standalone ApplicationContext, just hosted in Java EE environment, being able to access the Java EE servers facilities. RAR deployment is more natural alternative to scenario of deploying a headless WAR file, in effect, a WAR file without any HTTP entry points that is used only for bootstrapping a Spring ApplicationContext in a Java EE environment.
- 可以将Spring ApplicationContext部署为RAR文件,将上下文及其所有必需的bean类和库jar封装在Java EE RAR部署单元中。这相当于引导一个独立的ApplicationContext,只是托管在Java EE环境中,能够访问Java EE服务器设施。RAR部署是部署无头WAR文件(实际上是一个没有任何HTTP入口点的WAR文件,仅用于在Java EE环境中引导Spring ApplicationContext)的更自然的替代方案。
RAR deployment is ideal for application contexts that do not need HTTP entry points but rather consist only of message endpoints and scheduled jobs. Beans in such a context can use application server resources such as the JTA transaction manager and JNDI-bound JDBC DataSources and JMS ConnectionFactory instances, and may also register with the platform’s JMX server - all through Spring’s standard transaction management and JNDI and JMX support facilities. Application components can also interact with the application server’s JCA WorkManager through Spring’s TaskExecutor
abstraction.
- RAR部署对于不需要HTTP入口点,而只包含消息端点和计划作业的应用程序上下文非常理想。在这样的上下文中,bean可以使用应用服务器资源,比如JTA事务管理器、JNDI绑定的JDBC数据源和JMS ConnectionFactory实例,还可以向平台的JMX服务器注册——所有这些都通过Spring的标准事务管理和JNDI和JMX支持工具完成。应用程序组件还可以通过Spring的TaskExecutor抽象与应用服务器的JCA WorkManager交互。
Check out the javadoc of the SpringContextResourceAdapter
class for the configuration details involved in RAR deployment.
- 查看SpringContextResourceAdapter类的javadoc,了解RAR部署中涉及的配置细节。
For a simple deployment of a Spring ApplicationContext as a Java EE RAR file: package all application classes into a RAR file, which is a standard JAR file with a different file extension. Add all required library JARs into the root of the RAR archive. Add a "META-INF/ra.xml" deployment descriptor (as shown in SpringContextResourceAdapter
s javadoc) and the corresponding Spring XML bean definition file(s) (typically "META-INF/applicationContext.xml"), and drop the resulting RAR file into your application server’s deployment directory.
- 对于将Spring ApplicationContext作为Java EE RAR文件进行简单部署:将所有应用程序类打包到一个RAR文件中,该文件是一个具有不同文件扩展名的标准JAR文件。将所有需要的库jar文件添加到RAR归档的根目录中。添加一个“meta - inf / ra。xml“部署描述符”(如SpringContextResourceAdapters javadoc中所示)和相应的Spring xml bean定义文件(通常是“META-INF/applicationContext.xml”),并将产生的RAR文件放到应用服务器的部署目录中。
Such RAR deployment units are usually self-contained; they do not expose components to the outside world, not even to other modules of the same application. Interaction with a RAR-based ApplicationContext usually occurs through JMS destinations that it shares with other modules. A RAR-based ApplicationContext may also, for example, schedule some jobs, reacting to new files in the file system (or the like). If it needs to allow synchronous access from the outside, it could for example export RMI endpoints, which of course may be used by other application modules on the same machine. | |
---|---|
- 这种RAR部署单元通常是独立的;它们不向外部世界公开组件,甚至不向同一应用程序的其他模块公开组件。与基于rra的ApplicationContext的交互通常是通过JMS目的地进行的,该JMS目的地与其他模块共享。例如,基于rar的ApplicationContext还可以调度一些作业,对文件系统中的新文件(或类似的文件)做出反应。如果它需要允许从外部进行同步访问,例如,它可以导出RMI端点,这当然可以由同一台机器上的其他应用程序模块使用。
1.16. The BeanFactory
The BeanFactory
provides the underlying basis for Spring’s IoC functionality but it is only used directly in integration with other third-party frameworks and is now largely historical in nature for most users of Spring. The BeanFactory
and related interfaces, such as BeanFactoryAware
, InitializingBean
, DisposableBean
, are still present in Spring for the purposes of backward compatibility with the large number of third-party frameworks that integrate with Spring. Often third-party components that can not use more modern equivalents such as @PostConstruct
or @PreDestroy
in order to avoid a dependency on JSR-250.
- BeanFactory为Spring s IoC功能提供了底层基础,但它只在与其他第三方框架集成时被直接使用,对于大多数Spring用户来说,它在本质上已经具有很大的历史意义了。BeanFactory和相关的接口,如BeanFactoryAware、InitializingBean、DisposableBean,仍然存在于Spring中,目的是向后兼容大量与Spring集成的第三方框架。为了避免对JSR-250的依赖,第三方组件通常不能使用更现代的对等物,如@PostConstruct或@PreDestroy。
This section provides additional background into the differences between the BeanFactory
and ApplicationContext
and how one might access the IoC container directly through a classic singleton lookup.
- 本节提供了关于BeanFactory和ApplicationContext之间差异的额外背景知识,以及如何通过经典的单例查找直接访问IoC容器。
1.16.1. BeanFactory or ApplicationContext?
Use an ApplicationContext
unless you have a good reason for not doing so.(使用ApplicationContext,除非你有很好的理由不这样做。)
Because the ApplicationContext
includes all functionality of the BeanFactory
, it is generally recommended over the BeanFactory
, except for a few situations such as in embedded applications running on resource-constrained devices where memory consumption might be critical and a few extra kilobytes might make a difference. However, for most typical enterprise applications and systems, the ApplicationContext
is what you will want to use. Spring makes heavy use of the BeanPostProcessor
extension point (to effect proxying and so on). If you use only a plain BeanFactory
, a fair amount of support such as transactions and AOP will not take effect, at least not without some extra steps on your part. This situation could be confusing because nothing is actually wrong with the configuration.
- 因为ApplicationContext包含BeanFactory的所有功能,所以一般建议使用它而不是BeanFactory,除非在一些情况下,比如在资源受限设备上运行的嵌入式应用程序中,在这些情况下,内存消耗可能非常严重,而额外的几个千字节可能会造成差异。但是,对于大多数典型的企业应用程序和系统,ApplicationContext是您想要使用的。Spring大量使用了BeanPostProcessor扩展点(以实现代理等)。如果您只使用普通的BeanFactory,那么诸如事务和AOP等相当数量的支持将不会生效,至少在您这方面没有一些额外的步骤是不会生效的。这种情况可能令人困惑,因为配置实际上没有任何问题。
The following table lists features provided by the BeanFactory
and ApplicationContext
interfaces and implementations.
- 下表列出了BeanFactory和ApplicationContext接口和实现提供的特性。
Feature | BeanFactory |
ApplicationContext |
---|---|---|
Bean instantiation/wiring | Yes | Yes |
Automatic BeanPostProcessor registration |
No | Yes |
Automatic BeanFactoryPostProcessor registration |
No | Yes |
Convenient MessageSource access (for i18n) |
No | Yes |
ApplicationEvent publication |
No | Yes |
To explicitly register a bean post-processor with a BeanFactory
implementation, you need to write code like this:
- 要显式地用BeanFactory实现注册一个bean后处理器,您需要编写如下代码:
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// populate the factory with bean definitions
// now register any needed BeanPostProcessor instances
MyBeanPostProcessor postProcessor = new MyBeanPostProcessor();
factory.addBeanPostProcessor(postProcessor);
// now start using the factory
To explicitly register a BeanFactoryPostProcessor
when using a BeanFactory
implementation, you must write code like this:
- 在使用BeanFactory实现时,要显式注册BeanFactoryPostProcessor,您必须编写这样的代码:
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(new FileSystemResource("beans.xml"));
// bring in some property values from a Properties file
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("jdbc.properties"));
// now actually do the replacement
cfg.postProcessBeanFactory(factory);
In both cases, the explicit registration step is inconvenient, which is one reason why the various ApplicationContext
implementations are preferred above plain BeanFactory
implementations in the vast majority of Spring-backed applications, especially when using BeanFactoryPostProcessor
s and BeanPostProcessor
s. These mechanisms implement important functionality such as property placeholder replacement and AOP.
- 在这两种情况下,显式注册步骤都不方便,这就是为什么在绝大多数spring支持的应用程序中,不同的ApplicationContext实现比普通的BeanFactory实现更受青睐的原因之一,尤其是在使用BeanFactoryPostProcessors和BeanPostProcessors时。这些机制实现了重要的功能,比如属性占位符替换和AOP。
后续类容戳我^^
本文来自博客园,作者:六爻呈乾,转载请注明原文链接:https://www.cnblogs.com/ilycq/p/13669277.html