fen999

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  0 随笔 :: 3 文章 :: 0 评论 :: 0 Trackbacks

转载自www.easyjf.com 版权归原作者所有
《深入
Spring 2 :轻量级 J2EE 开发框架原理与实践》

( 作者:蔡世友 吴 嘉俊  冯煜   张钰 )

 

简介:

  本书首先是一本通过通俗案例讲解 Spring 的教程;同时也是一本深入挖掘 Spring 及相关框架结构、设计原理的书;更是一本探讨 J2EE 软件开发中的艺术的书。本书还想讲述一条开源框架设计中金科玉律:思想决定一切,万变不离其宗。

本书分成四个部分,第一部分是 Spring 新手上路,主要讲解轻量级构架中的相关概念、发展过程、所涉及到的相关技术及详细使用方法等;第二部分是一个综合的案例,讲解如何使用 Spring 及相关技术来构建 J2EE 应用;第三部分是 Spring 的原理部分,主要探讨 Spring 框架的结构,设计原理, Spring 项目源码分析等,让我们深入到 Spring 的核心;本书的第四部分主要探讨开源领域的一些相关话题,让大家对开源有更加深入的认识。

为了能让大家了解 Spring 、学会 Spring 、透视 Spring 的内核、掌握 Spring 的设计原理、领略 Java 艺术之精妙,我们为此做了很多工作。我们在 EasyJF 开源交流社区上开通了一个专用于解决轻量级 J2EE 开发问题的栏目,并请专人负责解决大家在学习及工作过程中遇到的问题,网址: http://www.easyjf.com/bbs 。另外我们还通过 EasyJF 把本书核心案例作为一个持续的开源项目,会长期根据 Spring 的变更而更新, SVN 地址: http://svn.easyjf.com/repository/easyjf/spring-road/

当然,由于时间仓促及作者水平有限,本书难免带有一些不成熟的观点,不可避免存在一些问题。为此,我们将通过 SVN 及交流论坛对本书的补充内容进行不断更新,以确保广大的读者能接触最新、最实用的 Spring 技术。书中存在的问题及不足之处,还请您多给我们提建议及意见,谢谢!

 

关于本书的电子版本发布申明:

  在出版社及本书全部作者的一致同意下,本书的一些重要章节将在互联网免费公开发行,欢迎各大网站及媒体在保留作者及版权申明的前提下转载,本书电子版本不得用于收费发布及平面发行。

另外,由于本书还处于最后组稿阶段,因此,电子版与最终出版的图书内容会存在一定的差异,我们将会通过 EasyJF 官网及相关网站上对电子版进行即时更新。

 

致谢:

在创作本书的过程中, EasyJF 开源的 williamRyam 、天一、瞌睡虫、云淡风轻、与狼共舞、 abc netgod navImg2 等很多成员给予了很我们很大的帮助,在此深表感谢。

 

作者邮箱:

蔡世友  caishiyou@sina.com.cn

嘉俊  stef_wu@163.com

冯 煜  fengyu8299@126.com

张 钰  zhangyu20030607@hotmail.com

 

第二章  Spring 概述及入门

 

目 录

 

第二章 Spring 概述及入门 ... 1

2.1 Spring 简介 ... 1

2.1.1 什么是 Spring . 1

2.1.2 Rod Johnson  Spring 团队及 Spring 交流社区 ... 1

2.1.3 Spring 能做什么 ... 2

2.1.4 Spring 框架总体构架 ... 3

2.2 开始 Spring 之旅 ... 6

2.2.1 获取 Spring . 6

2.2.2 Spring 项目文件简介 ... 8

2.2.3 查看 Spring 源码 ... 11

2.2.4 使用 Spring . 15

2.3 示例:用 Spring 来组装电脑 ... 19

2.3.1 示例简介 ... 19

2.3.2 定义 Bean- 定义电脑的组成配件并实现电脑的设计 ... 19

2.3.3 实现 Bean- 提供可供选择的配件 ... 23

2.3.4 配置 Bean- 组装电脑 ... 28

2.3.5 应用 Bean- 使用电脑 ... 29

2.3.6 发布 Bean- 把电脑交给客户 ... 30

2.3.7 传统的组装 ... 32

2.3.8 示例角色浅析 ... 33

2.4 分享 Spring 学习方法 ... 34

2.5 小结 ... 35

2.6 思考题 ... 35


 

第二章 Spring 概述 及入门

Spring 是一个开源的 J2EE 应用程序框架,其在轻量级 J2EE 开发中扮演着非常重要的角色。本章主要对 Spring 的作一个总体上的介绍,包括 Spring 是什么、 Spring 团队及 Spring 相关社区、 Spring 的功能体系、如何开始 Spring 等,本章最后还通过一个通俗、完整的 Spring 应用示例,演示了 Spring 在应用程序中所扮演的角色及作用,最后讲解了一些关于如何学好 Spring 的方法。

2.1 Spring 简介

   Spring 是什么? Spring 能为我们做什么?为什么我们选择使用 Spring Spring 由哪些功能部件组成?这是本节讲述的话题。

2.1.1 什么是 Spring

Spring Rod 主创的一个应用于 J2EE 领域的轻量应用程序框架,其核心是一个 IOC 容器以及 AOP 实现,在核心上面的一个主要部件是数据访问 DAO 框架,包括一个自己的 JDBC 数据访问封装以及对众多 ORM 系统的集成支持。 Spring 还内置一个功能强大、灵活的 Web MVC 框架,以提供快速的 Java Web 应用程序开发,同时 Spring 还提供了以其它各种 MVC 框架或视图技术的集成。通过 Spring 的核心容器及 AOP 的应用, Spring 提供了统一的声明式系统级服务支持。

Spring 的设计思想很多来源于 Rod Johnson 所写的《 Expert One-on-One J2EE Design and Development 》这本书。

