文档章节

Spring基本原理 - 容器和bean

CarlDing
 CarlDing
发布于 2016/07/12 16:43
字数 3404
阅读 146
收藏 0

Spring IoC容器至少包含一个bean定义,但大多数情况下会有多个bean定义。当使用 基于XML的配置元数据时,将在顶层的<beans/>元素中配置一个 或多个<bean/>元素。

bean定义与应用程序中实际使用的对象一一对应。通常情况下bean的定义包括:服务 层对象、数据访问层对象(DAO)、类似Struts Action的 表示层对象、Hibernate SessionFactory对象、JMS Queue对象等等。通常bean的定义并不与容器中的领域 对象相同,因为领域对象的创建和加载必须依赖具体的DAO和业务逻辑。.

1.以下是一个基于XML的配置元数据的基本结构:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

  <bean id="..." class="...">
    <!-- collaborators and configuration for this bean go here -->
  </bean>

  <bean id="..." class="...">
    <!-- collaborators and configuration for this bean go here -->
  </bean>

  <!-- more bean definitions go here -->

</beans>

2.实例化容器

Spring IoC容器的实例化非常简单,如下面的例子:

ApplicationContext context = new ClassPathXmlApplicationContext(
        new String[] {"services.xml", "daos.xml"});

// an ApplicationContext is also a BeanFactory (via inheritance)
BeanFactory factory = context;

3. XML配置元数据的结构

将XML配置文件分拆成多个部分是非常有用的。为了加载多个XML文件生成一个 ApplicationContext实例,可以将文件路径作为字符串数组传给ApplicationContext构造器 。而bean factory将通过调用bean defintion reader从多个文件中读取bean定义。

通常情况下,Spring团队倾向于上述做法,因为这样各个配置并不会查觉到它们 与其他配置文件的组合。另外一种方法是使用一个或多个的<import/>元素 来从另外一个或多个文件加载bean定义。所有的<import/>元素必 须在<bean/>元素之前完成bean定义的导入。 让我们看个例子:

<beans>

    <import resource="services.xml"/>
    <import resource="resources/messageSource.xml"/>
    <import resource="/resources/themeSource.xml"/>

    <bean id="bean1" class="..."/>
    <bean id="bean2" class="..."/>

</beans>

在上面的例子中,我们从3个外部文件:services.xmlmessageSource.xmlthemeSource.xml 来加载bean定义。这里采用的都是相对路径,因此,此例中的services.xml 一定要与导入文件放在同一目录或类路径,而messageSource.xm lthemeSource.xml的文件位置必须放在导入文件所 在目录下的resources目录中。正如你所看到的那样,开头的斜杠 ‘/’实际上可忽略。因此不用斜杠‘/’可能会更好一点。根据Spring XML配置文件的 Schema(或DTD),被导入文件必须是完全有效的XML bean定义文件,且根节点必须为 <beans/> 元素。

4.多种bean

Spring IoC容器将管理一个或多个bean,这些bean 将通过配置文件中的bean定义被创建(在XML格式中为<bean/> 元素)。

在容器内部,这些bean定义由BeanDefinition 对象来表示,该定义将包含以下信息:

  • 全限定类名:这通常就是已定义bean的实际实现类。

  • bean行为的定义,这些定义将决定bean在容器中的行为(作用域、生命周期回调等等)

  • 对其他bean的引用,这些引用bean也可以称之为协作bean(collaborators) 依赖bean(dependencies).

  • 创建bean实例时的其他配置设置。比如使用bean来定义连接池,可以通过属性或者构 造参数指定连接数,以及连接池大小限制等。

上述内容直接被翻译为每个bean定义包含的一组properties。下面的表格列出了部分 内容的详细链接:

5.表  bean定义

名称 功能
class

 “实例化bean”

name

 “bean的命名”

scope

 “Bean的作用域”

constructor arguments

“注入依赖”

properties

 “注入依赖”

autowiring mode

 “自动装配(autowire)协作者”

dependency checking mode

 “依赖检查”

lazy-initialization mode

“延迟初始化bean”

initialization method

“初始化回调”

destruction method

 “析构回调”

 

除了通过bean定义来描述要创建的指定bean的属性之外,某些 BeanFactory的实现也允许将那些非BeanFactory创建的、已有的用户 对象注册到容器中,比如使用DefaultListableBeanFactoryregisterSingleton(..) 方法。不过大多数应用还是采用 元数据定义为主。

6. bean的命名

bean命名约定

bean的命名采用标准的Java命名约定,即小写字母开头,首字母大写间隔 的命名方式。如accountManageraccountService userDaologinController,等等。

对bean采用统一的命名约定将会使配置更加简单易懂。而且在使用Spring AOP时 ,如果要发通知(advice)给与一组名称相关的bean时,这种简单的命名方式将会令你受益匪浅。

每个bean都有一个或多个id(或称之为标识符或名称,在术语 上可以理解成一回事)。这些id在当前IoC容器中必须唯一。如果 一个bean有多个id,那么其他的id在本质上将被认为是别名。

