文章作者:Tyan
博客:[noahsnail.com](http://noahsnail.com
3.3 Bean overview
A Spring IoC container manages one or more beans. These beans are created with the configuration metadata that you supply to the container, for example, in the form of XML <bean/>
definitions.
Spring IoC容器管理一个或多个beans。这些beans由提供给容器的配置元数据生成,例如,XML形式的<bean/>
定义。
Within the container itself, these bean definitions are represented as BeanDefinition
objects, which contain (among other information) the following metadata:
- A package-qualified class name: typically the actual implementation class of the bean being defined.
- Bean behavioral configuration elements, which state how the bean should behave in the container (scope, lifecycle callbacks, and so forth).
- References to other beans that are needed for the bean to do its work; these references are also called collaborators or dependencies.
- Other configuration settings to set in the newly created object, for example, the number of connections to use in a bean that manages a connection pool, or the size limit of the pool.
在容器本身内部,这些bean定义被表示成BeanDefinition
对象,含有以下元数据:
- 包限定的类名:通常是被定义的bean的实现类。
- bean行为配置元素,规定了bean在容器中的行为(作用范围、生命周期回调函数)等等。
- bean工作需要的引用的其它bean,这些引用也被称为协作者或依赖。
- 其它的配置在新创建的对象中设置,例如,bean中使用的连接数量控制着一个连接池,或连接池的大小限制。
This metadata translates to a set of properties that make up each bean definition.
元数据转化为一系列的属性,这些属性构成了每个bean的定义。
Table 3.1. The bean definition
Property | Explained in… |
---|---|
class | Section 3.3.2, “Instantiating beans” |
name | Section 3.3.1, “Naming beans” |
scope | Section 3.5, “Bean scopes” |
constructor arguments | Section 3.4.1, “Dependency Injection” |
properties | Section 3.4.1, “Dependency Injection” |
autowiring mode | Section 3.4.5, “Autowiring collaborators” |
lazy-initialization mode | Section 3.4.4, “Lazy-initialized beans” |
initialization method | the section called “Initialization callbacks” |
destruction method | the section called “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 method getBeanFactory() which returns the BeanFactory implementation DefaultListableBeanFactory
. DefaultListableBeanFactory
supports this registration through the methods registerSingleton(..)
and registerBeanDefinition(..)
. However, typical applications work solely with beans defined through metadata bean definitions.
除了bean定义中包含怎么创建一个指定的bean的信息之外,ApplicationContext
实现也允许用户注册容器之外创建的现有对象。这是通过调用ApplicationContext’s BeanFactory的getBeanFactory()方法完成的,这个方法会返回BeanFactory的实现类DefaultListableBeanFactory
。DefaultListableBeanFactory
支持通过registerSingleton(..)
和registerBeanDefinition(..)
方法来注册。不管怎样,标准应用仅使用通过元数据bean定义定义的beans。
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元数据和人工提供的单例需要尽可能早的进行注册,为了使容器在自动注入及其它的内省步骤时能恰当的推理它们。虽然在一定程度上是支持覆盖现有的元数据和单例的,但运行时新beans的注册(并发实时访问工厂)是不被正式支持的,可能会引起并发访问异常,在容器中的与/或状态不一致。
3.3.1 Naming beans
Every bean has one or more identifiers. These identifiers must be unique within the container that hosts the bean. A bean usually has only one identifier, but if it requires more than one, the extra ones can be considered aliases.
每个bean都有一个或多个标识符。这些托管bean的标识符在容器中必须是唯一的。一个bean通常只有一个标识符,但如果一个bean需要不止一个标识符,其它的标识符会被当成别名。
In XML-based configuration metadata, you use the id
and/or name
attributes to specify the bean identifier(s). The id
attribute allows you to specify exactly one id. Conventionally these names are alphanumeric ('myBean', 'fooService', etc.), but may contain special characters as well. If you want to introduce other aliases to the bean, you can also specify them in the name
attribute, separated by a comma (,
), semicolon (;
), or white space. As a historical note, in versions prior to Spring 3.1, the id
attribute was defined as an xsd:ID
type, which constrained possible characters. As of 3.1, it is defined as an xsd:string
type. Note that bean id
uniqueness is still enforced by the container, though no longer by XML parsers.
在基于XML的配置元数据中,你可以使用id
和/或name
属性指定bean标识符。id
属性允许你指定一个确定的id。按照惯例这些名字是字母数字的('myBean', 'fooService'等等),但也可能包含指定字符。如果你想引入bean其它的别名,你可以在name
属性中指定别名,用逗号 (,
),分号(;
),或空格分开。作为一个历史注解,在之前的Spring 3.1版本,id
属性被定义为一种xsd:ID
类型,可以通过合理字符来约束(XML控制id
唯一性)。从Spring 3.1开始,它被定义为xsd:string
类型。注意bean id
的唯一性仍然是容器强制的,虽然不再通过XML解析器来控制(容器控制id
唯一性)。
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和name不是必须提供的。如果没有明确指定name或id,容器会为bean产生一个唯一的名字。如果你想通过name引用bean,通过使用ref
元素或服务定位器模式查找,你必须提供一个名字。不提供name的动机是与内部bean的使用和协作bean的自动装配有关的。
Bean Naming Conventions
The convention is to use the standard Java convention for instance field names when naming beans. That is, bean names start with a lowercase letter, and are camel-cased from then on. Examples of such names would be (without quotes) 'accountManager', 'accountService', 'userDao', 'loginController', and so forth.
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命名规范
当命名bean时,采用的规范是标准Java实例字段命名规范。bean名称以小写字母开头,采用驼峰式的命名规则。这种命名方式的例子(不带引号)有'accountManager', 'accountService', 'userDao', 'loginController'等等。
一致的命名beans可以使人更容易读懂和理解你的配置,如果你正在使用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).
在classpath中进行组件扫描,Spring会根据上面的规则为未命名组件产生bean名称,本质上来说,是采用简单的类名并将其首字母改成小写。然而在特殊情况下(不平常的),当类名有不止一个字母且第一二个字母都是大写的情况下,会保留最初始的状态。与
java.beans.Introspector.decapitalize
定义中的规则是相同的(Spring也采用这个规则)。
Aliasing a bean outside the bean definition
In a bean definition itself, you can supply more than one name for the bean, by using a combination of up to one name specified by the id
attribute, and any number of other names in the name
attribute. These names can be equivalent aliases to the same bean, and are useful for some situations, such as 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时,通过与id
属性指定的名称相结合,你可以为bean提供不止一个名字,在name
属性中定义任何数量的其它名字。这些名字是同一个bean的等价别名,在一些情况下是非常有用的,例如允许应用中的每个组件通过bean名称引用一个共通的依赖,这个依赖为每个组件本身指定了一个名称。
Specifying all aliases where the bean is actually defined is not always adequate, however. It is sometimes desirable to introduce an alias for a bean that is defined elsewhere. This is commonly the case in large systems where configuration is split amongst each subsystem, each subsystem having its own set of object definitions. In XML-based configuration metadata, you can use the <alias/>
element to accomplish this.
然而在bean实际定义的地方指定所有别名并不总是适当的。有时会要求引入一个在别的地方定义的bean的别名。这通常是在大的系统中而配置被分割在每个子系统中,每个子系统有它知道对象定义集合。在基于XML配置元数据中,你可以使用<alias/>
来完成别名的定义。
<alias name="fromName" alias="toName"/>
In this case, a bean in the same container which is named fromName
, may also, after the use of this alias definition, be referred to as toName
.
在这种情况下,在同一个容器中的bean被命名为fromName
,也可能是在别名定义使用之后,被作为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 name subsystemB-dataSource
. When composing the main application that uses both these subsystems the main application refers to the DataSource via the name myApp-dataSource
. To have all three names refer to the same object you add to the MyApp configuration metadata the following aliases definitions:
例如,子系统A的配置元数据可能通过名称subsystemA-dataSource
引用数据源。子系统B的配置元数据可能通过名称subsystemB-dataSource
引用数据源。当构成主应用的时,主应用使用这些子系统并通过名称myApp-dataSource
引用数据源。为了使这三个名称引用同一个对象,你可以将如下的别名定义添加到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
If you are using Java-configuration, the
@Bean
annotation can be used to provide aliases see Section 3.12.3, “Using the @Bean annotation” for details.
Java配置
如果你正在使用Java配置,
@Bean
注解可以用来提供别名,更多细节请看3.12.3小节, “使用@Bean注解”。
3.3.2 Instantiating beans
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. This class
attribute, which internally is a Class
property on a BeanDefinition
instance, is usually mandatory. (For exceptions, see the section called “Instantiation using an instance factory method” and Section 3.7, “Bean definition inheritance”.) You use the Class
property in one of two ways:
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.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.
如果你使用基于XML的配置元数据,你可以指定对象的类型(或类),它将在<bean/>
元素中的class
属性中进行实例化。class
属性,在BeanDefinition
实例的内部是Class
性质,通常是必需的。(例外的情况,请看"使用实例工厂方法进行实例化"小节和3.7小节,"bean定义继承")。你可以通过以下两种方式中的一种使用Class
属性:
通常情况下,指定要构造的bean类,容器本身通过反射调用bean的构造方法直接创建bean,这与Java代码中使用
new
操作符是等价的。在不常见的情况下,指定包含静态工厂方法的实际类,调用静态工厂方法创建对象,容器在类上调用静态工厂方法创建bean。静态工厂方法调用返回的对象类型可能是同一个类,也可能完全是另一个类。
Inner class names. If you want to configure a bean definition for a
static
nested class, you have to use the binary name of the nested class.
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
Notice the use of the
$
character in the name to separate the nested class name from the outer class name.
内部类命名 如果你想为静态嵌套类配置bean定义,你必须使用嵌套类的二进制名字。
例如,如果你在
com.example
包中有个类叫Foo
,Foo
类中有一个静态嵌套类叫Bar
,'class'
属性在bean定义中的值为
com.example.Foo$Bar
注意名字中
$
符号的使用是为了将外部类名与嵌套类名分隔开。
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容器可以管理任何你想让它管理的类;它不受限于管理真实的JavaBeans。大多数Spring用户更喜欢实际的JavaBeans,在容器中它仅有一个默认(无参)的构造函数,并且属性之后有合适的setters,getters方法。在容器中你也可以有更多外来的非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 the static
factory method and an attribute named factory-method
to specify the name of the factory method itself. You should be able to call this method (with optional arguments as described later) and return a live object, which subsequently is treated as if it had been created through a constructor. One use for such a bean definition is to call static
factories in legacy code.
当定义的bean用静态工厂方法创建时,你可以使用class
属性指定包含静态工厂方法的类,用factory-method
属性指定工厂方法本身的名字。你应该能调用这个方法(用后面描述的可选参数)并且返回一个实时对象,随后对这个对象进行处理,就好像这个对象是通过构造函数创建的一样。这种bean定义的一个用法是在遗留代码(旧代码)中调用静态工厂方法。
The following bean definition specifies that the bean will be created by calling a factory-method. The definition does not specify the type (class) of the returned object, 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 the factory-bean
attribute, specify the name of a bean in the current (or parent/ancestor) container that contains the instance method that is to be invoked to create the object. Set the name of the factory method itself with the factory-method
attribute.
与通过静态工厂方法进行实例化类似,通过实例化工厂方法进行实例化,要从容器中调用现有bean非静态方法创建一个新的bean。使用这种机制,要让class
属性为空,在factory-bean
属性中,在包含实例化方法的当前容器(或父/祖先)中指定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();
private DefaultServiceLocator() {}
public ClientService createClientServiceInstance() {
return clientService;
}
}
One factory class can also hold more than one factory method as shown here:
一个工厂类可以拥有多个工厂方法,如下所示:
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
<bean id="accountService"
factory-bean="serviceLocator"
factory-method="createAccountServiceInstance"/>
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
private static AccountService accountService = new AccountServiceImpl();
private DefaultServiceLocator() {}
public ClientService createClientServiceInstance() {
return clientService;
}
public AccountService createAccountServiceInstance() {
return accountService;
}
}
This approach shows that the factory bean itself can be managed and configured through dependency injection (DI). See Dependencies and configuration in detail.
这个方法展示了工厂bean本身可以通过依赖注入(DI)来管理和配置。更多细节请看"依赖和配置"。
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,Spring容器将通过实例或静态工厂方法来创建对象。相比之下,
FactoryBean
(注意大写)引用了Spring特定的FactoryBean
。