Bean Overview

1.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容器管理一个或多个bean。这些bean是用您提供给容器的配置元数据创建的(例如,以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 size limit of the pool or the number of connections to use in a bean that manages a connection pool.
在容器本身内部,这些bean定义被表示为“BeanDefinition”对象,它包含(在其他信息中)以下元数据:
  • 包限定的类名:通常是正在定义的bean的实际实现类。
  • Bean行为配置元素,它规定Bean在容器中应该如何行为(范围、生命周期回调,等等)。
  • 对bean执行其工作所需的其他bean的引用。这些引用也称为协作者或依赖项。
  • 要在新创建的对象中设置的其他配置设置—例如,池的大小限制或在管理连接池的bean中使用的连接数。

This metadata translates to a set of properties that make up each bean definition. The following table describes these properties:

此元数据转换为组成每个bean定义的一组属性。下表描述了这些属性:
Property Explained in…
Class Instantiating Beans
Name Naming Beans
Scope Bean Scopes
Constructor arguments Dependency Injection
Properties Dependency Injection
Autowiring mode Autowiring Collaborators
Lazy initialization mode Lazy-initialized Beans
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 through the getBeanFactory() method, which returns the DefaultListableBeanFactory implementation. DefaultListableBeanFactory supports this registration through the registerSingleton(..) and registerBeanDefinition(..) methods. However, typical applications work solely with beans defined through regular bean definition metadata.

除了包含如何创建特定bean的信息的bean定义之外,ApplicationContext实现还允许注册在容器外部(由用户)创建的现有对象。这是通过getBeanFactory()方法访问ApplicationContext的BeanFactory来完成的,该方法返回DefaultListableBeanFactory实现。DefaultListableBeanFactory通过registerSingleton(..)和registerBeanDefinition(..)方法支持这种注册。但是,典型的应用程序只使用通过常规bean定义元数据定义的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 existing metadata and existing singleton instances is supported to some degree, the registration of new beans at runtime (concurrently with live access to the factory) is not officially supported and may lead to concurrent access exceptions, inconsistent state in the bean container, or both.

Bean元数据和手动提供的单例实例需要尽早注册,以便容器在自动装配和其他自省步骤期间正确地对它们进行推理。虽然在某种程度上支持覆盖现有的元数据和现有的单例实例,但官方并不支持在运行时注册新bean(与对工厂的实时访问同时进行),这可能会导致并发访问异常、bean容器中的状态不一致,或两者兼而有。

1.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. However, 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 attribute, the name attribute, or both to specify the bean identifiers. The id attribute lets you specify exactly one id. Conventionally, these names are alphanumeric ('myBean', 'someService', etc.), but they can contain special characters as well. If you want to introduce other aliases for 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', ' someeservice '等),但它们也可以包含特殊字符。如果希望引入bean的其他别名,还可以在name属性中指定它们,用逗号(,)分隔。分号(;)或空格。作为一个历史记录,在Spring 3.1之前的版本中,id属性被定义为xsd: id类型,它限制了可能的字符。从3.1开始,它被定义为xsd:string类型。请注意,bean id惟一性仍然由容器强制执行,但不再由XML解析器强制执行。

You are not required to supply a name or an id for a bean. If you do not supply a name or id 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 a 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 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 there. Examples of such names include accountManager, accountService, userDao, loginController, and so forth.

Naming beans consistently makes your configuration easier to read and understand. Also, if you use 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等。

一致地命名bean使您的配置更容易阅读和理解。另外,如果您使用Spring AOP,在将通知应用到一组与名称相关的bean时,它会有很大帮助。

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

通过在类路径中扫描组件,Spring为未命名组件生成bean名,遵循前面描述的规则:本质上,取简单的类名,并将其初始字符转换为小写。但是,在(不寻常的)特殊情况下,当有多个字符并且第一个和第二个字符都是大写字符时,将保留原来的大小写。这些规则与java.beans. introspectordecapitalize (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 letting each component in an application refer to a common dependency by using a bean name that is specific to that component itself.

在bean定义本身中,通过使用id属性指定的最多一个名称和name属性中任意数量的其他名称的组合,您可以为bean提供多个名称。这些名称可以是同一个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, with each subsystem having its own set of object definitions. In XML-based configuration metadata, you can use the <alias/> element to accomplish this. The following example shows how to do so:

但是,指定bean实际定义的所有别名并不总是足够的。有时需要为在其他地方定义的bean引入别名。这种情况在大型系统中很常见,配置被划分到每个子系统中,每个子系统有自己的一组对象定义。在基于xml的配置元数据中,可以使用元素来完成此任务。下面的例子展示了如何这样做:
<alias name="fromName" alias="toName"/>

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

在这种情况下,在使用别名定义之后,名为fromName的bean(在同一个容器中)也可以被称为toName。

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

例如,子系统A的配置元数据可能以子系统- DataSource的名称引用数据源。子系统B的配置元数据可以通过subsystemB-dataSource的名称引用数据源。当组合使用这两个子系统的主应用程序时,主应用程序以myApp-dataSource的名称引用数据源。要让这三个名称都指向同一个对象,可以在配置元数据中添加以下别名定义:
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-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.

现在,每个组件和主应用程序都可以通过一个唯一的名称引用dataSource,该名称保证不会与任何其他定义(实际上创建了一个名称空间)冲突,但它们引用的是同一个bean。

Java-configuration

If you use Javaconfiguration, the @Bean annotation can be used to provide aliases. See Using the @Bean Annotation for details.

如果您使用javconfiguration, @Bean注释可以用来提供别名。有关详细信息,请参阅使用@Bean注释。

1.3.2. Instantiating Beans

A bean definition is essentially 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 Instantiation by Using an Instance Factory Method and Bean Definition Inheritance.) You can 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 with the new operator.
  • To specify the actual class containing the static factory method that is invoked to create the object, in the less common case where the container invokes a static factory method on a class to create the bean. The object type returned from the invocation of the static factory method may be the same class or another class entirely.
如果使用基于xml的配置元数据,则需要在元素的class属性中指定要实例化的对象的类型(或类)。这个类属性(在内部是BeanDefinition实例上的class属性)通常是强制性的。(如有例外,请参阅使用实例工厂方法实例化和Bean定义继承。)使用Class属性有两种方式:
  • 通常,在容器本身通过反射性地调用其构造函数来直接创建bean的情况下,指定要构造的bean类,这在某种程度上相当于使用新操作符的Java代码。
  • 要指定包含用于创建对象的静态工厂方法的实际类,在较不常见的情况下,容器调用类上的静态工厂方法来创建bean。调用静态工厂方法返回的对象类型可以是同一个类,也可以完全是另一个类。

Nested class names

If you want to configure a bean definition for a nested class, you may use either the binary name or the source name of the nested class.

For example, if you have a class called SomeThing in the com.example package, and this SomeThing class has a static nested class called OtherThing, they can be separated by a dollar sign ($) or a dot (.). So the value of the class attribute in a bean definition would be com.example.SomeThing$OtherThing or com.example.SomeThing.OtherThing.

嵌套的类名

如果您希望为嵌套类配置bean定义,您可以使用嵌套类的二进制名称或源名称。

例如,如果您在com中有一个名为SomeThing的类。示例包,这个SomeThing类有一个静态嵌套类OtherThing,它们可以用一个美元符号($)或一个点(.)分隔。因此,bean定义中的class属性值是com.example.SomeThing$OtherThingcom.example.SomeThing.OtherThing美元的东西。

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,它只有一个默认(无参数)构造函数,并根据容器中的属性建模适当的设置器和getter。容器中还可以有更多非bean样式的奇特类。例如,如果您需要使用完全不遵守JavaBean规范的遗留连接池,Spring也可以对其进行管理。

With XML-based configuration metadata you can specify your bean class as follows:

<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, use the class attribute to specify the class that contains 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, but rather the class containing the factory method. In this example, the createInstance() method must be a static method. The following example shows how to specify a factory method:

下面的bean定义指定该bean将通过调用工厂方法来创建。定义没有指定返回对象的类型(类),而是指定包含工厂方法的类。在这个例子中,createInstance()方法必须是一个静态方法。下面的例子展示了如何指定一个工厂方法:
<bean id="clientService"
    class="examples.ClientService"
    factory-method="createInstance"/>

The following example shows a class that would work with the preceding bean definition:

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 by 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 or 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. The following example shows how to configure such a bean:

与通过静态工厂方法进行的实例化类似,使用实例工厂方法进行的实例化从容器中调用现有bean的非静态方法来创建新bean。要使用此机制,请将class属性保留为空,并在factory-bean属性中指定包含用于创建对象的实例方法的当前(或父或祖先)容器中的bean名称。使用factory-method属性设置工厂方法本身的名称。下面的例子展示了如何配置这样一个bean:
<!-- 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"/>

The following example shows the corresponding class:

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 the following example shows:

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

The following example shows the corresponding class:

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.

这种方法表明工厂bean本身可以通过依赖注入(DI)进行管理和配置。详细信息请参见依赖和配置。

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

Determining a Bean’s Runtime Type

The runtime type of a specific bean is non-trivial to determine. A specified class in the bean metadata definition is just an initial class reference, potentially combined with a declared factory method or being a FactoryBean class which may lead to a different runtime type of the bean, or not being set at all in case of an instance-level factory method (which is resolved via the specified factory-bean name instead). Additionally, AOP proxying may wrap a bean instance with an interface-based proxy with limited exposure of the target bean’s actual type (just its implemented interfaces).

特定bean的运行时类型的确定并不简单。bean元数据定义中的指定类只是一个初始类引用,可能与声明的工厂方法结合在一起,或者是可能导致bean的不同运行时类型的FactoryBean类,或者在实例级工厂方法(而是通过指定的工厂bean名称解析)的情况下根本不设置。此外,AOP代理可以用基于接口的代理包装一个bean实例,该代理有限地公开目标bean的实际类型(只公开其实现的接口)。

The recommended way to find out about the actual runtime type of a particular bean is a BeanFactory.getType call for the specified bean name. This takes all of the above cases into account and returns the type of object that a BeanFactory.getBean call is going to return for the same bean name.

了解特定bean的实际运行时类型的建议方法是BeanFactory。调用指定bean名称的getType。这将考虑上述所有情况,并返回BeanFactory的对象类型。getBean调用将返回相同的bean名称。
posted @ 2022-09-02 14:16  丶Jan  阅读(16)  评论(0)    收藏  举报