2.3 Spring Framework 5.x 之Bean概述

Bean 概述

Spring IoC容器管理一个或多个bean。这些bean是使用您提供给容器的配置元数据创建的(例如,以XML 定义的形式 )。

在容器本身内,这些bean定义表示为BeanDefinition 对象,其中包含以下元数据(以及其他信息):

  • 包限定的类名:通常是正在定义的bean的实际实现类。

  • Bean行为配置元素,说明bean在容器中的行为方式(范围,生命周期回调等)。

  • 引用bean执行其工作所需的其他bean。这些引用也称为协作者或依赖项。

  • 要在新创建的对象中设置的其他配置设置 - 例如,池的大小限制或在管理连接池的Bean中使用的连接数。

此元数据转换为组成每个bean定义的一组属性。下表描述了这些属性:

表1. bean定义

属性值解释
ClassInstantiating Beans(实例化的Bean)
NameNaming Beans(Bean的名称)
ScopeBean Scopes(Bean的作用范围)
Constructor argumentsDependency Injection(构造参数,依赖注入)
PropertiesDependency Injection(属性值,依赖注入)
Autowiring mode(自动装配模式)Autowiring Collaborators(自动化协作者)
Lazy initialization modeLazy-initialized Beans(懒惰初始化的Bean)
Initialization methodInitialization Callbacks(初始化回调)
Destruction methodDestruction Callbacks(销毁回调)

除了包含有关如何创建特定bean的信息的bean定义之外,这些ApplicationContext实现还允许注册在容器外部(由用户)创建的现有对象。这是通过方法访问ApplicationContext的BeanFactory来完成的getBeanFactory(),该方法返回BeanFactory DefaultListableBeanFactory实现。DefaultListableBeanFactory 通过registerSingleton(…)和 registerBeanDefinition(…)方法支持此注册。但是,典型应用程序仅适用于通过常规bean定义元数据定义的bean。

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

1.3.1 Bean的命名

每个bean都有一个或多个标识符。这些标识符在托管bean的容器中必须是唯一的。bean通常只有一个标识符。但是,如果它需要多个,则额外的可以被视为别名。