当使用基于XML的配置元数据时,将通过id name属性来指定bean标识符。id属性具有唯一性, 而且是一个真正的XML ID属性,因此其他xml元素在引用该id时,可以利用XML解析器的 验证功能。通常情况下最好为bean指定一个id。尽管XML规范规定了XML ID命名的有效 字符,但是bean标识符的定义不受该限制,因为除了使用指定的XML字符来作为id,还可 以为bean指定别名,要实现这一点可以在name属性中使用逗号、 冒号或者空格将多个id分隔。

值得注意的是,为一个bean提供一个name并不是必须的,如果没有指定,那么容 器将为其生成一个惟一的name。对于不指定name属性的原因我们会在后面介绍(比如 内部bean就不需要)。

3.2.3.1.1. bean的别名

在对bean进行定义时,除了使用id属性来指定名称 之外,为了提供多个名称,需要通过name属性来加以指定 。而所有的这些名称都指向同一个bean,在某些情况下提供别名非常有用,比如 为了让应用的每一个组件能更容易的对公共组件进行引用。

然而,在定义bean时就指定所有的别名并不是总是恰当的。有时我们期望 能在当前位置为那些在别处定义的bean引入别名。在XML配置文件中,可用 <alias/> 元素来完成bean别名的定义。如:

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

这里如果在容器中存在名为fromName的bean定义, 在增加别名定义之后,也可以用toName来引用。

考虑一个更为具体的例子,组件A在XML配置文件中定义了一个名为 componentA-dataSource的DataSource bean。但组件B却想在其XML文件中 以componentB-dataSource的名字来引用此bean。而且在主程序MyApp的XML配 置文件中,希望以myApp-dataSource的名字来引用此bean。最后容器加载三个 XML文件来生成最终的ApplicationContext,在此情形下,可通过在MyApp XML 文件中添加下列alias元素来实现:

<alias name="componentA-dataSource" alias="componentB-dataSource"/>
<alias name="componentA-dataSource" alias="myApp-dataSource" />

这样一来,每个组件及主程序就可通过唯一名字来引用同一个数据源而互不干扰。

7. 实例化bean

内部类名

如果需要你希望将一个静态的内部类配置为 一个bean的话,那么内部类的名字需要采用二进制的写法。

比如说,在com.example包下有一个叫 Foo的类,而Foo类有一个静态 的内部类叫Bar,那么在bean定义的时候, class属性必须这样写:

com.example.Foo$Bar

注意这里我们使用了$字符将内部类和外部类进行分隔

从本质上来说,bean定义描述了如何创建一个或多个对象实例。当需要的时候, 容器会从bean定义列表中取得一个指定的bean定义,并根据bean定义里面的配置元数据 使用反射机制来创建(或取得)一个实际的对象。

当采用XML描述配置元数据时,将通过<bean/>元素的 class属性来指定实例化对象的类型。class 属性 (对应BeanDefinition实例的 Class属性)通常是必须的(不过也有两种例外的情形,“使用实例工厂方法实例化”“bean定义的继承”)。class属性主要有两种用途 :在大多数情况下,容器将直接通过反射调用指定类的构造器来创建bean(这有点类似于 在Java代码中使用new操作符);在极少数情况下,容器将调用 类的静态工厂方法来创建bean实例,class 属性将用来指定实际具有静态工厂方法的类(至于调用静态工厂 方法创建的对象类型是当前class还是其他的class则无关紧要)。

8. 用构造器来实例化

当采用构造器来创建bean实例时,Spring对class并没有特殊的要求, 我们通常使用的class都适用。也就是说,被创建的类并不需要实现任何特定的 接口,或以特定的方式编码,只要指定bean的class属性即可。不过根据所采用 的IoC类型,class可能需要一个默认的空构造器。

此外,IoC容器不仅限于管理JavaBean,它可以管理任意 的类。不过大多数使用Spring的人喜欢使用实际的JavaBean(具有默认的(无参)构造器 及setter和getter方法),但在容器中使用非bean形式(non-bean style)的类也是可 以的。比如遗留系统中的连接池,很显然它与JavaBean规范不符,但Spring也能管理它。

当使用基于XML的元数据配置文件,可以这样来指定bean类:

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

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

给构造函数指定参数以及为bean实例设置属性将在随后的 部分中谈及。

9. 使用静态工厂方法实例化

当采用静态工厂方法创建bean时,除了需要指定class 属性外,还需要通过factory-method属性来指定创建bean实例 的工厂方法。Spring将调用此方法(其可选参数接下来介绍)返回实例对象,就此而言, 跟通过普通构造器创建类实例没什么两样。

下面的bean定义展示了如何通过工厂方法来创建bean实例。注意,此定义并 未指定返回对象的类型,仅指定该类包含的工厂方法。在此例中, createInstance()必须是一个static方法。

<bean id="exampleBean"
      class="examples.ExampleBean2"
      factory-method="createInstance"/>

给工厂方法指定参数以及为bean实例设置属性将在随后的部份中谈及。

10. 使用实例工厂方法实例化