Spring 项目在开源领域是一个非常活跃的项目,有着很多活跃的开源技术社区支持,在全世界范围内拥有不少的用户群体。 Spring 提供了众多优秀开源项目的集成,包括与各种优秀的 Web 框架集成,与优秀的开源持久层 ORM 系统集成,与动态语言的集成,与其它企业级应用的集成等。

可以这么说,由于 Spring 是主动去适应变化,去整合其他优秀的开源项目及技术,再加上 Spring 优秀的设计构架,其可扩展性非常强。所以 Spring 能很容易就把其它开源项目整合到其应用体系中,于是给我们看到的就是一个基于 Spring 核心体系,无所不能的 J2EE 应用程序框架。

2.1.2 Rod Johnson  Spring 团队及 Spring 交流社区

Rod Johnson  Spring Framework 的创建者,也是 Java J2EE 领域中的知名专家。 Rod  Interface21 公司的 CEO ,该公司是一家致力于提供专业级 J2EE Spring Framework 服务的咨询公司。谈到 Rod Johnson ,除了 Spring 框架本身以外,他所著作的《 Expert One-on-One J2EE Development without EJB 》一书,其影响力比 Spring 框架本身还更加震撼。

现在 Spring 团队已经成立了公司,除了提供商业咨询及顾问服务以外,公司还有几十个固定的工作人员在负责维护 Spring 项目,工作内容包括修改 Spring 中的 Bug 、为 Spring 增加新功能、解答 Spring 用户的问题等。相比其它一些开源项目, Spring 的发布以及更新都非常活跃,能快速适应市场的变化。 Spring 2004 年初发布 1.0 版本,到 2006 10 3 发布了 2.0 版本,基本上维持着每半年就会有一次大的更新。

Spring 官方交流社区, http://forum.springframework.org/ ,官方网站提供非常活跃的技术交流,只要你提出一个问题,都会有很多大师级的人物迅速给予解答。作为商业上的支持, Inteface21 公司专注于提供基于 Spring 技术框架的 J2EE 技术咨询服务,其官方网站为 , http://www.springframework.com/ http://www.interface21.com/ ,当然 java 开源社区也有很多著名的网站提供 Spring 的技术交流,如 TSS(http://www.theserverside.com) 等。

2.1.3 Spring 能做什么

n         容器功能

Spring 的一个强大之处是他能代替 EJB 容器,负责管理用户基于 POJO 方式写的业务逻辑组件,具有类似 EJB 容器的功能,同时也是轻量级容器的代表。关于“轻量级容器”,我们将在下一章的“轻容器时代”一节详细讲述。 (POJO ,全称 Plain Old Java Objects -简单的 Java 对象,实际就是普通 JavaBeans ,使用 POJO 的目的在于区别 EJB ,且简称比较直接,有一些属性及 getter setter 方法 !)

Spring 所管理的对象及组件,统一叫做 Bean 。跟其它的轻量级容器一样, Spring 的容器除了最基本的贮存功能以外,同时也具有对象及组件创建 (Bean 工厂负责生产 Bean )功能,还具有 Bean 之间的依赖及相关关系管理以及 Bean 生命周期管理的功能。也就是说, Spring 负责管理 Bean 的创建、提供基于配置文件、声明式的 Bean 组装方式,自动管理 Bean 之间的相互依赖关系及 Bean 的生命周期。

另外, Spring 核心容器还为基于 POJO Bean 提供一些基础性的系统服务,通过引入 AOP 技术,实现了声明式的事务、安全、日志管理等功能。通过使用 AOP ,用户还能根据实际项目需要设计并实现自己的切面,解决横切交叉关注点中的问题。

n         黏合剂 / 组装功能

Spring 已经把很多优秀开源项目以一种非常优雅的方式集成在一起,同时 Spring 用户也可以把自己项目中开发的组件或框架非常方便的集成到 Spring 中,然后享受 Spring 核心容器提供的各种服务。在这里, Spring 更多的扮演了黏合剂角色,他就像一个强力的黏合剂,以一种非常简单、统一的方式就能把各种各样、五花八门的组件、工具及项目等组合到一起,然后形成一个可交付的 J2EE 应用软件。因此,也可以说 Spring 具有组装功能,通过组装的方式来构建一个系统。

n         企业应用开发实用工具集

Spring 提供了很多轻量级应用开发实践的工具集合,这些工具集以接口、抽象类、或工具类的形式存在于 Spring 中。通过使用这些工具集,可以实现应用程序与各种开源技术及框架间的友好整合。比如有关 jdbc 封装的数据访问工具 Spring JDBC ,有关编写单元测试的 spring test 包以及 spring-mock ,有关访问动态脚本语言的 Spring Script ,另外还有发送邮件的工具 Spring Mail 、日程及任务处理工具 Spring scheduling 等。

可以这么说,大多数企业级应用开发中经常涉及到的一些通用的问题,都可以通过 Spring 提供的一些实用工具包轻松解决。

n         通用实践抽象

Spring 的开发者本身都有着非常丰富、涉及领域非常的广泛的 J2EE 应用开发经验。因此,框架内置了很多在实践中积累而来的通用问题的解决方案。比如,在 Spring 中,我们随处可以看到一种称为 Template 的机制,封装了很多实用的模板代码,然后以回调的形式让用户根据自己的实际情况完成个性化需求的代码填写,比如 Spring 中有关 jdbc 的封装、 DAO 的应用、访问 JNDI 资源、访问 EJB 、访问 Web Service 等。

 

总体来说, Spring 有自己的表示层 MVC 框架,有自己的持久层数据访问工具,有自己的核心容器,可以灵活使用声明式系统级服务,还有很多实用的企业级应用开发中经常要用到的实用工具集及通用问题的解决方案,并且能与任何有用的 J2EE 或非 J2EE 技术集成。因此,可以这么说,如果你是一个 Spring 忠实爱好者,并了解 Spring 的各组成部分并能充分利用其提供的各种实用工具,完全可以把他作为企业应用开发的一整套解决方案。只有在需要的时候,引入 EJB 技术或 Web Service 技术来解决分布式应用问题,然后再集成到 Spring 中即可。

