文章作者: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由提供給容器的配置元數(shù)據生成,例如,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
對象,含有以下元數(shù)據:
- 包限定的類名:通常是被定義的bean的實現(xiàn)類。
- bean行為配置元素,規(guī)定了bean在容器中的行為(作用范圍、生命周期回調函數(shù))等等。
- bean工作需要的引用的其它bean,這些引用也被稱為協(xié)作者或依賴。
- 其它的配置在新創(chuàng)建的對象中設置,例如,bean中使用的連接數(shù)量控制著一個連接池,或連接池的大小限制。
This metadata translates to a set of properties that make up each bean definition.
元數(shù)據轉化為一系列的屬性,這些屬性構成了每個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定義中包含怎么創(chuàng)建一個指定的bean的信息之外,ApplicationContext
實現(xiàn)也允許用戶注冊容器之外創(chuàng)建的現(xiàn)有對象。這是通過調用ApplicationContext’s BeanFactory的getBeanFactory()方法完成的,這個方法會返回BeanFactory的實現(xiàn)類DefaultListableBeanFactory
。DefaultListableBeanFactory
支持通過registerSingleton(..)
和registerBeanDefinition(..)
方法來注冊。不管怎樣,標準應用僅使用通過元數(shù)據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元數(shù)據和人工提供的單例需要盡可能早的進行注冊,為了使容器在自動注入及其它的內省步驟時能恰當?shù)耐评硭鼈儭km然在一定程度上是支持覆蓋現(xiàn)有的元數(shù)據和單例的,但運行時新beans的注冊(并發(fā)實時訪問工廠)是不被正式支持的,可能會引起并發(fā)訪問異常,在容器中的與/或狀態(tài)不一致。
?
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的配置元數(shù)據中,你可以使用id
和/或name
屬性指定bean標識符。id
屬性允許你指定一個確定的id。按照慣例這些名字是字母數(shù)字的('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的使用和協(xié)作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命名規(guī)范
當命名bean時,采用的規(guī)范是標準Java實例字段命名規(guī)范。bean名稱以小寫字母開頭,采用駝峰式的命名規(guī)則。這種命名方式的例子(不帶引號)有'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會根據上面的規(guī)則為未命名組件產生bean名稱,本質上來說,是采用簡單的類名并將其首字母改成小寫。然而在特殊情況下(不平常的),當類名有不止一個字母且第一二個字母都是大寫的情況下,會保留最初始的狀態(tài)。與
java.beans.Introspector.decapitalize
定義中的規(guī)則是相同的(Spring也采用這個規(guī)則)。
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
屬性中定義任何數(shù)量的其它名字。這些名字是同一個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實際定義的地方指定所有別名并不總是適當?shù)摹S袝r會要求引入一個在別的地方定義的bean的別名。這通常是在大的系統(tǒng)中而配置被分割在每個子系統(tǒng)中,每個子系統(tǒng)有它知道對象定義集合。在基于XML配置元數(shù)據中,你可以使用<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:
例如,子系統(tǒng)A的配置元數(shù)據可能通過名稱subsystemA-dataSource
引用數(shù)據源。子系統(tǒng)B的配置元數(shù)據可能通過名稱subsystemB-dataSource
引用數(shù)據源。當構成主應用的時,主應用使用這些子系統(tǒng)并通過名稱myApp-dataSource
引用數(shù)據源。為了使這三個名稱引用同一個對象,你可以將如下的別名定義添加到MyApp配置元數(shù)據中:
<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.
現(xiàn)在主應用和每個組件都能通過名稱引用數(shù)據源,這個名稱是唯一的且能保證不與任何其它的定義相沖突(有效的創(chuàng)建了一個命名空間),但它們引用了同一個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
注解可以用來提供別名,更多細節(jié)請看3.12.3小節(jié), “使用@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定義本質上來說是創(chuàng)建一個或多個對象的方法。當問及一個命名bean時,容器會查看這個方法并使用bean定義中封裝的配置元數(shù)據創(chuàng)建(或取得)一個實際的對象。
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的配置元數(shù)據,你可以指定對象的類型(或類),它將在<bean/>
元素中的class
屬性中進行實例化。class
屬性,在BeanDefinition
實例的內部是Class
性質,通常是必需的。(例外的情況,請看"使用實例工廠方法進行實例化"小節(jié)和3.7小節(jié),"bean定義繼承")。你可以通過以下兩種方式中的一種使用Class
屬性:
通常情況下,指定要構造的bean類,容器本身通過反射調用bean的構造方法直接創(chuàng)建bean,這與Java代碼中使用
new
操作符是等價的。在不常見的情況下,指定包含靜態(tài)工廠方法的實際類,調用靜態(tài)工廠方法創(chuàng)建對象,容器在類上調用靜態(tài)工廠方法創(chuàng)建bean。靜態(tài)工廠方法調用返回的對象類型可能是同一個類,也可能完全是另一個類。
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.
?
內部類命名 如果你想為靜態(tài)嵌套類配置bean定義,你必須使用嵌套類的二進制名字。
例如,如果你在
com.example
包中有個類叫Foo
,Foo
類中有一個靜態(tài)嵌套類叫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.
當你使用構造方法創(chuàng)建bean時,所有的正常類都可以被Spring使用和兼容。也就是說,正在進行開發(fā)的類不需要實現(xiàn)任何特定的接口或以特定的方式進行編碼。簡單的指定bean類就足夠了。然而,根據你為指定的bean所使用的IoC類型,你可能需要一個默認的(空的)構造函數(shù)。
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。大多數(shù)Spring用戶更喜歡實際的JavaBeans,在容器中它僅有一個默認(無參)的構造函數(shù),并且屬性之后有合適的setters,getters方法。在容器中你也可以有更多外來的非bean類型的類。例如,如果你需要使用遺留的連接池,這絕對不符合JavaBean規(guī)范,但Spring也可以管理它。
With XML-based configuration metadata you can specify your bean class as follows:
基于XML的配置元數(shù)據你可以用如下方式指定你的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.
更多關于為構造函數(shù)提供參數(shù)(如果有必要的話)的機制和構造對象之后設置對象實例屬性的細節(jié),請看"依賴注入"。
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用靜態(tài)工廠方法創(chuàng)建時,你可以使用class
屬性指定包含靜態(tài)工廠方法的類,用factory-method
屬性指定工廠方法本身的名字。你應該能調用這個方法(用后面描述的可選參數(shù))并且返回一個實時對象,隨后對這個對象進行處理,就好像這個對象是通過構造函數(shù)創(chuàng)建的一樣。這種bean定義的一個用法是在遺留代碼(舊代碼)中調用靜態(tài)工廠方法。
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定義指定了一個通過調用工廠方法創(chuàng)建的bean。定義沒有指定返回對象的類型只有包含工廠方法的類。在這個例子中,createInstance()
必須是一個靜態(tài)方法。
<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.
更多關于為工廠方法提供(可選)參數(shù)的原理和從工廠方法返回對象后設置對象實例屬性的信息,請看"依賴和詳細配置"。
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.
與通過靜態(tài)工廠方法進行實例化類似,通過實例化工廠方法進行實例化,要從容器中調用現(xiàn)有bean非靜態(tài)方法創(chuàng)建一個新的bean。使用這種機制,要讓class
屬性為空,在factory-bean
屬性中,在包含實例化方法的當前容器(或父/祖先)中指定bean的名字,通過調用實例化方法來創(chuàng)建對象。通過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)來管理和配置。更多細節(jié)請看"依賴和配置"。
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容器將通過實例或靜態(tài)工廠方法來創(chuàng)建對象。相比之下,
FactoryBean
(注意大寫)引用了Spring特定的FactoryBean
。