Spring 核心技术(2)
接上篇:Spring 核心技术(1)
version 5.1.8.RELEASE
1.3 Bean概述
Spring IoC 容器管理一个或多个bean,他们都是根据提供的配置元数据(例如 XML 中<bean/>定义)创建的。
在容器内部,这些 bean 定义以 BeanDefinition 对象进行表示,其中包含(以及其他信息)以下元数据:
- 包限定的类名:通常是 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 工厂的实现类 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 类型。请注意,bean id 在容器内必须唯一,但 XML 解析器不会进行限制。
bean 的 name 和 id 并不是必填的。如果你没有显式提供 name 或 id,则容器会为该 bean 生成唯一的名称。但是如果需要通过使用 ref 元素或 Service Locator 样式按名称引用该 bean 则必须提供名称。在使用内部 Bean 或自动装配协作者时可以不提供名称。
Bean命名约定
在命名 bean 时约定使用 Java 实例字段命名规范。也就是说,bean 名称以小写字母开头并遵循驼峰法。这样的名字的例子包括
accountManager、accountService、userDao、loginController等等。
命名 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。
Spring 核心技术(2)的更多相关文章
- Spring核心技术(八)——Spring自动装载的注解
本文针对自动装载的一些注解进行描述. 基于注解的容器配置 @Required注解 @Required注解需要应用到Bean的属性的setter方法上面,如下面的例子: public class Sim ...
- Spring核心技术(六)——Spring中Bean的生命周期
前文已经描述了Bean的作用域,本文将描述Bean的一些生命周期作用,配置还有Bean的继承. 定制Bean 生命周期回调 开发者通过实现Spring的InitializeingBean和Dispos ...
- Spring核心技术(五)——Spring中Bean的作用域
前文概述了Spring的容器,Bean,以及依赖的一些信息,本文将描述一下Bean的作用域 Bean的作用域 当开发者定义Bean的时候,同时也会定义了该如何创建Bean实例.这些具体创建的过程是很重 ...
- Spring核心技术(四)——Spring的依赖及其注入(续二)
前面两篇文章描述了IoC容器中依赖的概念,包括依赖注入以及注入细节配置.本文将继续描述玩全部的依赖信息. 使用 depends-on 如果一个Bean是另一个Bean的依赖的话,通常来说这个Bean也 ...
- Spring 核心技术(3)
接上篇:Spring 核心技术(2) version 5.1.8.RELEASE 1.4 依赖 典型的企业应用程序不会只包含单个对象(或 Spring 术语中的 bean).即使是最简单的应用程序也是 ...
- Spring 核心技术(4)
接上篇:Spring 核心技术(3) version 5.1.8.RELEASE 1.4.2 依赖关系及配置详情 如上一节所述,你可以将 bean 属性和构造函数参数定义为对其他托管 bean(协作者 ...
- Spring 核心技术(5)
接上篇:Spring 核心技术(4) version 5.1.8.RELEASE 1.4.5 自动装配协作者 Spring 容器可以自动连接协作 bean 之间的关系.你可以让 Spring 通过检查 ...
- Spring 核心技术(6)
接上篇:Spring 核心技术(5) version 5.1.8.RELEASE 1.5 Bean 作用域 创建 bean 定义时,你创建了一种用于创建 bean 定义中定义的类实例的方法.bean定 ...
- Spring 核心技术(7)
接上篇:Spring 核心技术(6) version 5.1.8.RELEASE 1.6 定制 Bean 的特性 Spring Framework 提供了许多可用于自定义 bean 特性的接口.本节将 ...
随机推荐
- WPF 数据库增删改查
<Window x:Class="DataBindingExam.MainWindow" xmlns="http://schemas.microsof ...
- C/C++读写csv文件(用getline探测逗号分隔符)
csv文件其实就是文本文件,每行字段用逗号分隔. 代码 #include <iostream> #include <string> #include <vector> ...
- Win8Metro(C#)数字图像处理--2.12Sobel边缘检测
原文:Win8Metro(C#)数字图像处理--2.12Sobel边缘检测 [函数名称] 图像Sobel边缘检测函数SobelEdgeProcess(WriteableBitmap src) [ ...
- Win10《芒果TV》送7天免费会员,邀您抢先看萌心自制《妈妈是超人3》
<妈妈是超人>第三季萌心归来,霍思燕,贾静雯,黄圣依,邓莎联合释放"妈妈的声音",嗯哼,咘咘,波妞,安迪,大麟子五位萌娃共同出镜,萌化屏幕.Win10<芒果TV& ...
- LoadLibrary方法加载运行DLL库
最近和另一家公司对接,要求用对方提供的测试程序测试我们做的DLL. 接到对方的测试程序,发现和我们以前调用DLL的方式不太一样.但我稍微看了一会代码也看懂其意思了,一天搞定了. 但其中也遇到些小困惑, ...
- 一定要在commit之前做RAR备份,这样在出问题的时候,可以排除别人代码的干扰
否则找错实在是太痛苦了,根本不知道来自哪里...而这样上面那样做,可以节省时间.
- 快速开发平台 WebBuilder 8 发布
快速开发平台 WebBuilder 8 发布 了解:http://www.putdb.com,官网:http://www.geejing.com 什么是WebBuilder? WebBuilder是 ...
- 地球坐标-火星坐标-百度坐标及之间的转换算法 C#
美国GPS使用的是WGS84的坐标系统,以经纬度的形式来表示地球平面上的某一个位置.但在我国,出于国家安全考虑,国内所有导航电子地图必须使 用国家测绘局制定的加密坐标系统,即将一个真实的经纬度坐标加密 ...
- js中prototype与__proto__区别
proto(隐式原型)与prototype(显式原型) 显式原型 explicit prototype property:每一个函数在创建之后都会拥有一个名为prototype的属性,这个属性指向函数 ...
- HTML连载7-表单练习
昨天因为晚上有事情,未更新,但是今天中午发也不晚,因为是同一天只是时间早晚而已,因此今日傍晚还将更新一次,废话不多说. 1.表单的综合练习,我们要创建一个综合的注册页面.运用到我们前面所学的所有知识. ...