当然, Spring 有一个很让人称道的理念:不把自己的世界观强加给用户!强调的是一种自由观念,用户可以自由选择自己熟悉的技术及框架开发自己的组件 ( 不需要依赖于 Spring 的任何东西 ) ,然后再把他们组合放到 Spring 中运行。

2.1.4 Spring 框架总体构架

  下面我们通过引用 Spring 参考文档中的一些图,从而对 Spring 有一个总体上认识。首先来看一下 Spring 框架的总体结构图,如“图 2-1 。我们从下往上看,最底层是 Spring 框架的核心 IOC 容器,也是 Spring 最基础的部分, Spring 的其它功能大多都依赖于这个核心容器来支撑。紧接着 Spring 核心容器上是 Spring AOP 层, Spring 有自己单独的 AOP 实现,同时还集成了 AspectJ AOP 功能。因为数据访问层都考虑了声明式事务处理等,因此在 AOP 层上面是 Spring 的数据访问层。数据访问层包括两大部分, DAO 部分主要是 Spring jdbc 的封装以及事务管理, ORM 部分是 Spring 与其它各种轻持久层对象-关系映射框架的整合及集成,如 Hibernate JPA 等。然后再往图的右边看有两大部分, JEE 部分封装了企业级应用中的一些常用服务及功能,如 JMS Email EJB Remoting 等; WEB 部分主要是 Spring 自己的 MVC 实现以及与其它 MVC 框架(如 Struts Tapestry JSF ) 的综合集成等。

2-1   Spring 框架总体结构图

 

从上面的图可以看到, Spring 提供了很多 J2EE 应用的基础设施及解决方案,便于我们开发 J2EE 应用, Spring 是一个非常灵活、松散的框架。除了 J2EE 应用,还可以用于其它各种各样的场景。下面通过列举一些常用的应用程序场景,演示 Spring 如何在这些应用中发挥作用。

先来看一个完整 Spring MVC WEB 应用,如“图 2-2 。通过使用 Spring 声明式事务管理,可以把事务声明及管理用于普通的 POJO 。最外层是 Spring MVC 框架,中间是 Spring IOC 核心容器,即 Web 应用上下文。在容器中还有其它业务逻辑层组件,这些组件可以使用 Spring DAO 访问数据或者使用 Spring 集成的第三方持久层框架(如 Hibernate )进行数据访问。最底层仅仅只需要一个 Web 容器。

2-2  基于 Spring MVC 框架的完整 Web 应用

 

当然也可以只选择使用 Spring 的核心容器及 AOP 功能,表示层及持久层使用第三方的解决方案,此时一个基于 Spring 应用框架的 J2EE 应用如“图 2-3 所示,最外层是 Web MVC 层,可以是 Struts WebWork EasyJWeb 等。业务逻辑层是普通的 POJO ,数据访问层使用其它 ORM 框架,业务逻辑层及数据访问层都可以使用 Spring 提供的声明式事务特性,主要由 Spring AOP 来负责,再往下看是 Spring 的核心容器,最后是 Web 容器。

2-3 基于第三方 MVC 框架的 Spring Web 应用

在一些更大型的企业级应用中,需要访问远程的服务, Spring 同样能发挥作用。此时业务逻辑层通过 Spring 提供的远程访问包,可以轻松实现访问远端的服务,如“图 2-4

2-4   Spring 的远程访问

2.2 开始 Spring 之旅

  通过前面小节的介绍,已经对 Spring 有一个总体的认识。然而我们从哪儿得到 Spring ?如何开始一个 Spring 的应用项目实践?如何在项目中使用 Spring ?在本节中,将通过图文结合的方式,讲解 Spring 的下载、安装及使用。

2.2.1 获取 Spring

首先到 Spring 官方网站下载 Spring ,网址是 http://www.springframework.org/ ,点击 download 栏目,进入下载页面,如“图 2-5

2-5 Spring 官方网站

然后点击需要下载的 Spring 版本,作为研究我们推荐尽量选择最新的版本,如当前的 Spring Framework 2.0 ,即可进入 www.sourceforge.net 中下载 Spring 的源代码,如“图 2-6

2-6 SourceForge Spring 下载连接

( 备注: SourceForge 是全球最大的开放源代码软件开发平台和仓库,它集成了很多开放源代码应用程序,为软件开发提供了整套生命周期服务。 SourceForge.net 是开放源代码软件的开发者进行开发管理的集中式场所,也是源代码仓库。 )

通过点击 SourceForge Spring 项目相应的连接,即可开始下载 Spring2.0 的整个项目源码,如“图 2-7

2-7 Spring 项目下载服务器选择

2.2.2 Spring 项目文件简介

下载完后,得到一个类似 spring-framework-2.0-xxx.zip 的压缩包,然后我们解压该压缩文件,即可见到 Spring 的项目文件,如“图 2-8

2-8 Spring 项目文件

n         根目录

在根目录上,主要是 Spring 开源项目的 ant 脚本文件 build.xml maven 脚本 maven.xml 等。我们可以在命令行输入 ant tests 来运行 Spring 的所有测试代码,另外还可以使用 ant build ant alljars 实现在本机上根据自己的 jdk 重新编译 Spring 、并生成相关的 jar 包。

在根目录上,还有 spring 的发布协议说明 license.txt 、项目说明 readme.txt 、变更日志 changelog.txt 、注意事项 notice.txt 等文件。

n         dist 目录

Spring 项目的文件中, dist 是已经编译打包好的发布 jar dist 中的文件结构如“图 2-9 所示:

2-9 dist 文件目录中的内容