在基于XML的配置元数据中,您可以使用id属性,name属性或两者来指定bean标识符。该id属性允许您指定一个id。通常,这些名称是字母数字(‘myBean’,'someService’等),但它们也可以包含特殊字符。如果要为bean引入其他别名,还可以在name 属性中指定它们,用逗号(,),分号(;)或空格分隔。作为历史记录,在Spring 3.1之前的版本中,该id属性被定义为一种xsd:ID类型,它约束了可能的字符。从3.1开始,它被定义为一种xsd:string类型。请注意,id容器仍然强制执行bean 唯一性,但不再是XML解析器。

您不需要提供一个name或id一个bean。如果您不提供 name或id显式提供,则容器会为该bean生成唯一的名称。但是,如果要通过名称引用该bean,通过使用ref元素或 Service Locator样式查找,则必须提供名称。不提供名称的动机与使用内部bean和自动装配协作者有关。

Bean命名约定

惯例是在命名bean时使用标准Java约定作为实例字段名称。也就是说,bean名称以小写字母开头,并从那里开始驼峰。这样的名字的例子包括accountManager, accountService,userDao,loginController,等等。

命名bean始终使您的配置更易于阅读和理解。此外,如果您使用Spring AOP,那么在将建议应用于与名称相关的一组bean时,它会有很大帮助。

注意:通过类路径中的组件扫描,Spring按照前面描述的规则为未命名的组件生成bean名称:基本上,采用简单的类名并将其初始字符转换为小写。但是,在(不常见的)特殊情况下,当有多个字符并且第一个和第二个字符都是大写字母时,原始外壳将被保留。这些规则与java.beans.Introspector.decapitalize(Spring在此处使用)定义的规则相同。

给Bean定义别名Bean

在bean定义本身中,您可以为bean提供多个名称,方法是使用id属性指定的最多一个名称和属性中的任意数量的其他名称name。这些名称可以是同一个bean的等效别名,对某些情况很有用,例如让应用程序中的每个组件通过使用特定于该组件本身的bean名称来引用公共依赖项。

但是,指定实际定义bean的所有别名并不总是足够的。有时需要为其他地方定义的bean引入别名。在大型系统中通常就是这种情况,其中配置在每个子系统之间分配,每个子系统具有其自己的一组对象定义。在基于XML的配置元数据中,您可以使用该元素来完成此任务。以下示例显示了如何执行此操作:

<alias name="fromName" alias="toName"/>

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

例如,子系统A的配置元数据可以通过名称引用DataSource subsystemA-dataSource。子系统B的配置元数据可以通过名称引用DataSource subsystemB-dataSource。在编写使用这两个子系统的主应用程序时,主应用程序通过名称引用DataSource myApp-dataSource。要使所有三个名称引用同一对象,可以将以下别名定义添加到配置元数据中:

<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>

现在,每个组件和主应用程序都可以通过一个唯一的名称引用dataSource,并保证不与任何其他定义冲突(有效地创建命名空间),但它们引用相同的bean。

Java的配置

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

1.3.2 实例化Bean

bean定义本质上是用于创建一个或多个对象的配置。容器在被询问时查看命名bean的配置,并使用由该bean定义封装的配置元数据来创建(或获取)实际对象。

如果使用基于XML的配置元数据,则指定要在元素的class属性中实例化的对象的类型(或类)。此 class属性(在内部,是 实例Class上的属性BeanDefinition)通常是必需的。(有关例外,请参阅 使用实例工厂方法和Bean定义继承进行实例化。)您可以通过以下Class两种方式之一使用该属性:

  • 通常,在容器本身通过反向调用其构造函数直接创建bean的情况下指定要构造的bean类,稍微等同于使用new运算符的Java代码。

  • 要指定包含static为创建对象而调用的工厂方法的实际类,在不常见的情况下,容器static在类上调用 工厂方法来创建bean。从调用static工厂方法返回的对象类型可以完全是同一个类或另一个类。

内部类名
如果要为static嵌套类配置bean定义,则必须使用嵌套类的二进制名称。

例如,如果你有一个SomeThing在com.example包中调用的类,并且这个 SomeThing类有一个static被调用的嵌套类OtherThing,那么class bean定义中的属性值就是com.example.SomeThing$OtherThing。

请注意,使用$名称中的字符将嵌套类名与外部类名分开。

使用构造函数实例化

当您通过构造方法创建bean时,所有普通类都可以使用并与Spring兼容。也就是说,正在开发的类不需要实现任何特定接口或以特定方式编码。简单地指定bean类就足够了。但是,根据您为该特定bean使用的IoC类型,您可能需要一个默认(空)构造函数。

Spring IoC容器几乎可以管理您希望它管理的任何类。它不仅限于管理真正的JavaBeans。大多数Spring用户更喜欢实际的JavaBeans,只有一个默认(无参数)构造函数,并且在容器中的属性之后建模了适当的setter和getter。您还可以在容器中拥有更多异国情调的非bean样式类。例如,如果您需要使用绝对不符合JavaBean规范的旧连接池,那么Spring也可以对其进行管理。

使用基于XML的配置元数据,您可以按如下方式指定bean类:

<bean id="exampleBean" class="examples.ExampleBean"/>

<bean name="anotherExample" class="examples.ExampleBeanTwo"/>

有关为构造函数提供参数的机制(如果需要)以及在构造对象后设置对象实例属性的详细信息,请参阅 注入依赖项。

使用静态工厂方法实例化

定义使用静态工厂方法创建的bean时,请使用该class 属性指定包含static工厂方法的类和factory-method指定工厂方法本身名称的属性。您应该能够调用此方法(使用可选参数,如稍后所述)并返回一个活动对象,随后将其视为通过构造函数创建的对象。这种bean定义的一个用途是static在遗留代码中调用工厂。

以下bean定义指定通过调用工厂方法来创建bean。该定义未指定返回对象的类型(类),仅指定包含工厂方法的类。在此示例中,该createInstance() 方法必须是静态方法。以下示例显示如何指定工厂方法:

<bean id="clientService"
    class="examples.ClientService"
    factory-method="createInstance"/>

以下示例显示了一个可以使用前面的bean定义的类:

public class ClientService {
    private static ClientService clientService = new ClientService();
    private ClientService() {}

    public static ClientService createInstance() {
        return clientService;
    }
}

有关在从工厂返回对象后为工厂方法提供(可选)参数和设置对象实例属性的机制的详细信息,请参阅依赖关系和详细配置。

使用实例工厂方法实例化

与通过静态工厂方法实例化类似,使用实例工厂方法进行实例化会从容器调用现有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"/>

以下示例显示了相应的Java类:

public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();

    public ClientService createClientServiceInstance() {
        return clientService;
    }
}

一个工厂类也可以包含多个工厂方法,如以下示例所示:

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

以下示例显示了相应的Java类:

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;
    }
}

这种方法表明可以通过依赖注入(DI)来管理和配置工厂bean本身。请参阅详细信息中的依赖关系和配置。

在Spring文档中,“factory bean”是指在Spring容器中配置并通过实例或 静态工厂方法创建对象的bean 。相反, FactoryBean(注意大写)指的是特定于Spring的 FactoryBean。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值