2.1.2 Rod Johnson 、Spring团队及Spring交流社区... 1
2.3.2 定义Bean-定义电脑的组成配件并实现电脑的设计... 19
第二章 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能做什么
<!--[if !supportLists]-->n <!--[endif]-->容器功能
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,用户还能根据实际项目需要设计并实现自己的切面,解决横切交叉关注点中的问题。
<!--[if !supportLists]-->n <!--[endif]-->黏合剂/组装功能
Spring已经把很多优秀开源项目以一种非常优雅的方式集成在一起,同时Spring用户也可以把自己项目中开发的组件或框架非常方便的集成到Spring中,然后享受Spring核心容器提供的各种服务。在这里,Spring更多的扮演了黏合剂角色,他就像一个强力的黏合剂,以一种非常简单、统一的方式就能把各种各样、五花八门的组件、工具及项目等组合到一起,然后形成一个可交付的J2EE应用软件。因此,也可以说Spring具有组装功能,通过组装的方式来构建一个系统。
<!--[if !supportLists]-->n <!--[endif]-->企业应用开发实用工具集
Spring提供了很多轻量级应用开发实践的工具集合,这些工具集以接口、抽象类、或工具类的形式存在于Spring中。通过使用这些工具集,可以实现应用程序与各种开源技术及框架间的友好整合。比如有关jdbc封装的数据访问工具Spring JDBC,有关编写单元测试的spring test包以及spring-mock,有关访问动态脚本语言的Spring Script,另外还有发送邮件的工具Spring Mail、日程及任务处理工具Spring scheduling等。
可以这么说,大多数企业级应用开发中经常涉及到的一些通用的问题,都可以通过Spring提供的一些实用工具包轻松解决。
<!--[if !supportLists]-->n <!--[endif]-->通用实践抽象
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项目文件
<!--[if !supportLists]-->n <!--[endif]-->根目录
在根目录上,主要是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等文件。
<!--[if !supportLists]-->n <!--[endif]-->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目录中的内容
<!--[if !supportLists]-->n <!--[endif]-->docs目录
docs目录是Spring项目的文档目录,里面主要包括Spring项目使用说明文档及系统API等,在Spring2.0的项目中,包括api文档、spring mvc应用简单示例、spring参考手册、spring标签库简介等几个部分,如“图2-11”。
图2-11 docs目录中的内容
<!--[if !supportLists]-->n <!--[endif]-->mock目录
mock目录是Spring用于单元测试中模仿对象的mock实现源代码,也就是spring-mock.jar中的源码。
<!--[if !supportLists]-->n <!--[endif]-->aspectj目录
aspectj目录是Spring与AspectJ集成的源代码及应用测试代码。
<!--[if !supportLists]-->n <!--[endif]-->src目录
src目录是Spring项目的全部源代码。
<!--[if !supportLists]-->n <!--[endif]-->samples目录
samples目录是Spring项目的应用程序示例源代码,主要包括一个简单的网上商店jpetstore,一个宠物医院petclinic。另外还有演示一些特殊功能的简单示例,如countries、imagedb等。通过这些示例程序代码,可以快速学习到Spring使用方法。
<!--[if !supportLists]-->n <!--[endif]-->test目录
test目录是Spring项目的单元测试代码,Spring作为测试驱动开发的推崇者,有着非常详细的单元测试用例,通过单元测试代码,可以快速掌握Spring各个类的方法。
<!--[if !supportLists]-->n <!--[endif]-->tiger目录
tiger是Spring项目中使用java tiger版中的新功能及特性的源代码,包括注解等。
<!--[if !supportLists]-->n <!--[endif]-->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)厂商 |
用户(使用电脑) |
![](http://www.easyjf.com/spring/spring2-2/image073.gif)
![](http://www.easyjf.com/spring/spring2-2/image074.gif)
图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过程中的一些经验,供大家参考:
<!--[if !supportLists]-->1、 <!--[endif]-->安装并运行Spring项目中所附带的example示例。然后使用Eclipse等开发工具,了解这些项目的包结构,并认真阅读并理解一些重要示例的源代码。
<!--[if !supportLists]-->2、 <!--[endif]-->下载并运行一些优秀的开源示例应用代码,比如Appfuse。
<!--[if !supportLists]-->3、 <!--[endif]-->认真阅读Spring的参考文档,文档虽然是英文的,但我想只要你不放弃,通过应用一些即时翻译工具软件(如金山词霸)的帮助,可以帮助您的阅读。
<!--[if !supportLists]-->4、 <!--[endif]-->认真阅读Spring项目自带的单元测试代码,单元测试代码中的测试用例是我们了解一个类如何工作最好文档。
<!--[if !supportLists]-->5、 <!--[endif]-->阅读Spring项目中一些核心包,比如core、bean、aop、context等源代码,必要时,使用UML工具,绘制出这些代码的UML结构图,掌握各个接口、类之间的关系。
<!--[if !supportLists]-->6、 <!--[endif]-->多做项目练习及实践,理论上Spring可以组装任何项目,因此,可以试着把自己以前一些小项目,改成使用Spring的方式来组装。
<!--[if !supportLists]-->7、 <!--[endif]-->经常到一些国内外知名Java社区,加入一些Spring用户群等,做到随时能接触Spring的一手信息。
2.5 小结
本章简单介绍了Spring项目的情况,并对其用途作了一些简单的归纳总结。另外,通过图文并茂的方式,演示如何下载、安装并运行一个简单的示例程序hello。本章中,我们重点举了一个组装电脑的例子,演示了Spring IOC的运用,并通过与传统的电脑组装方式,结合现实中的角色分工,展示了Spring带给我们一些奇妙功能及特性。
本章只是Spring的入门章节,主要让新手能了解Spring,轻松把Spring运用起来。若你是新手,可以确保自己独立根据本章示例的操作步骤,完成本章中的两个实例后,再继续以后的章节;若您曾经使用过Spring,则请直接通过下面其它章节,具体了解Spring的一些使用方法及技巧。当然,若您已经很熟悉Spring应用的老手,则可以直接跳到本书的第二及第三部分内容。
2.6 思考题
请想想能不能用一种方式,不需要使用Spring,同时也不需要修改及重新编译源代码,通过配置文件就能实现自由灵活的电脑组装。