其中 spring-src.zip Spring 源码的压缩包, spring.jar 是整个 Spring 源代码经过编译后的打包文件, spring-mock.jar spring 提供用于单元测试中模仿对象的相关类, spring-aspects.jar spring aspectj 的集成的 jar 包。 Resources 目录是 spring 项目的相关资源文件,如配置文件描述符 spring-beans.dtd 等。

dist 中的 modules 目录是 spring 各组成部分单独发布的 jar 包。因为 Spring 的各组成部分是完全独立的,用户可以只选择使用 Spring 中的一部分功能,此时可以只直接使用相关部分 jar 文件即可。比如只用 spring mvc 就选择 spring-webmvc.jar ,要用 Srping 中的 jdbc 封装可以直接选择 spring-jdbc.jar modules 目录中的内容如“图 2-10 所示。

2-10 modules 目录中的内容

n         docs 目录

docs 目录是 Spring 项目的文档目录,里面主要包括 Spring 项目使用说明文档及系统 API 等,在 Spring2.0 的项目中,包括 api 文档、 spring mvc 应用简单示例、 spring 参考手册、 spring 标签库简介等几个部分,如“图 2-11

2-11 docs 目录中的内容

n         mock 目录

mock 目录是 Spring 用于单元测试中模仿对象的 mock 实现源代码,也就是 spring-mock.jar 中的源码。

n         aspectj 目录

aspectj 目录是 Spring AspectJ 集成的源代码及应用测试代码。

n         src 目录

   src 目录是 Spring 项目的全部源代码。

n         samples 目录

   samples 目录是 Spring 项目的应用程序示例源代码,主要包括一个简单的网上商店 jpetstore ,一个宠物医院 petclinic 。另外还有演示一些特殊功能的简单示例,如 countries imagedb 等。通过这些示例程序代码,可以快速学习到 Spring 使用方法。

n         test 目录

   test 目录是 Spring 项目的单元测试代码, Spring 作为测试驱动开发的推崇者,有着非常详细的单元测试用例,通过单元测试代码,可以快速掌握 Spring 各个类的方法。

n         tiger 目录

   tiger Spring 项目中使用 java tiger 版中的新功能及特性的源代码,包括注解等。

n         lib 目录

lib 目录中包括了 Spring 项目用到的所有 jar 文件, Spring 一个特点就是提供了对很多主流框架的集成支持,很多功能是在一些现存的项目上搭建起来的。因此,要使用这些特性,必须在项目中引入相关的 jar 。在 Spring lib 目录中,这些 jar 文件分门别类的存放于 lib 的子目录中,如“图 2-12所示。

2-12 lib 目录中的内容

2.2.3 查看 Spring 源码

由于 Spring 的功能相当强大,其源代码的数据以及源代码的层次结构等都相当复杂,因此需要借助专业的 Java 开发工具,来查看 Spring 的项目源码。 Spring2.0 的源代码需要在 Jdk1.5 以上的版本才能全部正常编译。下面演示在 Eclipse 中如何打开 Spring 的源代码:

第一步,在 Eclipse 新建一个工程,在 新建工程 对话框中,选择 create project from existing source ,然后通过浏览文件对话框选择 Spring 项目的主目录,如“图 2-13 所示。

2-13  选择 Spring 项目目录

  第二步,选择好 Spring 项目的目录后,点击 next 按钮, Eclipse 会加载 Spring 项目文件,进入项目的 setting 配置对象框。该对话框中我们主要检查 Source (源代码目录)及 Libraries( 相关 jar ) 两个部分,分别如“图 2-14及“ 2-15 所示。

  

2-14   Spring 项目的源码路径

2-15   Spring 项目所需要的 jar 库文件

  第三步,点击 完成 finish 按钮,完成项目的创建,这里即可通过在 Eclipse package explorer 视图面板中查看到 Spring 项目的源代码,如“图 2-16 所示。

2-16 Spring 项目源码总体结构

2.2.4 使用 Spring

  要在项目中使用 Spring ,需要把 Spring 编译打包后的 jar 文件引入到项目的 Classpath 中。通过直接使用 Spring 的相关 jar 包,开始使用 Spring 。下面演示使用 Eclipse 开发一个简单的 Spring 示例程序。

  第一步,使用 Eclipse new project 向导,新建一个名为 spring-hello 的工程。

  第二步,新建一个名为 Hello 的类, package 选择 com.easyjf ,如“图 2-17 所示。

2-17 新建项目

第三步, 把所需要使用的 Spring 项目 jar 的文件加入到当前工程的 Libraries 中,本例中只使用 Spring 的简单 IOC 功能,只需要 spring-beans.jar spring-core.jar 以及 commons-logging.jar 三个包即可。

右键点击工程名称,查看工程属性,选择工程属性中的 Java Builder Path ,然后选择 Libraries 选项,通过点击 add external jar 按钮来把外部的 jar 文件添加到工程项目中。 如下图所示:

2-18 jar 添到构建路径

 

第四步, 录入 Hello.java 的完整源代码,其中 Hello 这个类有一个 msg 属性,有一个 setMsg 方法用于设置 msg 属性的值。另外,我们直接在 Hello main 方法中使用 Spring Bean 工厂来从配置文件中加载一个名为 helloBean ,类型为 com.easyjf.Hello Bean 。然后调用这个 Bean sayHello 方法。全部源代码如下所示:

package com.easyjf;

import org.springframework.beans.factory.BeanFactory;

import org.springframework.beans.factory.xml.XmlBeanFactory;

import org.springframework.core.io.ClassPathResource;

import org.springframework.core.io.Resource;

public class Hello {

       private String  msg;

       public void setMsg(String msg)

       {

              this.msg=msg;

       }

       public void sayHello()

       {

              System.out.print(msg);

       }    

      

       public static void main(String[] args) {

              Resource res=new ClassPathResource("com/easyjf/bean.xml");

              BeanFactory factory=new XmlBeanFactory(res);

              Hello hello=(Hello)factory.getBean("helloBean");

              hello.sayHello();

       }

}

 

