1.3 Bean概述html
Spring IoC 容器管理一个或多个bean,他们都是根据提供的配置元数据(例如 XML 中<bean/>定义)建立的。java
在容器内部,这些 bean 定义以 BeanDefinition 对象进行表示,其中包含(以及其余信息)如下元数据:spring
元数据能够转换为构成每一个 bean 定义的一组属性。下表描述了这些属性:api
属性转换目标
类(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 命名ui
每一个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 的 name 和 id 并非必填的。若是你没有显式提供 name 或 id,则容器会为该 bean 生成惟一的名称。可是若是须要经过使用 ref 元素或Service Locator样式按名称引用该 bean 则必须提供名称。在使用内部 Bean 或自动装配协做者时能够不提供名称。htm
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 定义则必须使用嵌套类的二进制名称。例如,若是在 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)进行管理和配置。