Spring翻转控制器.docx
- 文档编号:30132709
- 上传时间:2023-08-05
- 格式:DOCX
- 页数:86
- 大小:305.69KB
Spring翻转控制器.docx
《Spring翻转控制器.docx》由会员分享,可在线阅读,更多相关《Spring翻转控制器.docx(86页珍藏版)》请在冰豆网上搜索。
Spring翻转控制器
Chapter 3. 控制反转容器
3.1. 简介
本章将详细深入地探讨Spring框架的控制反转实现(InversionofControl,IoC)[1]原理。
Spring框架所提供的众多功能之所以能成为一个整体正是建立在IoC的基础之上,因此对这一内涵简单、外延丰富的技术我们有必要进行详细的介绍。
接口选择之惑
在实际应用中,用户有时候不知道到底是选择BeanFactory接口还是ApplicationContext接口。
但是通常在构建J2EE应用时,使用ApplicationContext将是更好的选择,因为它不仅提供了BeanFactory的所有特性,同时也允许使用更多的声明方式来得到我们想要的功能。
org.springframework.beans及org.springframework.context包是SpringIoC容器的基础。
BeanFactory提供的高级配置机制,使得管理任何性质的对象成为可能。
ApplicationContext是BeanFactory的扩展,功能得到了进一步增强,比如更易与SpringAOP集成、消息资源处理(国际化处理)、事件传递及各种不同应用层的context实现(如针对web应用的WebApplicationContext)。
简而言之,BeanFactory提供了配制框架及基本功能,而ApplicationContext则增加了更多支持企业核心内容的功能。
ApplicationContext完全由BeanFactory扩展而来,因而BeanFactory所具备的能力和行为也适用于ApplicationContext。
本章分为两部份,第一部份讲解BeanFactory及ApplicationContext的基本原理,而第二部份则针对ApplicationContext的功能进行讲解。
3.2. 容器和bean的基本原理
在Spring中,那些组成应用的主体(backbone)及由SpringIoC容器所管理的对象被称之为bean。
简单地讲,bean就是由Spring容器初始化、装配及被管理的对象,除此之外,bean就没有特别之处了(与应用中的其他对象没有什么区别)。
而bean定义以及bean相互间的依赖关系将通过配置元数据来描述。
为什么使用bean?
使用'bean'这个名字而不是'组件'(component)或'对象'(object)的动机源于Spring框架本身(部分原因则是相对于复杂的EJB而言的)。
3.2.1. 容器
org.springframework.beans.factory.BeanFactory是SpringIoC容器的实际代表者,IoC容器负责容纳此前所描述的bean,并对bean进行管理。
在Spring中,BeanFactory是IoC容器的核心接口。
它的职责包括:
实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
Spring为我们提供了许多易用的BeanFactory实现,XmlBeanFactory就是最常用的一个。
该实现将以XML方式描述组成应用的对象以及对象间的依赖关系。
XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。
SpringIoC容器
3.2.1.1. 配置元数据
从上图可以看到,SpringIoC容器将读取配置元数据;并通过它对应用中各个对象进行实例化、配置以及组装。
通常情况下我们使用简单直观的XML来作为配置元数据的描述格式。
在XML配置元数据中我们可以对那些我们希望通过SpringIoC容器管理的bean进行定义。
Note
到目前为止,基于XML的元数据是最常用到的配置元数据格式。
然而,它并不是唯一的描述格式。
SpringIoC容器在这一点上是完全开放的。
在本文写作时,Spring支持三种配置元数据格式:
XML格式、Java属性文件格式或使用Spring公共API编程实现。
由于XML元数据配置格式简单明了,因而本章采用该格式来表达SpringIoC容器的主要理念和特性。
多种资源
对IoC容器基本原理的掌握将有利于我们对Chapter 4,资源中Resource抽象机制的理解。
SpringIoC容器可以通过多种途径来加载配置元数据,比如本地文件系统、JavaCLASSPATH等。
在大多数的应用程序中,并不需要用显式的代码去实例化一个或多个的SpringIoC容器实例。
例如,在web应用程序中,我们只需要在web.xml中添加(大约)8行简单的XML描述符即可(参见Section 3.8.4,“ApplicationContext在WEB应用中的实例化”)。
SpringIoC容器至少包含一个bean定义,但大多数情况下会有多个bean定义。
当使用基于XML的配置元数据时,将在顶层的
bean定义与应用程序中实际使用的对象一一对应。
通常情况下bean的定义包括:
服务层对象、数据访问层对象(DAO)、类似StrutsAction的表示层对象、HibernateSessionFactory对象、JMSQueue对象等等。
项目的复杂程度将决定bean定义的多寡。
以下是一个基于XML的配置元数据的基本结构:
xmlversion="1.0"encoding="UTF-8"?
>
//www.springframework.org/schema/beans" xmlns: xsi="http: //www.w3.org/2001/XMLSchema-instance" xsi: schemaLocation=" http: //www.springframework.org/schema/beanshttp: //www.springframework.org/schema/beans/spring-beans-2.0.xsd"> --collaboratorsandconfigurationforthisbeangohere--> --collaboratorsandconfigurationforthisbeangohere--> --morebeandefinitionsgohere...--> 3.2.2. 实例化容器 SpringIoC容器的实例化非常简单,如下面的例子: Resourceresource=newFileSystemResource("beans.xml"); BeanFactoryfactory=newXmlBeanFactory(resource); ...或... ClassPathResourceresource=newClassPathResource("beans.xml"); BeanFactoryfactory=newXmlBeanFactory(resource); ...或... ApplicationContextcontext=newClassPathXmlApplicationContext( newString[]{"applicationContext.xml","applicationContext-part2.xml"}); //ofcourse,anApplicationContextisjustaBeanFactory BeanFactoryfactory=(BeanFactory)context; 3.2.2.1. 组成基于XML配置元数据 将XML配置文件分拆成多个部分是非常有用的。 为了加载多个XML文件生成一个ApplicationContext实例,可以将文件路径作为字符串数组传给ApplicationContext构造器。 而beanfactory将通过调用beandefintionreader从多个文件中读取bean定义。 通常情况下,Spring团队倾向于上述做法,因为这样各个配置并不会查觉到它们与其他配置文件的组合。 另外一种方法是使用一个或多个的 所有的 让我们看个例子: 在上面的例子中,我们从3个外部文件: services.xml、messageSource.xml及themeSource.xml来加载bean定义。 这里采用的都是相对路径,因此,此例中的services.xml一定要与导入文件放在同一目录或类路径,而messageSource.xml和themeSource.xml的文件位置必须放在导入文件所在目录下的resources目录中。 正如你所看到的那样,开头的斜杠‘/’实际上可忽略。 因此不用斜杠‘/’可能会更好一点。 根据SpringXML配置文件的Schema(或DTD),被导入文件必须是完全有效的XMLbean定义文件,且根节点必须为 3.2.3. 多种bean 诚如此前所言,SpringIoC容器将管理一个或多个bean,这些bean将通过配置文件中的bean定义被创建(在XML格式中为 在容器内部,这些bean定义由BeanDefinition对象来表示,该定义将包含以下信息: ∙全限定类名: 这通常就是已定义bean的实际实现类。 如果通过调用staticfactory方法来实例化bean,而不是使用常规的构造器,那么类名称实际上就是工厂类的类名。 ∙bean行为的定义,即创建模式(prototype还是singleton)、自动装配模式、依赖检查模式、初始化以及销毁方法。 这些定义将决定bean在容器中的行为 ∙用于创建bean实例的构造器参数及属性值。 比如使用bean来定义连接池,可以通过属性或者构造参数指定连接数,以及连接池大小限制等。 ∙bean之间的关系,即协作(或者称依赖)。 上述内容直接被翻译为每个bean定义包含的一组properties。 下面的表格列出了部分内容的详细链接: Table 3.1. bean定义 名称 链接 class Section 3.2.3.2,“实例化bean” name Section 3.2.3.1,“命名bean” scope Section 3.4,“bean的作用域” constructorarguments Section 3.3.1,“注入依赖” properties Section 3.3.1,“注入依赖” autowiringmode Section 3.3.6,“自动装配(autowire)协作者” dependencycheckingmode Section 3.3.7,“依赖检查” lazy-initializationmode Section 3.3.5,“延迟初始化bean” initializationmethod Section 3.5.1,“Lifecycle接口” destructionmethod Section 3.5.1,“Lifecycle接口” 除了通过bean定义来描述要创建的指定bean的属性之外,某些BeanFactory的实现也允许将那些非BeanFactory创建的、已有的用户对象注册到容器中,比如使用DefaultListableBeanFactory的registerSingleton(..)方法。 不过大多数应用还是采用元数据定义为主。 3.2.3.1. 命名bean bean命名约定 bean的命名采用标准的Java命名约定,即小写字母开头,首字母大写间隔的命名方式。 如accountManager、accountService、userDao及loginController,等等。 对bean采用统一的命名约定将会使配置更加简单易懂。 而且在使用SpringAOP时,如果要发通知(advice)给与一组名称相关的bean时,这种简单的命名方式将会令你受益匪浅。 每个bean都有一个或多个id(或称之为标识符或名称,在术语上可以理解成一回事)。 这些id在当前IoC容器中必须唯一。 如果一个bean有多个id,那么其他的id在本质上将被认为是别名。 当使用基于XML的配置元数据时,将通过id或name属性来指定bean标识符。 id属性具有唯一性,而且是一个真正的XMLID属性,因此其他xml元素在引用该id时,可以利用XML解析器的验证功能。 通常情况下最好为bean指定一个id。 尽管XML规范规定了XMLID命名的有效字符,但是bean标识符的定义不受该限制,因为除了使用指定的XML字符来作为id,还可以为bean指定别名,要实现这一点可以在name属性中使用逗号、冒号或者空格将多个id分隔。 值得注意的是,为一个bean提供一个name并不是必须的,如果没有指定,那么容器将为其生成一个惟一的name。 对于不指定name属性的原因我们会在后面介绍(比如内部bean就不需要)。 3.2.3.1.1. bean的别名 在对bean进行定义时,除了使用id属性来指定名称之外,为了提供多个名称,需要通过alias属性来加以指定。 而所有的这些名称都指向同一个bean,在某些情况下提供别名非常有用,比如为了让应用的每一个组件能更容易的对公共组件进行引用。 然而,在定义bean时就指定所有的别名并不是总是恰当的。 有时我们期望能在当前位置为那些在别处定义的bean引入别名。 在XML配置文件中,可用单独的 如: 这里如果在容器中存在名为fromName的bean定义,在增加别名定义之后,也可以用toName来引用。 考虑一个更为具体的例子,组件A在XML配置文件中定义了一个名为componentA-dataSource的DataSourcebean。 但组件B却想在其XML文件中以componentB-dataSource的名字来引用此bean。 而且在主程序MyApp的XML配置文件中,希望以myApp-dataSource的名字来引用此bean。 最后容器加载三个XML文件来生成最终的ApplicationContext,在此情形下,可通过在MyAppXML文件中添加下列alias元素来实现: 这样一来,每个组件及主程序就可通过唯一名字来引用同一个数据源而互不干扰。 3.2.3.2. 实例化bean 就SpringIoC容器而言,bean定义基本上描述了创建一个或多个实际bean对象的内容。 当需要的时候,容器会从bean定义列表中取得一个指定的bean定义,并根据bean定义里面的配置元数据使用反射机制来创建一个实际的对象。 因此这一节将讲解如何告知SpringIoC容器我们将要实例化的对象的类型以及如何实例化对象。 当采用XML描述配置元数据时,将通过 class属性(对应BeanDefinition实例的Class属性)通常是必须的(不过也有两种例外的情形,见Section 3.2.3.2.3,“使用实例工厂方法实例化”和Section 3.6,“bean定义的继承”)。 class属性主要有两种用途: 在大多数情况下,容器将直接通过反射调用指定类的构造器来创建bean(这有点等类似于在Java代码中使用new操作符);在极少数情况下,容器将调用类的静态工厂方法来创建bean实例,class属性将用来指定实际具有静态工厂方法的类(至于调用静态工厂方法创建的对象类型是当前class还是其他的class则无关紧要)。 3.2.3.2.1. 用构造器来实例化 当采用构造器来创建bean实例时,Spring对class并没有特殊的要求,我们通常使用的class都适用。 也就是说,被创建的类并不需要实现任何特定的接口,或以特定的方式编码,只要指定bean的class属性即可。 不过根据所采用的IoC类型,class可能需要一个默认的空构造器。 此外,IoC容器不仅限于管理JavaBean,它可以管理任意的类。 不过大多数使用Spring的人喜欢使用实际的JavaBean(具有默认的(无参)构造器及setter和getter方法),但在容器中使用非bean形式(non-beanstyle)的类也是可以的。 比如遗留系统中的连接池,很显然它与JavaBean规范不符,但Spring也能管理它。 当使用基于XML的元数据配置文件,可以这样来指定bean类: 给构造函数指定参数以及为bean实例设置属性将在随后的部份中谈及。 3.2.3.2.2. 使用静态工厂方法实例化 当采用静态工厂方法创建bean时,除了需要指定class属性外,还需要通过factory-method属性来指定创建bean实例的工厂方法。 Spring将调用此方法(其可选参数接下来介绍)返回实例对象,就此而言,跟通过普通构造器创建类实例没什么两样。 下面的bean定义展示了如何通过工厂方法来创建bean实例。 注意,此定义并未指定返回对象的类型,仅指定该类包含的工厂方法。 在此例中,createInstance()必须是一个static方法。 class="examples.ExampleBean2" factory-method="createInstance"/> 给工厂方法指定参数以及为bean实例设置属性将在随后的部份中谈及。 3.2.3.2.3. 使用实例工厂方法实例化 与使用静态工厂方法实例化类似,用来进行实例化的实例工厂方法位于另外一个已有的bean中,容器将调用该bean的工厂方法来创建一个新的bean实例 为使用此机制,class属性必须为空,而factory-bean属性必须指定为当前(或其祖先)容器中包含工厂方法的bean的名称,而该工厂bean的工厂方法本身必须通过factory-method属性来设定(参看以下的例子)。 --thefactorybean,whichcontainsamethodcalledcreateInstance()--> ... --thebeantobecreatedviathefactorybean--> factory-bean="myFactoryBean" factory-method="createInstance"/> 虽然设置bean属性的机制仍然在这里被提及,但隐式的做法是由工厂bean自己来管理以及通过依赖注入(DI)来进行配置。 3.2.4. 使用容器 从本质上讲,BeanFactory仅仅只是一个维护bean定义以及相互依赖关系的高级工厂接口。 通过BeanFactory我们可以访问bean定义。 下面的例子创建了一个bean工厂,此工厂将从xml文件中读取bean定义: InputStreamis=newFileInputStream("beans.xml"); BeanFactoryfactory=newXmlBeanFactory(is); 基本上就这些了,接着使用getBean(String)方法就可以取得bean的实例;BeanFactory提供的方法极其简单。 它仅提供了六种方法供客户代码调用: ∙booleancontainsBean(String): 如果BeanFactory包含给定名称的bean定义(或bean实例),则返回true ∙ObjectgetBean(String): 返回以给定名字注册的bean实例。 根据bean的配置情况,如果为singleton模式将返回一个共享的实例,否则将返回一个新建的实例。 如果没有找到指定的bean,该方法可能会抛出BeansException异常(实际上将抛出NoSuchBeanDefinitionException异常),在对bean进行实例化和预处理时也可能抛出异常 ∙ObjectgetBean(String,Class): 返回以给定名称注册的bean实例,并转换为给定class类型的实例,如果转换失败,相应的异常(BeanNotOfRequiredTypeException)将被抛出。 上面的getBean(String)方法也适用该规则。 ∙ClassgetType(Stringname): 返回给定名称的bean的Class。 如果没有找到指定的bean实例,则抛出NoSuchBeanDefinitionException异常。 ∙booleanisSingleton(String): 判断给定名称的bean定义(或bean实例)是否为singleton模式(singleton将在bean的作用域中讨论),如果bean没找到,则抛出NoSuchBeanDefinitionException异常。 ∙String[]getAliases(String): 返回给定bean名称的所有别名。 3.3. 依赖 典型的企业应用不会只由单一的对象(或bean)组成。 毫无疑问,即使最简单的系统也需要多个对象一起来满足最终用户的需求。 接下来的的内容除了阐述如何单独定义一系列bean外,还将描述如何让这些bean对象一起协同工作来实现一个完整的真实应用。 3.3.1. 注入依赖 依赖注入(DI)背后的基本原理是对象之间的依赖关系(即一起工作的其它对象)只会通过以下几种方式来实现: 构造器的参数、工厂方法的参数,或给由构造函数或者工厂方法创建的对象设置属性。 因此,容器的工作就是创建bean时注入那些依赖关系。 相对于由bean自己来控制其实例化、直接在构造器中指定依赖关系或者类似服务定位器(Serv
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Spring 翻转 控制器