第五步 ,在与 Hello.java 同级的目录下,建一个名为 bean.xml Spring 配置文件,在这个 Bean 配置文件中定义 helloBean ,并通过依赖注入设置 helloBean msg 属性值,其内容如下:

  <? xml version = "1.0" encoding = "UTF-8" ?>

<! DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" >

< beans >

   < bean id = "helloBean" class = "com.easyjf.Hello" >

       < property name = "msg" value = " 这是最简单的 Spring 示例 !" />

   </ bean >   

</ beans >

 

完成后的工程项目如“图 2-19 所示。

2-19   Hello 项目结构图

 

第六步, 运行程序,在 Hello.java 上点右键,选择 Run As 下面的 Java Application 。即可运行这个使用了 Spring 的程序,该程序将输出 helloBean 中的 msg 属性的值:“这是最简单的 Spring 示例 ! ”,如“图 2-20所示。

2-20   Spring 版的 Hello 程序输出结果

到这里为止,我们就完成了一个最简单的 Spring 应用实践。

这个例子我们使用了 Spring IOC 功能。具体来说就是通过一个资源文件 (Resource) res ,创建一个 Bean 工厂实例 factory ,然后再通过 factory 来查找程序中需要使用的 Bean ,最后使用具体的 Bean 完成相应的工作。

当然,这个示例说明不了多少问题,没有展示出 Spring 的特长。下一节我们将通过一个组装电脑的示例来演示 Spring IOC 的强大功能。

2.3 示例:用 Spring 来组装电脑

  在上一节,我们学习了怎样在自己的项目中使用 Spring ,并通过一个 Spring 版本的 Hello 程序演示了 Spring IOC 的功能。在这一节,我们将通过一个通俗完整的 OOP 应用示例,演示 Spring 在构建松散耦合的系统过程中的作用及功能。

2.3.1 示例简介

大多数搞软件的朋友,都有组装电脑的经历,选择什么样的主板、硬盘、 CPU 、显示器都是值得仔细研究的,要考虑价格、要考虑款式、或者是商家的售后服务质量等等很多因素。今天这里不是讨论怎么组装电脑,而是想通过组装电脑的示例,演示一下 Spring 通过灵活的组装 Bean ,像搭积木一样堆积成一个能实现客户所需功能的软件。

我们知道,一台电脑由主板、硬盘、 CPU 及其它输入输出设备等组成,只有电脑的各个组成部分都能运行,电脑才能正常工作。而在企业级的应用软件中,很多时候我们会有很多的对象,这些对象之间有一定的关系,有些对象需要在其它对象都正常的情况下才能工作,把这些结构关联的类有机地组织到一切,就形成一个可用的组件。

    下面我们以电脑这个实体为例子,演示使用 Spring 来灵活组装一台电脑,然后把一个完整的电脑提供给客户使用。

2.3.2 定义 Bean - 定义电脑的组成配件并实现电脑的设计

在这个示例中,我们假设每台电脑由内存、主板、 CPU 三个基本的电脑元件组成,内存及 CPU 需要插在主板上才能工作。我们假定有各式各样的主板、内存及 CPU 可供选择,因此可通过 Java 接口来抽象各配件的定义。下面我们先来做关于各个配件的接口设计。

首先是电脑配件最基本的接口 PCComponent ,该接口的 UML 如“图 2-21 所示:

2-21 PCComponent 类图

其代码如下:

package springroad.deomo.chap2;

public interface PCComponent {

       String getName();// 名称

       double getPrice();// 价格

       String getCompany();// 厂家  

}

 

CPU 接口表示所有 CPU 的抽象, CPU 接口的 UML 如“图 2-22 所示:

2-22 CPU 类图

其代码如下:

package springroad.deomo.chap2;

public interface CPU extends PCComponent{     

       int getSpeed();// 处理器速度

       void doInstr(); // 做指令运算

       void outResult();// 输出结果

}

Ram 接口表示所有内存的抽象,该接口的 UML 如“图 2-23 所示:

2-23 Ram 类图

其代码如下:

package springroad.deomo.chap2;

public interface Ram extends PCComponent{

int getSize();// 内存大小

void inData();// 读数据

void outData();// 取数据

}

 

Mainboard 接口表示所有主板的抽象,该接口的 UML 如“图 2-24 所示:

2-24 Mainboard 类图

Mainboard 接口的代码如下所示:

package springroad.deomo.chap2;

public interface Mainboard extends PCComponent {

void setCpu(CPU cpu);// 安装 cpu

CPU getCpu();// 得到主板上的 CPU

void setRam(Ram ram);// 安装内存

Ram getRam();// 得到主板上的内存

boolean havePower();// 是否有电源

void startPower();// 开电源

void shutdownPower();// 关电源

}

   

完成了电脑各组成部分的定义后,就可以来开始实现电脑 Computer 类的设计了。在这个示例中,我们假设电脑主要由一个主板 mainboard 组成,电脑有开机 start 、关机 shutdown 以及工作 doWork 等动作,另外还可以通过 getSetting getPrice 等方法返回电脑的配置及价格信息。 Computer UML 类图如“图 2-25 所示:

2-25 Computer 类图

下面是 Computer 类的全部代码:

package springroad.deomo.chap2;

public class Computer {

private Mainboard mainboard;// 主板

// 电脑的显示器、鼠标键等其它属性省略

public void setMainboard(Mainboard mainboard) {

       this.mainboard = mainboard;

}

public void doWork()

{

System.out.println(" 开始工作 ...");

for(int i=0;i<100;i++)

       System.out.print(i+"  ");

System.out.println(" 结束工作 !");

}

public void start()

{

       mainboard.startPower();

}

public void shutdown()

{

       mainboard.shutdownPower();

}

public double getPrice()

{

       return mainboard.getPrice()+mainboard.getCpu().getPrice()+mainboard.getRam().getPrice();

}

public String getSetting()// 读取电脑配置信息以及价格总额

{

       String ret;

       ret=" 电脑组成如下 ! 主板 :"+mainboard.getName()+" CPU:"+mainboard.getCpu().getName()+" ,内存 :"+mainboard.getRam().getName()+"\n";

       ret+=" 这个配置的价格为: "+getPrice();

       return ret;

}

}

 