使用静态工厂方法实例化类似,用来进行实例化的非静态实例工厂方法位 于另外一个bean中,容器将调用该bean的工厂方法来创建一个新的bean实例。为使 用此机制,class属性必须为空,而factory-bean 属性必须指定为当前(或其祖先)容器中包含工厂方法的bean的名称,而该 工厂bean的工厂方法本身必须通过factory-method属性来设定。

<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="com.foo.DefaultServiceLocator">
  <!-- inject any dependencies required by this locator bean -->
</bean>

<!-- the bean to be created via the factory bean -->
<bean id="exampleBean"
      factory-bean="serviceLocator"
      factory-method="createInstance"/>

虽然设置bean属性 的机制仍然在这里被提及,但隐式的做法是由工厂bean自己来管理以及通过依 赖注入(DI)来进行配置。

注意

Spring文档中的factory bean指的是配置在Spring容器中通过使用 实例 静态工厂方法创建对象的一种bean。而文档中的FactoryBean (注意首字母大写)指的是Spring特有的 FactoryBean

11. 使用容器

从本质上讲,BeanFactory仅仅只是一个 维护bean定义以及相互依赖关系的高级工厂接口。通过BeanFactory 我们可以访问bean定义。下面的例子创建了一个bean工厂,此工厂 将从xml文件中读取bean定义:

Resource res = new FileSystemResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(res);

基本上就这些了,接着使用getBean(String) 方法就可以取得bean的实例;BeanFactory 提供的方法极其简单。 BeanFactory接口提供 了非常多的方法,但是对于我们的应用来说,最好永远不要调用它们,当然也包括 使用getBean(String)方法,这样可以避免我们对 Spring API的依赖。

© 著作权归作者所有

上一篇: 依赖
下一篇: AOP
CarlDing
粉丝 5
博文 106
码字总数 78103
作品 0
济南
其他
私信 提问
三条路线告诉你如何掌握Spring IoC容器的核心原理

一、前言 前三篇已经从历史的角度和大家一起探讨了为什么会有Spring,Spring的两个核心概念:IoC和AOP的雏形,Spring的历史变迁和如今的生态帝国。本节的主要目的就是通过一个切入点带大家一...

Java小铺
2018/08/27
0
0
2014-03-10 Spring的学习(2)------依赖注入和自动扫描Bean

1.依赖注入(DI)的概念 所谓的依赖注入是指在运行期,由外部容器将依赖对象注入到组件中.依赖注入(DI)背后的基本原理是对象之间的依赖关系(即一起工作的其它对象).例如:Service业务层依赖D...

查封炉台
2014/03/10
282
0
Spring 管理Bean(获取Bean,初始化bean事件,自动匹配ByName······等)

1.实例化spring容器 和 从容器获取Bean对象 实例化Spring容器常用的两种方式: 方法一: 在类路径下寻找配置文件来实例化容器 [推荐使用] ApplicationContext ctx = new ClassPathXmlApplicat...

长平狐
2013/01/06
5.7K
0
【Spring实战】注入非Spring Bean对象

大家经常用到Spring IOC去管理对象之间的依赖关系,但一般情况下都有一个前提:这些Bean对象必须是通过Spring容器创建实例化的。 但实际上,项目中有可能会遇到这样的场景: 一个类不是通过S...

Carl_
2015/01/06
1K
0
Spring中管理Bean依赖注入之后和Bean销毁之前的行为

对于Singleton作用域的Bean,Spring容器将会跟踪它们的生命周期,容器知道何时实例化结束、何时销毁。Spring可以管理Bean在实例化结束之后和Bean销毁之前的行为。 Bean依赖关系注入之后的行为...

摆渡者
2014/03/06
5.4K
0

没有更多内容

加载失败,请刷新页面

加载更多

75、GridFS

GridFS是MongoDB提供的用于持久化存储文件的模块,CMS使用Mongo DB存储数据,使用FGridFS可以快速集成开发。 工作原理: 在GridFS存储文件是将文件分块存储,文件会按照256KB的大小分割成多个...

lianbang_W
39分钟前
4
0
js bind 绑定this指向

本文转载于:专业的前端网站➱js bind 绑定this指向 1、示例代码 <!DOCTYPE html><html lang="zh"> <head> <meta charset="UTF-8" /> <title>bind函数绑定this指向......

前端老手
42分钟前
4
0
CentOS Linux 7上将ISO映像文件写成可启动U盘

如今,电脑基本上都支持U盘启动,所以,可以将ISO文件写到U盘上,用来启动并安装操作系统。 我想将一个CentOS Linux 7的ISO映像文件写到U盘上,在CentOS Linux 7操作系统上,执行如下命令: ...

大别阿郎
49分钟前
4
0
深入vue-公司分享ppt

组件注册 全局注册 注册组件,传入一个扩展过的构造器 Vue.component('my-component', Vue.extend({/*...*/})) 注册组件,传入一个选项对象(自动调用Vue.extend) Vue.component('my-comp...

莫西摩西
50分钟前
4
0
gitlab重置管理员密码

登录gitlab服务器 [root@localhost bin]# sudo gitlab-rails console productionLoading production environment (Rails 5.2.3)irb(main):001:0> u = User.where(email: 'admin@example.co......

King华仔o0
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部