Spring 核心技术(2)

接上篇:Spring 核心技术(1)html

version 5.1.8.RELEASEjava

1.3 Bean概述

Spring IoC 容器管理一个或多个bean,他们都是根据提供的配置元数据(例如 XML 中<bean/>定义)建立的。spring

在容器内部,这些 bean 定义以 BeanDefinition 对象进行表示,其中包含(以及其余信息)如下元数据:api

  • 包限定的类名:一般是 bean 的实际实现类
  • Bean 行为配置元素,定义 bean 在容器中的行为方式(范围,生命周期回调等)
  • 引用 bean 执行工做所需的其余 bean,这些引用也称为协做者或依赖项
  • 要在新建立的对象中设置的其余配置。例如链接池中链接池的大小和链接数。

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

属性 转换目标
类(Class) 实例化 Bean
名称(Name) Bean 名称
范围(Scope) Bean 做用范围
构造函数参数(Constructor arguments) 依赖注入
属性(Properties) 依赖注入
自动装配模式(Autowiring mode) 自动装配协做者
延迟初始化模式(Lazy initialization mode) 延迟初始化 Bean
初始化方法(Initialization method) 初始化回调
销毁方法(Destruction method) 销毁回调

除了包含如何建立特定 bean 的 bean 定义以外,ApplicationContext 实现类还容许用户已经在容器外建立的对象进行注册。这些任务经过使用 getBeanFactory() 方法访问应用程序上下文的 Bean 工厂来完成,该方法返回 Bean 工厂的实现类 DefaultListableBeanFactoryDefaultListableBeanFactory 经过 registerSingleton(..)registerBeanDefinition(..) 方法支持此注册过程。然而通常状况下应用程序仅使用经过常规 bean 定义元数据定义的 bean。函数

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

1.3.1 Bean 命名

每一个bean都有一个或多个标识符。这些标识符在托管 bean 的容器中必须是惟一的。一个 bean 一般只有一个标识符。若是它须要多个,则额外的能够被视为别名。this

在基于 XML 的配置元数据中,您可使用 id 属性、name 属性或者二者都用来指定 bean 标识符。id 属性容许您指定一个准确的 id。通常来讲这些名称包含字母和数字('myBean','someService'等),但它们也能够包含特殊字符。若是你想要为 bean 引入其余别名,还能够在 name 属性中指定它们,使用逗号(,)、分号(;)或空格进行分隔。做为历史记录,在 Spring 3.1 以前的版本中,id 属性被定义为一种 xsd:ID 类型,它限制了可用的字符。从 3.1 开始,它被定义为一种 xsd:string 类型。请注意,bean id 在容器内必须惟一,但 XML 解析器不会进行限制。编码

bean 的 nameid 并非必填的。若是你没有显式提供 nameid,则容器会为该 bean 生成惟一的名称。可是若是须要经过使用 ref 元素或 Service Locator 样式按名称引用该 bean 则必须提供名称。在使用内部 Bean 或自动装配协做者时能够不提供名称。.net

Bean命名约定

在命名 bean 时约定使用 Java 实例字段命名规范。也就是说,bean 名称以小写字母开头并遵循驼峰法。这样的名字的例子包括 accountManageraccountServiceuserDaologinController等等。
命名 bean 始终使你的配置更易于阅读和理解。此外,若是使用 Spring AOP,那么在将切面织入使用 name 进行关联的一组 bean 时,它会有很大帮助。

经过类路径中的组件扫描,Spring 按照前面描述的规则为未命名的组件生成 bean 名称:实质上是简单的使用类名并将其初始字符转换为小写。可是,在特殊状况下,当类名中有多个字符且第一个和第二个字符都是大写字母时,原始格式将被保留。Spring 遵循 java.beans.Introspector.decapitalize 定义的规则。

在 Bean 定义以外为其建立别名

在 bean 定义自己中,能够组合使用单个 id shuxing 和任意数量的 name 属性为 bean 提供多个名称。这些名称能够是同一个 bean 的等效别名,在某些状况下颇有用,例如让应用程序中的每一个组件经过使用特定于该组件自己的 bean 名称来引用公共依赖项。

可是,只在 Bean 定义时指定别名是不够的,有时须要为其余地方定义的 bean 引入别名。在大型系统中,每一个子系统之间的配置一般是分离的,每一个子系统都有本身的一组对象定义。在基于 XML 的配置元数据中,您可使用<alias/>元素来完成此任务。如下示例显示了如何执行此操做:

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

在示例中,同一容器中名称为 fromName 的 Bean 在使用这种别名定义以后也能够叫作 toName

例如,子系统 A 的配置元数据经过名称 subsystemA-dataSource 引用数据源。子系统 B 的配置元数据经过名称 subsystemB-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 的配置元数据,则须要在 <bean/> 元素的 class 属性指定对象类型。此 class 属性一般是必需的(对应 BeanDefinition 实例的 Class 属性)。(有关例外的状况,请参阅使用实例工厂方法进行实例化Bean定义继承)。你能够经过如下两种方式之一使用 Class 属性:

  • 容器经过反射调用 Bean 的构造函数(相似于使用 new 运算符的 Java 代码)直接建立 Bean 的状况下指定要构造的 bean 类型。
  • 调用指定包含静态工厂方法的实际类来建立对象,在不太常见的状况下,容器调用类中的静态工厂方法来建立 bean。经过调用静态工厂方法返回的对象类型能够彻底是同一个类或另外一个类。

内部类名
若是要为静态嵌套类配置 bean 定义则必须使用嵌套类的二进制名称。

例如,若是在 com.example 包中有一个类叫作 SomeThing,而且 SomeThing 类有一个静态嵌套类叫作 OtherThing,则 bean 定义中的 class属性值将为 com.example.SomeThing$OtherThing

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

使用构造函数实例化

当您经过构造方法建立 bean 时,全部普通类均可以使用并与 Spring 兼容。也就是说,须要开发的类不须要实现任何特定接口或以某种特定方式进行编码。简单地指定 bean 的类就足够了。取决于指定 bean 使用的 IoC 类型,有时候你可能须要一个默认构造函数。

Spring IoC 容器几乎能够管理你但愿它管理的任何类。它不只限于管理真正的 JavaBean。大多数 Spring 用户更倾向于使用只有一个默认构造函数且在属性以后由合适的 setter 和 getter 的 JavaBean。你还能够在容器中包含一些外部的非 bean 样式类。例如,若是须要使用彻底不符合 JavaBean 规范的传统链接池,Spring 也能够对其进行管理。

使用基于 XML 的配置元数据,你能够按以下方式指定 bean 类:

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

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

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

使用静态工厂方法实例化

定义使用静态工厂方法建立的 bean 时,请使用 class 属性指定包含静态工厂方法的类,并使用 factory-method 属性指定工厂方法自己的名称。你应该可以调用此方法(如后面示例所述,使用可选参数)并返回一个活动对象,随后将其视为经过构造函数建立的对象。这种 bean 定义的一个用途是在传统代码中调用静态工厂。

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

这种方法代表工厂 bean 自己能够经过依赖注入(DI)进行管理和配置。请参阅依赖关系和配置详情

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

相关文章
相关标签/搜索