“图 2-26 显示了这个示例设计的总体 UML 结构图,图中的 AbstractMainboard 表示主板的抽象,将在后面讲解。

2-26  装机示例的 UML 结构图

2.3.3 实现 Bean - 提供可供选择的配件

    在上面的配件设计及 Computer 类中相关的业务逻辑代码中,还缺少具体的主板、 CPU 以及内存实现,由于每种配件可选择的类别很多,不同厂家生产的配件除了一些标准定义的共性以外,还有自己的特性。因此,光有接口就类似于只有一个配件接口标准 ( 一个空壳的电脑 ) Computer 是无法工作的,下面需要分别提供主板、 CPU 及内存的实现。作为惯例,我们把实现写在 impl 包下面。

(1) 、提供可供选择的具体主板 Mainboard

下面我们先来看主板 Mainboard 的实现。虽然主板 Mainboard 有多种多样,但其一些业务逻辑是差不多的。因此,我们先通过一个抽象类 AbstractMainboard 来定义主板 Mainboard 的一些共同的业务逻辑,然后再让具体的主板类继承该抽象类即可, Mainboard 接口下的相关类的 UML 如“图 2-27 所示:

2-27 主板实现的类图

 

下面是 AbstractMainboard 的全部代码:

    package springroad.deomo.chap3.impl;

 

import springroad.deomo.chap2.CPU;

import springroad.deomo.chap2.Mainboard;

import springroad.deomo.chap2.Ram;

public abstract class AbstractMainboard implements Mainboard {

       private CPU cpu;

       private Ram ram;   

       private boolean power;

       public void setCpu(CPU cpu) {

              this.cpu=cpu;

       }

       public CPU getCpu() {  

              return cpu;

       }

       public void setRam(Ram ram) {

              this.ram=ram;

       }

       public Ram getRam() { 

              return ram;

       }

       public boolean havePower() {

              // TODO Auto-generated method stub

              return power;

       }

       public void startPower() {

              power=true;

       }

       public void shutdownPower() {

              power=false;

       }

}

   通过继承主板抽象类,我们提供两种可供选择的主板,即 AUSU 生产的主板以及 Intel 生产的主板。其中 AUSUBoard 类的代码如下:

package springroad.deomo.chap2.impl;

public class AUSUBoard extends AbstractMainboard {

       public String getName() {

              return "AUSU 主板 ";

       }

       public double getPrice() {

              return 3000.00;

       }

       public String getCompany() {

              return "SUSU 公司 ";

       }    

}

IntelBoard 类的代码如下:

   package springroad.deomo.chap2.impl;

public class IntelBoard extends AbstractMainboard {

       public String getName() {

              return "Intel 主板 ";

       }

       public double getPrice() {

              return 3500.00;

       }

       public String getCompany() {

              return "Intel 公司 ";

       }    

}

(2) 、提供具体可供选择的 CPU 实现

   在本示例中,我们暂时只提供两款可供选择的 CPU ,分别是 Intel CPU ,以及 AMD CPU UML 结构如“图 2-28 所示:

2-28 CPU 实现的类图

IntelCPU 类的代码如下:

package springroad.deomo.chap2.impl;

import springroad.deomo.chap2.CPU;

public class IntelCPU implements CPU {

       public int getSpeed() {

              return 1700;

       }

       public void doInstr() {

       System.out.println(" 做指令运算 ");             

       }

       public void outResult() {      

       }

       public String getName() {    

              return "IntelCPU";

       }

       public double getPrice() {

              return 2500;

       }

       public String getCompany() {      

              return "Intel 公司 ";

       }

}

    AMDCpu 类的代码如下:

package springroad.deomo.chap2.impl;

import springroad.deomo.chap2.CPU;

public class AMDCpu implements CPU {

       public int getSpeed() {

              return 1500;

       }

       public void doInstr() {

       System.out.println(" 做指令运算 ");             

       }

       public void outResult() {             

       }

       public String getName() {    

              return "AMD CPU";

       }

       public double getPrice() {

              return 1800;

       }

       public String getCompany() {      

              return "AMD 公司 ";

       }

}

 

(3) 、提供可供选择的具体的内存 Ram 实现

   作为演示,本例我们也只提供两款可供选择的内存。分别是 Kingmax 的内存,以及 Kingstone 的内存。 Ram 相关类的 UML 如“图 2-29 所示:

2-29 Ram 实现的类别

其中 KingmaxRam 类的代码如下:

package springroad.deomo.chap2.impl;

import springroad.deomo.chap2.Ram;

public class KingmaxRam implements Ram {

       public int getSize() {            

              return 512;

       }

       public void inData() {

       // 读入数据

       }

       public void outData() {

       // 输出数据

       }

       public String getName() {

              return "Kingmax 内存 ";

       }

       public double getPrice() {     

              return 300;

       }

       public String getCompany() {      

              return "Kingmax 公司 ";

       }

}

    KingstoneRam 类的代码如下:

package springroad.deomo.chap3.impl;

import springroad.deomo.chap3.Ram;

public class KingstoneRam implements Ram {

       public int getSize() {            

              return 512;

       }

       public void inData() {

              // 读入数据

              }

              public void outData() {

              // 输出数据

              }

              public String getName() {

                     return "Kingstone 内存 ";

              }

              public double getPrice() {     

                     return 200;

              }

              public String getCompany() {      

                     return "Kingstone 公司 ";

              }

 

}

 

    这样,我们已经有了具体的 Computer 类,有了各个具体的配件实现。接下来要做的就是,根据用户的喜好,选择相关的配件组装到电脑里面,从而形成一个可以工作的电脑。

2.3.4 配置 Bean - 组装电脑

    下面在 springroad.deomo.chap3 这个包下面建设一个 Spring Bean 配置文件,我们随便取一个名字,这里为 computer-bean.xml 。配置文件中的内容如下:

    <? xml version = "1.0" encoding = "UTF-8" ?>

<! DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" >

< beans >

   < bean id = "myMainboard" class = "springroad.demo.chap2.impl.IntelBoard" >

       < property name = "ram" >< bean class = "springroad.demo.chap2.impl.KingmaxRam" /></ property >

       < property name = "cpu" >< bean class = "springroad.demo.chap2.impl.IntelCPU" /></ property >

   </ bean >   

   < bean id = "myComputer" class = "springroad.demo.chap2.Computer" >      

       < property name = "mainboard" ref = "myMainboard" />

   </ bean >

</ beans >

    在配置文件中,通过 <bean> 标签来定义了一个 id myMainboard 的主板,一个 id myComputer 的电脑。通过 <bean> 标签下的 < property > 分别设置了主板上选择的具体的内存 Ram CPU ,另外还通过 myComputer < property > 标签设置了 mainboard 属性为 myMainboard

2.3.5 应用 Bean - 使用电脑

    下面,写一个简单的客户端程序来运用 Computer 对象,做一些简单的工作。我们在 springroad.deomo.chap3 包下添加一个名为 ClientDemo 的带有 main 方法程序, ClientDemo 的全部代码如下:

package springroad.deomo.chap2;

import org.springframework.beans.factory.BeanFactory;

import org.springframework.beans.factory.xml.XmlBeanFactory;

import org.springframework.core.io.ClassPathResource;

import org.springframework.core.io.Resource;

public class ClientDemo {

       public static void main(String[] args) {

              // 定义 Spring Bean 工厂资源文件

              Resource res=new ClassPathResource("springroad/demo/chap2/computer-beans.xml");

              // 创建一个 Bean 工厂

              BeanFactory factory=new XmlBeanFactory(res);

              // Bean 工厂中取出一个名为 myComputer Computer 对象

              Computer computer=(Computer)factory.getBean("myComputer");

              // 执行 computer doWork 方法,使得 commputer 开始工作

              computer.doWork();

              // 输出电脑的配置信息

              System.out.println(computer.getSetting());

       }

}

    此时通过 Eclipse 环境直接可以运行这个 ClientDemo 程序,在 ClientDemo 上点右键选择 Run As ,然后点 Java Application ,程序成功运行会在输出面板中得到如下图所示的结果:

   

    下面,我们简单的修改一下 computer-bean.xml 文件中的内容,把 myMainboard 中的 cpu 的属性值改为 springroad.deomo.chap3.impl. AMDCpu ,表示这个电脑使用 AMD CPU

    然后运行 ClientDemo 程序,我们会看到电脑的 Computer 的配置信息及总价格已经有了改变,如“图 2-30 所示:

2-30 装示例运行结果

 

   当然,你还可以在配置文件中把 IntelBoard 换成 AUSUBoard 主板,把 KingmaxRam 内存换成 KingstoneRam ,都可以配出完整的电脑。

2.3.6 发布 Bean- 把电脑交给客户

作为一个可以自由工作的组件,应该要脱离具体的开发环境,我们最终交给用户的应该是一个打包好的可以正常运行的程序。也相当于我们电脑组装人员要把组装好的电脑交给客户使用。

下面我们使用 Eclipse 把这个示例打包成 jar 发布,使用 Eclipse Jar Export 可以简单实现该功能,如“图 2-31 所示。

2-31 打包 computer 组件

   假设我们发布的 jar 文件名为 computer.jar ,然后即可进入 dos 命令行,使用 java 命令执行刚才的程序, ( 注意, computer.jar spring.jar commons-logging.jar 等文件所在路径 ) ,执行方法如下:

    java -cp computer.jar;lib/spring.jar;lib/commons-logging.jar;. springroad.deomo.chap2.ClientDemo

    则可以看到如“图 2-32 所示的结果:

2-32  在命令运行客户端应用的输出

 

   可以直接使用解压工具如 winzip winrar 等打开 computer.jar ,如“图 2-33

2-33  用 WinRar 打开发布的压缩包

 

然后双击其中的 computer-bean.xml 文件,可以打开编辑器修改这个 Spring 配置文件的内容,比如我们在 xml 文本编辑器中把 computer-bean.xml 文件的内容改成如“图 2-34 所示的内容。

2-34  在文本编辑器中修改配置文件

 

把修改的内容保存并覆盖 jar 中的内容后,此时,重新在 dos 命令窗口中执行刚才的命令,则会得到如“图 2-35 所示的完全不同的配置结果。

2-35 修改配置文件后运行客户端程序的输出

    由此,可以看到,通过使用 Spring Bean 工厂,我们可以不需要改一句 Java 源代码,只需根据自己喜爱修改 Spring 的配置文件,即可配置一台完整的、可应用的电脑供客户端使用。

而且电脑组装人员在组装电脑、尝试各种配置的过程中,也只需要修改配置文件即可看组装的效果,而不需要修改程序代码。

2.3.7 传统的组装

为了作比较,我们来看看若是采用传统的方式,客户端程序应该怎样来组装一台可用的电脑。 ClientOldDemo 类是一个演示采用传统方式使用 Computer 的客户端示例, ClientOldDemo 的全部源代码如下:

package springroad.deomo.chap2;

import springroad.deomo.chap2.impl.IntelBoard;

import springroad.deomo.chap2.impl.IntelCPU;

import springroad.deomo.chap2.impl.KingmaxRam;

public class ClientOldDemo {

       public static void main(String[] args) {       

       CPU cpu=new IntelCPU();

       Ram ram=new KingmaxRam();

       Mainboard myMainboard=new IntelBoard();

       myMainboard.setCpu(cpu);

       myMainboard.setRam(ram);

       Computer computer=new Computer();

       computer.setMainboard(myMainboard);

    // 执行 computer doWork 方法,使得 commputer 开始工作

       computer.doWork();

       // 输出电脑的配置信息

       System.out.println(computer.getSetting());  

       }

}

 

    通过上面的程序可以看出,用户为了使用这个电脑工作,需要自己从 CPU Ram Mainboard 开始,一层一层地自己创建,然后把 CPU Ram 装到主板上,然后再把主板装到 Computer 上,最后才能使用一个完整的、可以工作的电脑来执行相关的工作。若客端要换一种配置,则每换一样都需要修改程序中创建 Computer 各组成部分的代码,然后再编译、调试、打包、发布 !

2.3.8 示例角色浅析

本例中, ClientDemo 相当于电脑的最终使用者,一个不会组装电脑的用户,其甚至不知道电脑由哪些部件组成,他需要的仅仅是一个完整可以正常工作的电脑;而负责维护 Spring 配置文件者,相当于组装电脑的一般技术人员,他不需要很高深的技术,不需要知道怎么样生产一块主板、生产一块 CPU ,只需要知道什么是主板,什么是 CPU ,什么是 Ram ,并且知道 CPU Ram 应该插放在什么位置,知道主板怎么安装即可。而实现 CPU 接口、 Mainboard 接口及 Ram 内存的类编写人员,如编写 InterCPU 这个类的人员,就相当 CPU 厂家的一线专业技术工程师,他们需要对微电子、数据电路等很多非常专业的技术,他们需要对 CPU 的工作原理等非常了解。

    电脑终端用户、组装人员、生产厂商的工程师三者之间形成了如“图 2-36 所示的角色结构:

装机人员 ( 组装电脑 )

主板厂商

CPU 厂商

内存 (Ram) 厂商

用户 ( 使用电脑 )

2-36  装机示例中的角色

    如果是采用传统组装电脑的方式,比如 ClientOldDemo 中示例,则要求客户端用户必须了解具体的电脑组成部件 ( ClientOldDemo 中,用户不但要与 Computer 类打交道,还要与 CPU Ram 等接口打交道 ) ,知道每一个部件的生产方式 (ClientOldDemo 中用户知道使用 new 方法跟一个 CPU 实现类的类名来创建一个 CPU 实例 ) ,并要清楚每一个部件之间的关系 (ClientOldDemo 中用户需要知道通过 setCpu setMainboard 等方法把相关部件分别设置到主板及电脑对象中 ) ,然后使用专业的电脑组装工具 ( 修改源码及编译等 ) 才能组装出一台可用的代码。

2.4 分享 Spring 学习方法

通过使用 Spring ,我们可以快速搭建轻量级的 J2EE 企业及应用平台。 Spring 是一个应用程序框架,更像一个强大的二次开发工具包。作为一个开源项目, Spring 为我们了很多优秀的设计思想,融合了很多经典模式的应用。即使我们项目中不用 Spring ,也有必要对 Spring 从体系结构上有一定的了解,并深入了解他一些模块的设计方法。当然,若您的项目中需要用到 Spring ,则有必要学会选择一些适合自己的高效学习方法。下面是我们在学习使用 Spring 过程中的一些经验,供大家参考:

1、  安装并运行 Spring 项目中所附带的 example 示例。然后使用 Eclipse 等开发工具,了解这些项目的包结构,并认真阅读并理解一些重要示例的源代码。

2、  下载并运行一些优秀的开源示例应用代码,比如 Appfuse

3、  认真阅读 Spring 的参考文档,文档虽然是英文的,但我想只要你不放弃,通过应用一些即时翻译工具软件 ( 如金山词霸 ) 的帮助,可以帮助您的阅读。

4、  认真阅读 Spring 项目自带的单元测试代码,单元测试代码中的测试用例是我们了解一个类如何工作最好文档。

5、  阅读 Spring 项目中一些核心包,比如 core bean aop context 等源代码,必要时,使用 UML 工具,绘制出这些代码的 UML 结构图,掌握各个接口、类之间的关系。

6、  多做项目练习及实践,理论上 Spring 可以组装任何项目,因此,可以试着把自己以前一些小项目,改成使用 Spring 的方式来组装。

7、  经常到一些国内外知名 Java 社区,加入一些 Spring 用户群等,做到随时能接触 Spring 的一手信息。

 

2.5 小结

    本章简单介绍了 Spring 项目的情况,并对其用途作了一些简单的归纳总结。另外,通过图文并茂的方式,演示如何下载、安装并运行一个简单的示例程序 hello 。本章中,我们重点举了一个组装电脑的例子,演示了 Spring IOC 的运用,并通过与传统的电脑组装方式,结合现实中的角色分工,展示了 Spring 带给我们一些奇妙功能及特性。

    本章只是 Spring 的入门章节,主要让新手能了解 Spring ,轻松把 Spring 运用起来。若你是新手,可以确保自己独立根据本章示例的操作步骤,完成本章中的两个实例后,再继续以后的章节;若您曾经使用过 Spring ,则请直接通过下面其它章节,具体了解 Spring 的一些使用方法及技巧。当然,若您已经很熟悉 Spring 应用的老手,则可以直接跳到本书的第二及第三部分内容。

2.6 思考题

请想想能不能用一种方式,不需要使用 Spring ,同时也不需要修改及重新编译源代码,通过配置文件就能实现自由灵活的电脑组装。

posted on 2007-02-21 14:45 风起花落 阅读(800) 评论(0)  编辑  收藏 所属分类: Java学习

只有注册用户登录后才能发表评论。


网站导航: