摘要 ……………………………………………………?/B>…………?
文献lD ……………………………………………………………?
W一?前言…………………………………………………………?
W二?OOP的基本原则及发展方向
W一?软g的可l护性与可复用性………………………?
W二?六条OOP设计原则 …………………………………?
W三?AOP的兴起…………………………………………?8
W三?J2EEpȝ的架构设?
W一节J2EE中常用的概念…………………………………?0
W二?MVC架构 ……………………………………………?2
W三?分布式架构…………………………………………?3
W四?数据持久层的设计
W一?业务对象的持久化…………………………………?4
W二?数据讉K对象设计模式……………………………?5
W三?ORM框架的原理和重要?…………………………?6
W四?数据持久层…………………………………………?9
W五?数据库连接池、缓存及pȝ性能的提?…………?1
W六?Java反射技?nbsp; ……………………………………?2
W五?J2EE架构中各层的数据表示Ҏ
W一?MVC三层体系l构中的数据表示要求 ……………?3
W二?J2EEpȝ中各层数据表C的设计 ………………?4
W六?设计模式的概念与几种常用的J2EE设计模式
W一?设计模式的概念……………………………………?5
W二?工厂创徏模式与单例模式…………………………?7
W三?使用工厂模式实现DAO ……………………………?1
ȝ …………………………………………………………………?3
l束??/B>……………………………………………………………?4
多层J2EEpȝ的架构与模式设计
【摘要?nbsp; J2EE提供了一套完整的Z标准化模块的服务lgQ它能自动的处理大多数应用程序的l节Q而不需要复杂的~程Q因此简化了复杂的企业应用E序的开发。本文首先考察企业U应用的一般概念和需求,然后要阐q面向对象程序设计的基本原则Qƈl合软g工程的思想来讨论多层的J2EE应用架构Q分析它们满企业应用的方?Q再通过讲述常用的几UJava设计模式和Java反射技术来说明如何实现q些应用架构?
【关键词?模型-视图-控制Q对象关pL,业务对象Q面向方面编E,数据讉K对象Q设计模?
The Framework of Multitier J2EE System and Design Pattern
?B>abstracts?FONT face="Times New Roman">The J2EE simplifies enterprise applications by basing them on standardized, modular components, by providing a complete set of services to those components, and by handling many details of application behavior automaticallyQ?FONT face="Times New Roman">without complex programming. This paper reviews the general concept and the requirement of enterprise application, elaborates the general principle of object oriented programming briefly. We combine the idea of Software-Engineering to discuss the framework of multitier J2EE, and meanwhile analyze how they can satisfy the demand of enterprise applications. At last, this paper shows how to implement those frameworks of multitier J2EE by introducing some kinds of Java design pattern and the Java reflection technology.
?B>key words?FONT face="Times New Roman">MVCQ?FONT face="Times New Roman">ORMQ?FONT face="Times New Roman"> BOQ?FONT face="Times New Roman"> AOPQ?FONT face="Times New Roman"> DAOQ?FONT face="Times New Roman">Design pattern.
?B>文献lD?
计算Y件是人类心灵和智慧在虚拟I间中的投射。Y件的性能是hc能力的扩展Q它的活动就是hcd智活动的反映。Y件直接表辑և设计者对目标的理解,对用L期待Q以及对自己的定位。h们在自己的环境中不断发现问题和寻N题的解决Ҏ的时候,发现有一些问题及其解x案不断变换面孔重复出玎ͼ但在q些不同的面孔后面有着共同的本质,q些共同的本质就是模式。著名徏{工E学家Christopher Alexander所著《徏{的永恒之道? The Timeless Way of Building)和他发展出来的模式理论涵盖科学,心理Q艺术和哲学Q不仅适用于徏{工E学Q而且适用于Y件工E学以及M其他的工E学?
今天的企业Y件可以由多个不同的部分组成,但企业已l认识到Q只要符合企业利益,很有必要各个分散的pȝq行良好的集成,以尽可能怺支持Qȝ来说企业希望寚w成后的企业软g的具体应用如下:
1. 通过集成企业的客h持和本n的品知识,企业可以利用WEB为它的客h供更新更好的服务?
2. 企业售货机联网Q企业可以获得更多的在线客户?
3. 销售管理系l和存货pȝ盔R接,企业可以设计特定的低成本的Web销售渠道,q样可以q入未曾涉的市场领域?
4. 如果l企业员工所使用的服务提供一个前端,例如内部办公用品订货pȝQ将它与会计pȝq接在一P企业可以降低M开支ƈ提高员工的工作效率?
5. 在线使用企业HRpȝQ可以让员工Ҏ他们自己的健L况进行更多的选择Q这样可以降低企业整体的理费用?
6. 使企业的人力资源密集型操作自动化Qƈ使它可用于Q何时间Q何地点,在降低整体运营费用的同时Q企业还可以l它的客h供更好的服务?
按企业对企业UY件的要求Q一个企业应用pȝ(J2EE)肯定会是一个服务于商业目的Q处理企业业务信息,数据的Y件系l,因此大概可以ȝZ下五斚w的特?有复杂的业务逻辑Q有大量持久化数据,与多U外部系l相兌有较高的性能要求Q在q行旉要随时监控,理Q应该能够实时记录,观察pȝq行情况。修改系l配|?
以前的企业应用,集中式的单层(single tier)应用E序占有dC。在软g中,层是一个抽象概念,它的主要目的是通过Y件分解成独立的逻辑层,帮助我们理解与特定应用程序相兌的体pȝ构。从应用E序的角度看Q单层应用程序的最大问题在于,它将表示Q业务逻辑和数据都混合在一赗客h-服务器方法通过表C和一些业务逻辑分别U至单独的层中,~解了上qC要问题的影响Q不q从应用E序的角度来看,业务逻辑和表CZ然很混ؕ。N?n-tier)Ҏ可以取得更好的整体^衡,它将表示逻辑与业务逻辑从底层数据中分离开来,以满特定的需求。单单采用面向对象开发技术后只可以实现部分代码重用,原因之一是对象都l粒度化Q正是因为细_度对象间更紧密的耦合状态,从而便利大范围的重用变得很困难。分层化的组件设计就是ؓ了解册个问题。与对象不同QY件组件是在更高的抽象U中设计的,可以提供一个完整的功能或服务。组仉的耦合更ؓ松散。利用组件的接口Q可以将lgq速组合在一起以构徏更大的企业应用E序?
q年来,Z已开发出了各U不同的帮助理解的组件模型,例如QMicrosoft的ActiveXQ后来的COM~程接口Q和现在兴v?net FrameWorkQSUN Microsystems的applet和JavaBeansQEnterprise JavaBeans(EJB),其中EJB是J2EE的一部分?
Sun Microsystems把Java2q_l织成三个特定的Q引人瞩目的版本Q微型版QJ2MEQ,标准版(J2SEQ和企业版(J2EEQ。在q些产品中,J2EE与开发企业Java应用联系最紧密。J2EE为开发复杂的Q分布式企业UJava应用定义了一套体pȝ构?
J2EE最初是由Sun Microsystems?999q中期发布的Q其正式发布则在1999q后期。J2EE仍然较新Q其依次发布的版本间仍然存在着重大的改变,特别是在EJB斚w。该q_是徏立在Java“一ơ编写,随意q行”的理念上的Q它通过一l技术和一套API实现?
N层体pȝ构的概念已经出现一D较长的旉了,q已成功地应用于构徏企业U应用程序。Sun在Java中采用n层开发模型,q引入特定功能,允许更容易地开发服务器端可伸羃的、基于Web的企业应用E序Q从而在q个领域提供了Java自n所~少的关键成分?
Z么要使用J2EE呢?它不是太新ƈ且功能未l证实,它能提供什么?N只是一U一时的技术狂热吗Q在J2EE出现之前QJDBC API早已建立好了Q可选用的轻量的,可维护的servlet技术也已出现。除了这些,J2EEq提供了一些有前景的优点,它让开发h员关注开发业务逻辑Q不用预先详l了解执行环境而把_֊攑ֈ实现pȝ上,以及创徏在硬件^台和操作pȝQOSQ间更容易衔接的pȝ。企业软g开发是一复杂的dQ需要具备许多不同领域的q泛知识。例如,一典型的企业U应用程序开发工作可能要求你熟悉q程间的通信问题、安全问题、数据库特定讉K查询{?
J2EE企业U开发^台鼓励在pȝ开发、部|和执行之间作一个清晰的划分。此开发h员可以将部vl节留给部v人员处理Q如实际的数据库名称和存放位|、主机持有配|属性等。J2EE让系l可通过Java和J2EE而不是底层系lAPI被访问,从而支持硬件和OS无关性。由于这U原因,遵@J2EE体系l构技术规范的企业U系l可以非常容易地在硬件系l和不同的OS之间衔接?
在企业开发领域,虽然面对Microsoft .net强大的挑战,但是J2EE׃上述优点Qƈ且相对说来比较成熟,已经占据了企业开发的大部分市场,q着技术的q步、新的J2EE版本的发布、开源社区庞大自由开发者的支持Q将会企业U开发变得更高效Q更快速,更高质量Q更易于l护?
W一?前言
J2EE核心技术有十三U,它们和J2EE API覆盖了企业Java开发的q泛领域。在企业UJava开发工作中要用到的J2EE的方斚w面知识是不太可能的。比较常用的有容器,servlet, JSP, EJB{。容器是一U运行在服务器上的Y件实体,用于理特定cd的组件。它为开发J2EElg提供了执行环境。通过q些容器QJ2EE体系l构p在开发和部v间提供无x,q在不同cd的中间层服务器间提供可移植性。servlet是一些可生成动态内容的Weblg。它们是当今在www上看到的最常用的J2EElg之一。它们提供了一U有效的机制Q用于基于服务器的业务逻辑和基于Web的客L之间的交互,q可为通用的CGI脚本Ҏ提供一U轻型且更易于管理的替代Ҏ。JSP是另一U类型的J2EE WeblgQ它是从servlet技术发展而来的。事实上Q一部分JSP~译qservletq在servlet容器中执行。EJB技术规范是J2EEq_的最核心的部分。它为构建可伸羃、分布式、基于服务器的企业Java应用lg提供了一U综合性的lg模型。文章将l合q几U主要的lg技术来讲述构徏J2EEpȝ的一般过E?
W二?OOP的基本原则及发展方向
W一?软g的可l护性与可复用?
通常认ؓQ一个易于维护的pȝQ就是复用率较高的系l;而一个复用较好的pȝQ就是一个易于维护的pȝ。也是说一个系l的设计目标应该h如下性质Q可扩展性,灉|性,可插入性?
常听一个项目开发结束只完了q个目的三分之一Q可见系l的可维护的重要性。导致一个系l可l护性降低主要有四个原因Q过于僵,q于脆弱Q复用率低,黏度q高。通过良好的Y件复用,可以提高软g的生产效率,控制生成本Qƈ能提高Y件的质量Q改善系l的可维护性,提高pȝ的灵zL和可插入性?
在面向对象的设计里,可维护性复用是以设计原则和设计模式为基的,下一节介l面向对象设计的基本原则?
W二?六条OOP设计原则
OOP设计原则是提高Y件系l的可维护性和可复用性的指导性原则,Java是一门纯面向对象的设计语aQ因此我们在使用Java开发J2EEpȝ时必遵守OOP设计的基本原则?
q些设计原则首先都是复用的原则,遵@q些设计原则可以有效地提高系l的复用性,同时提高pȝ的可l护性:
l OCP开闭原?一个Y件实体应当对扩展开放,对修改关?
l LSP(里氏代换原则):它是l承复用的基?
l DIP(依赖倒{原则):要依赖于抽象Q不要依赖于具体
l ISP(接口隔离原则):一个类对另一个类的依赖性应当是建立在最接口上
l CARP(合成/聚合复用原则):要尽量用合?聚合Q尽量不要用?
l LOD(q米Ҏ?:一个对象应该对其他对象有尽可能的了解
通过扩展已有的Y件系l,可以提供新的行ؓQ以满对Y件的新需求,使变化中的Y件系l有一定的适应性和灉|性。而已有的软g模块Q特别是最重要的抽象层模块不能再修改,q就使变化莫中的Y件系l有一定的E_性和延箋性。具有这些优点的软gpȝ是一个在高层ơ上实现了复用的pȝQ也是一个易于维护的pȝ?
里氏代换要求凡是基类型用的地方Q子cd一定适用Q因此子cdd备基cd的全部接口?
传统的过E性系l的设计办法們于高层ơ的模块依赖于低层次的模?抽象层次依赖于具体层ơ。抽象层ơ包含的是应用系l的商务逻辑和宏观的Q对整个pȝ来说是重要的战略性决定,是必然性的体现;而具体层ơ则含有一些次要的与实现有关的法和逻辑Q以及战术性的军_Q带有相当大的偶然性选择。具体层ơ的代码是会l常有变动的Q不能避免出现错误。抽象层ơ依赖于具体层次Q许多具体层次的细节的法变化立即影响到抽象层ơ的宏观商务逻辑Q导致微观决定宏观,战术军_战略Q偶然决定必然。从哲学意义上面讲这是很荒唐的事情,倒{原则是要把q个错误的依赖关pd{q来?
如果两个cM必彼此直接通信Q那么这两个cd不应当发生直接的怺作用。如果其中的一个类需要调用另一个类的某一个方法的话,以可通过W三者{发这个调用?
“针Ҏ口编E”现在已l逐渐成ؓq大OOPE序员的pQ成为OOP设计思想的集中体现。一门语a即不提供Interfaceq样的关键字Q它也需要在很大E序上模拟出接口的功能。典型的如C++Q通过声明一个只有纯虚函数的子类来模拟接口功能。不q这U模拟也׃限于此,比如对于Java中的动态代理,抽象基类g无能ؓ力了?
OOPl过二十多年的发展,逐渐取代面向q程E序设计Q已l相当成熟。OOP的设计思想主要体现在下以几个方?
(1) 针对抽象~程Q不针对具体~程。这是依赖倒{原则所要求的。换a之,应当针对抽象cȝE,不要针对具体子类~程Q这一原则点出了抽象类对代码利用的一个最重要的作用?
(2) 使用l承辑ֈ软g复用的目的。在Java中,l承有两U,一U是接口l承Q一U是实现l承。第二种l承常常很容易被滥用。只要可能,量使用合成Q而不要用承来辑ֈ复用的目的?
(3) 使用模板方式模式Q它是类的行为模式,准备一个抽象类Q将部分逻辑以具体方法以及具体构造子的Ş式实玎ͼ然后声明一些抽象方法来q子类实现剩余逻辑。不同的子类可以以不同的方式实现q些抽象ҎQ从而对剩余的逻辑有不同的实现?
W三?AOP的兴?
软g工程的发展史实际上就是抽象的发展双Ӏ随着软g来复杂,相应地我们也提高了编E语a的方法的抽象U别。因此,我们l历了从C到C++到Java,从结构化Ҏ到面向对象的设计Q从cd设计模型又到体系l构框架q一pd的改变,q且q个改变仍然在l着?
AOP(Aspect Oriented Programming) 面向斚w~程是一U超OOP的编E模型,它允许程序员横切关注点Q散布在多个模块中的一致概念如同步处理Q持久化Q日志等都是典型的横切关注点Q封装成清晰的可重用模块Q然后通过l合q些模块和功能性组件获得系l的实现。AOP通过促进另一U模块性补充了OOPQ便利我们可以很自然地处理一些传l的OOP不能解决的问题?
在J2EE应用开发中Q我们主要用AOP的拦?interception)能力Q它提供了在M对象的方法调用前/后加入自定义行ؓ的能力。这使得我们可以处理企业应用中的横切x?同时作用于多个对象的x?Qƈ且仍然保持强cdQ而不需要改变方法签名。例如,可以在一个应该具有事务的Ҏ调用前开始一个事务,在方法返回时提交或者回滚。用AOP可以把与事务理相关的重复劳动放q一个框架内?
作ؓ一个开发者,我每天大部分的时间面对的是数据库的存取,JNDI资源的访问,事情的声明释放,以及各处文g的读取等{,q些面对不同业务的同h作。但是,在执行一步操作的时候往往我们需要配|一个比较完整的环境Q如果JSP/Servlet容器QEJB容器{。在当今J2EEL以发展轻量构g的时代,我们有机会从摆脱q种重复的劳动,使用上轻量的构件技术?
轻量U容器依靠反转控?Inversion of Control. IoC)模式或依赖注?Dependency Injection)现在是JavaC非常热门的话题,它实际上是针Ҏ口编E这个OOP概念的进一步深化。利用IoC模式能够很好的解决代码调用者和被调用者之间的依赖关系Q不仅可以灵zȝ装配我们的业务对象,更重要的是它让我们有Z在一个完整的环境中进行工作,使我们的业务开发不用再考虑环境因素。如果用得着某几J2EE服务Q就可以使用他们Q比如,想用JTAqJTAQ想用数据库q接池就用连接池。这P让我们的应用代码在J2EE环境下,不受Mq行环境的束~。更有特色的是,轻量U容器借助AOP的横切服务甚臛_以让我们的代码段中不包含try/catchq样的常用代码成例。因栯U异常处理是与环境相关的?
从概念上面来_JNDI查找Q事务,安全之类的基设施都是与业务逻辑横切的。由于业务组仉是轻量容器负责理生命周期Q用者只要是通过容器q行lg讉KQ我们就应该让容器插入额外的代码来管理横切基设施。然而,这些基设计q行外部声明Q而不让他们进入到应用代码之中Q才是一个系l实现可插入性的最好的实现办法?
在J2EE轻量U容器中QSpring无疑是最行Q发展得最好的Q它提供的IoC容器不仅可以帮助我们完成我们的目标,而且它是开源的?
那么Spring如果我们从重复的劳动中解放出来?一般,在我们写数据库接口时Q需要访问数据库的时候都需要创Z个ConnectionQ再声明一个statementQ然后再q行具体的数据库操作Q事务处理完闭之后,q要用try/catch语句statementQconnection close()掉。在JDBC2.0规范中,我们通常所做的Ҏ是通过容器q?Tomcat5.0QJbossQWeblogic都提供很好的JNDI支持)定义资源Qƈ暴露为全局性的JNDI对象Q这P客户端的代码直接通过JNDI讉Kq些资源Q显Ӟ应用代码与JNDI基础设施l定在了一P也就是说应用代码与环境相关了Q很隑ր助伪造的资源对象来进行单元测试,而且q些的代码既不易重用Q也不能在J2EE环境以外q行?
W三?J2EEpȝ的架构设?
W一?nbsp; J2EE中常用的概念
在Y件业q向lg装配工业(software component industry) 的过E中H不断发现组件设计者对其组件应用场合的预想环境与应用Y件师的Y件体pȝ构常常无法很好地整合hH导致应用Y件开发h员难以灵zd复用他h设计好的lgQ造成软glg工业发展上的瓉。OOP软g专家也逐渐认识到其问题是来自于软gL构上的不兼容。Y件主架构的重要性ƈ非今天才呈现出来H?0多年前Y件大师Fred.P.Brooks 提刎ͼ软g开发者之_他们设计的理念必M致才能共同创造出单易用的软gQ同时他也强调Y件主架构在达到概念一致的q程中,合作居于核心角色。现在,开发者们在项目开始时不是讨论要不要用架构,而是讨论I竟该用什么样的架构?
(1) 体系l构QArchitectureQ?
体系l构也可UCؓ架构Q所谓Y件架构﹐ҎPerry 和Wolfe之定义:Software Architecture = {ElementsQFormsQ?Rationale / Constraint }Q也是软gL?= {lg元素Q元素互助合作之模式Q基要求与限制}。Philippe Kruchten采用上面的定义﹐q说明主架构之设计就是:各lg元素以某些理想的合作模式l织hH以达成pȝ的基本功能和限制?
(2) 架构(Framework)
框架也可UCؓ应用架构Q框架的一般定义就是:在特定领域基于体pȝ构的可重用的设计。也可以认ؓ框架是体pȝ构在特定领域下的应用。框架比较出名的例子是MVCQ模?视图-控制Q?
(3) ?Library)
库应该是可重用的、相互协作的资源的集合,供开发h员进行重复调用。它与框架的主要区别在于q行时与E序的调用关pR库是被E序调用Q而框架则调用E序。常见的库有Java APIQApachel织提供的Java开发包?
(4) 设计模式QDesign PatternQ?
设计模式应该很熟悉,其四h帮所写的书更是家L晓。“四人帮”将模式描述为“在一定的环境中解x一问题的方案”。这三个事物 ?问题、解x案和环境 ?是模式的基本要素?
(5) q_QPlatformQ?
由多U系l构成,其中也可以包含硬仉分?
在J2EEpȝ开发过E中Q大致可以分Z大步骤:需求、分析、设计、编码、测试。而体pȝ构是软g的骨Ӟ是最重要的基。体pȝ构是涉及到每一步骤中。一般在获取需要的同时Q就应该开始分析Y件的体系l构。体pȝ构现在一般是各个大的功能模块l合成,然后描述各个部分的关p,J2EEq_已经为我们提供了整个软gpȝ的体pȝ构?
架构是体pȝ构中每个模块中相对细的l构。如需要表CWeb技术,׃用到MVC架构Q而Web功能只是整个软g体系中的一个功能模块。每个架构可以有许多个实例,如用Java实现的MVC架构Struts?
而在架构之下是设计模式Q设计模式一般是应用于架构之中,也可以说是对架构的补充。架构只是提供了一个环境,需要我们填入东ѝ无论是否应用了设计模式Q都可以实现软g的功能,而正应用设计模式,是对前h软g设计思想或实现方法的一Uѝ?
W二?nbsp; MVC架构
上一节中提到ZWeb开发的MVC架构目前在J2EE的世界内I前J荣。在q些架构中,老牌的有Struts、Web work。新兴的有Spring MVC、Tapestry、JSF{。这些大多是著名团队的作品,都提供了较好的层ơ分隔能力,在实现良好的MVC 分隔的基上,通过提供一些现成的辅助cdQ促q了生效率的提高?
在这么多J2EE架构中如何选择一个适合自己目的架构呢Q什么是衡量一个架构设计是否优U的标准?从实际Web产品研发的角度而言Q而非Ua设计上,扩展性上Q以及支持特性上的比较)Q目前Struts 也许是第一选择。它拥有成熟的设计,同时Q也拥有最丰富的信息资源和开发群体。从较偏向设计的角度出发QWebWork2 的设计理忉|加先q,其代码与Servlet API 相分,q得单元测试更加便利,同时pȝ从B/Sl构转向C/S接口也较为简单。另外,对基于模板的表现层技术(Velocity、Free Maker和XSLTQ的支持Q也为程序员提供了除JSP之外的更多的选择QStruts也支持基于模板的表现层技术,只是实际中不太常用)。而对于Spring而言Q首先,它提供了一个相当灵zd可扩展的MVC实现Q与WebWork2相比Q它在依赖注入方面、AOP {方面更加优UQ但在MVC 框架与底层构架的分离上又与WebWork2 存在着一定差距,Spring 的MVC 与Servlet API 相耦合Q难于脱Servlet容器独立q行Q在q点的扩展性上Q比Webwork2E逊一{VSpring对于Web应用开发的支持Qƈ非只限于框架中的MVC部分。即使不使用其中的MVC实现Q我们也可以从其他组Ӟ如事务控制、ORM模板中得益。同ӞSpring也ؓ其他框架提供了良好的支持Q很Ҏ可以将Struts与Spring搭配使用。因此,对于Spring在Web应用中的作用Q应该从一个更全面的角度出发?
J2EEpȝ采用三层的MVC架构之后Q其解决的主要问题无外乎以下几部分:
(1) Web面中的输入元素装Z个(hQ数据对象?
(2) Ҏh的不同,调度相应的逻辑处理单元Qƈ(hQ数据对象作为参C入?
(3) 逻辑处理单元完成q算后,q回一个结果数据对象?
(4) 结果数据对象中的数据与预先设计的表现层相融合ƈ展现l用h其持久化?
q样的J2EEpȝ具有下以几个优点:
(1) 多个视图能共享一个模型。在MVC架构中,模型响应用户hq返回响应数据,视图负责格式化数据ƈ把它们呈现给用户Q业务逻辑和表C层分离Q同一个模型可以被不同的视N用,所以大大提高了代码的可重用性?
(2) 模型是自包含的,与控制器和视图保持相对独立,所以可以方便地改变应用E序的数据层和业务规则。由于MVC的三个模块相互独立,改变其中一个不会媄响其它的两个Q所以依据这U设计思想能构造良好的松耦合的构件?
(3) 控制器提高了应用E序的灵zL和可配|性?
使用MVC需要精心的计划Q由于它的内部原理比较复杂,所以需要花费一些时间去理解它。将MVCq用到J2EE应用E序中,会带来额外的工作量,增加应用的复杂性,所以MVC不适合型应用E序?
面对大量用户界面Q业务逻辑复杂的大型应用程序,MVC会使Y件在健壮性,代码重用和结构方面上一个新的台Ӟ其是商业Y件的高度可变性。在我实际开发过的项?一个电子商务网站与一个搜索引擎,和正在开发的一个进销存管理系l?中,我都应用CStrutsQ项目相Ҏ说比较成功,通过实践认识到ƈ不是pȝ中加入了Struts的类库和标签p明用了MVC StrutsQStruts仅仅是一U思想Q你也可以不用它的类库模拟MVC环境QY件的开应该要做到灵zd变?
W三?分布式架?
J2EE的两大特征就是分层与分布。据l计Q大多数中小企业U应用都用不上分布式Q因此本文侧重介l多层,要的介绍一下分布式的适用范围?
“记住分布式计算机的W一法则:不要分布你的对象!”?Martin Fowler Patterns of Enterprise Application Architecture)。我们真正需要分布式应用?其实我们早已意识到大部分J2EE应用E序Q特别是WEB应用E序Qƈ不能从分布式体系架构中受益。甚至相反,׃前期的过渡设计,在根本无需分布式的应用中大量用分布式技术,不但没有享受到分布式的优点,而且q带来了不同应用层之间昂늚q程调用Q引入了复杂的远E访问期间基架构和分布式~程。同Ӟ我们也必L白逻辑层的分层q比物理层的分隔重要。选择分布式也是选择EJBQ选择EJB也就是选择了重量lg?
也就是说Q一些应用选择分布式架构应该有_的理由。如果真正是明确的业务需求,q属于应有的分布式应?internal distribution)Q你需要根据特定的情Ş选择适当的分布式机制Q如果是Z灉|性,在项目的未来某个时期也许要远E输出某些功能,应用E序的架构应该是允许引入选择性的分布式应?selective distribution)Q而不是在目早期p行过渡设计,直接使用分布式架构?
W四?数据持久层的设计
W一?业务对象的持久化
业务对象(Business Object)Q是对真实世界的实体的Y件抽象,它可以代表业务领域中的hQ地点,事物或概c业务对象包括状态和行ؓQ判断一个类是否成ؓ业务对象的一个重要标准,是看q个cL否同是拥有状态和行ؓ。业务对象具有的特征:包含状态和行ؓQ代表业务领域的人,地点Q事物或概念。可以重用。通常分ؓ三类业务对象:
(1) 实体业务对象Q代表hQ地点,事物或概늚lgQ在分布式应用中可以作ؓ实体EJBQ在更一般的Web应用中可以作为包含状态和行ؓ?FONT face="Times New Roman">Java Bean?
(2) q程业务对象Q代表应用中的业务过E或程Q通常依赖于业务对象。在J2EE应用中,它们通常作ؓ会话EJB或是消息驱动EJB。在非分布式应用中,我们可以使用h理和控制应用行为的常规Java Bean?
(3) 事g业务对象Q代表应用中的一些事Ӟ如异常,警告或是时?
业务对象提供了通用的术语概念,不管是技术h员还是非技术h员都可以׃nq理解他们,q且它可以隐藏实现细节,对外只暴露接口?
业务对象在Java~程中可以分两类Q分别是普通纯Java对象(pure old java object or plain ordinary java object or what ever POJO)和持久对象(Persistent Object POQ?
持久对象实际上必d应数据库中的entityQ所以和POJO有所区别。比如说POJO是由new创徏Q由GC(垃圾攉?回收。但是持久对象是insert数据库创建,由数据库delete删除的。持久对象的生命周期和数据库密切相关。另外持久对象往往只能存在一个数据库Connection之中QConnection关闭以后Q持久对象就不存在了Q而POJO只要不被GC回收QL存在的。由于存在诸多差别,因此持久对象PO(Persistent Object)在代码上肯定和POJO不同Qv码PO相对于POJO会增加一些用来管理数据库entity状态的属性和Ҏ?
持久化意味着通过手工或其化方式输入到应用中的数据Q能够在应用l束q行后依然存在,即应用q行l束或者计机关闭后,q些信息依然存在Q不什么样的系l都需要数据的持久化。我们将需要持久化处理的BOUC为POQ当应用中的业务对象在内存中创徏后,它们不可能永q存在,在从内存中清除之前,要被持久化到关系数据库中?
W二?数据讉K对象设计模式
上一节中提到PO在从内存中清除之前要被持久化到关pL据库中,如何做到q一点呢QOOP是当今的LQ但是不得不使用关系型数据库Q因此在企业U开发中Q对?关系的映?Object-Relation MappingQ简UORM)是很关键的一部分了。围lORM和数据持久化的方式,软g领域通常采用一U数据访问对?Data Access ObjectQ简UDAO)设计模式。DAO模式提供了访问关pd数据库系l所需要的所有操作接口,其中包括创徏数据库,定义表,字段和烦引,建立表间的关p,更新和查询数据库{。DAO模式底层数据库讉K操作与高层业务逻辑分离开Q对上层提供面向对象的数据访问接?接口的实现通常使用抽象工厂设计模式来实?。在DAO的实CQ可以采用XML语言来配|对象和关系型数据之间的映射。在映射数据库表Ӟ值对象类及其子类所构成的树形结构被用来映射一个数据库表,该承树通过XML 配置文g对应数据库中的单个表Q这使得底层的关pd的数据库表结构能够面向对象模型所隐藏Q另外,׃面向对象设计Ҏ中类的可l承性,采用l承树对应一个表的策略得该映射{略极易扩展Qƈ且能够将一个复杂的数据表{化成若干单的值对象来表示Q提高了pȝ的可l护性和可修Ҏ?
对于一般的J2EE应用Q可以直接通过JDBC~程来访问数据库。JDBC可以说是讉K持久层最原始Q最直接的方法。在企业U应用开发中Q可以通过JDBC~程Q来开发自qDAO APIQ将数据库访问期间操作封装v来,供业务层l一调用。因此DAO所装的接口在团队开发中昑־非常的重要,几乎是项目成败的关键?
DAO模式在系l中所处的位置
DAO的实现通常使用工厂Ҏ模式Q工厂方法模式将创徏实例的工作与使用实例的工作分开Q也是_让创建实例所需要的大量初始化工作从单的构造函C分离出去。只需要调用一个统一的方法,卛_Ҏ需要创建出各种对象的实例,对象的创建方法不再用~码到程序模块中Q而是l一~写在工厂类中。这样在pȝq行扩充修改Ӟpȝ的变化仅存在于工厂类内部Q而绝对不会对其他对象造成影响?
W三?ORM框架的原理和重要?
如果数据模型非常复杂Q那么直接通过JDBC~程来实现持久化框架需要有专业的知识,q样可以直接使用采用W三Ҏ供的持久化框架。如HibernateQIbatisQJDO?
在用ORM框架时也需要遵守OOP设计原则和MVC框架的基本原则,都应该确保框架没有渗透到应用中,应用的上层组件应该和ORM框架保持独立。ORMq求的目标就是要 PO在用上量和POJO一_对于E序员来_他们可以把PO当作POJO来用Q而感觉不到PO的存在。ORM框架是要做到维护数据库表记录的PO完全是一个符合Java Bean规范的POJOQ没有增加别的属性和Ҏ?
同是ORM框架Q但不同的ORM工具实现的方式有所不同Q目前主要有两种ORM工具竞争QJDO与HibernateQ以下介l一下它们的工作机理?
JDO的实现ORMҎ如下Q?
(1) ~写POJO?
(2) ~译POJO?
(3) 使用JDO的一个专门工P叫做EnhancerQ一般是一个命令行E序Q手工运行,或者在ant脚本里面q行Q对POJO的class文g处理一下,把POJO替换成同名的PO?
(4) 在运行时q行的实际上是POQ而不是POJO?
该方法有点类gJSPQJSP也是在编译期被{换成Servlet来运行的Q在q行期实际上q行的是ServletQ而不是JSP?
Hibernate的实现方法如下:
(1) ~写POJOQ通常我们可以通过Hibernate官方提供的MiddleGen for Hibernate 和Hibernate Extension工具包,很方便的Ҏ现有数据库,导出数据库表l构Q生成XML格式的ORM配置文g和POJO?
(2) ~译POJO?
(3) 直接q行Q在q行Ӟ由Hibernate的cglib库利用Java的反技术动态把POJO转换为PO?
由此可以看出Hibernate是在q行时把POJO的字节码转换为PO的,而JDO是在~译期{换的。一般认为JDO的方式效率会E高Q毕竟是~译期{换嘛。但是Hibernate的作者Gavin King说cglib(Hibernatecd中的一个必需使用的jar?的效率非怹高,q行期的PO的字节码生成速度非常之快Q效率损失几乎可以忽略不计。实际上q行时生成PO的好处非常大Q这样对于程序员来说Q是无法接触到PO的,PO对他们来说完全透明。可以更加自q以POJO的概忉|UPO。Hibernate查询语言(Query Language)Q即HQLQHQL是一U面向对象的查询语言Q不同于SQL(l构化查询语a)Q它具备l承、多态和兌{特性?
Hibernate是从PO实例中取values的,所以即使Session关闭Q也一样可以get/setQ可以进行跨Session的状态管理?
在N层的J2EEpȝ中,׃持久层和业务层和Web层都是分开的,此时Hibernate的PO完全可以当作一个POJO来用Q在各层间自׃递,而不用去Session是开q是兟뀂如果你把这个POJO序列化的话,甚至可以用在分布式环境中?
因此Q在较ؓ常用的数据持久方案中QHibernate的ORM框架是最优秀的,下面是对各种持久Ҏ的比较:
l 行的数据持久层架构Q?
Business Layer <-> Session Bean <-> Entity Bean <-> DB
l Z解决性能障碍的替代架构:
Business Layer <-> DAO <-> JDBC <-> DB
l 使用Hibernate来提高上面架构的开发效率的架构Q?
Business Layer <-> DAO <-> Hibernate <-> DB
通过实际开发和试Q分析出以上三个架构的优~点Q?
(1) 内存消耗:采用JDBC的架构无疑是最省内存的QHibernate的架构次之,EJB的架构最差?
(2) q行效率Q如果JDBC的代码写的非怼化,那么JDBC架构q行效率最高,但是实际目中,q一点几乎做不到Q这需要程序员非常_NJDBCQ运用Batch语句Q调整PreapredStatement的Batch Size和Fetch Size{参敎ͼ以及在必要的情况下采用结果集cache{等。而一般情况下E序员是做不到这一点的。因此Hibernate架构表现出最快的q行效率。EJB的架构效率会差的很远?
(3) 开发效率:在有Eclipse、JBuilder{开发工L支持下,对于单的目QEJB架构开发效率最高,JDBCơ之QHibernate最差。但是在大的目Q特别是持久层关pL很复杂的情况下QHibernate效率高的惊hQJDBCơ之Q而EJB架构很可能会p|?
在我工作时所做过的一些项目的q程中,例如电子商务|站 (通常是在写数据库查询和存储过E接口时)Q面对大量的数据反复存储调用Q工作量之大无法忍受Q这个很烦恼的持久层开发的问题一直在困扰我。持久层的开发现在一般来说要么用CMPQ要么用JDBCQ?FONT face="Times New Roman">DAO?FONT face="Times New Roman"> CMP需要的成本太高Q对于这U无需对象分布的系lƈ不实用,?FONT face="Times New Roman">JDBC+DAO也存在很多的困难Q尤其是数据库表很庞大关pd复杂(通常的商业Y件的数据库都非常的庞?FONT face="Times New Roman">)的时候,我很隑ց到把关系表记录完整的映射?FONT face="Times New Roman">PO的关pM来,q主要体现在多表的关pL法直接映到Ҏ久对象的映射上来Q可能是一个表映射多个持久对象Q有可能是多个表映射一?FONT face="Times New Roman">POQ更有可能的是表的某些字D|到一个持久对象,但是另外一些字D|到别的持久对象上。而且即ɘq些问题都处理好了,也不能直接按照对象的方式来对持久对象Q?FONT face="Times New Roman">POQ编E,因ؓ存在1Q?FONT face="Times New Roman">N关系的持久对象的查询其实是1+nơ对数据库的SQLQ等于是完全抛弃了对象设计,完全是按照表字段q行操作Q但在这U情况下重复~程量简直无法想象。更重要的是q样做会为系l的成|留下非常大的隐患Q因Z般系l是从需求设计,pȝ设计q样自顶而下的,如果都到了详l设计阶D被持久层映问题限Ӟ不得不自底向上修改设计方案,又回Cq程化设计上来,严重了违背了依赖倒{原则(DIP)?FONT face="Times New Roman"> 很明显我q不是第一个遇到这U问题的人,其实q是一个经典的问题Q?B>对象和关pȝ映射问题。自?FONT face="Times New Roman">OOP行以来Q就一直存在这个难题,所以才有h提出关pL据库q行重新设计Q也会有对象型数据库的出玎ͼ但实际上关系数据库ƈ没有被淘汎ͼ于是只能在上层的应用层找解x案?FONT face="Times New Roman">ORM产品正是U解x案而设计的?FONT face="Times New Roman"> 一个好?FONT face="Times New Roman">ORM应该有如下的特点Q?
(1) 开源和免费?FONT face="Times New Roman">LicenseQQ何h都可以在需要的时候研I源代码Q改写源代码Q进行功能的定制?
(2) 轻量U封装,避免引入q多复杂的问题,调试ҎQ也减轻E序员的负担?
(3) h可扩展性,API开放,当功能不够用的时候,用户可以自行~码q行扩展?
(4) 开发者活跃,产品有稳定的发展保障?FONT face="Times New Roman">
HibernateW合以上ORM的标准,它的文档也是非常有特色的地方(而且提供了简体中文版)Q它不仅仅是 Hibernate的功能介l那么简单,它实际上是一个持久层设计的最佛_늚l验ȝQ文档里面的例子和ȝ全部都是最佌计的l晶?FONT face="Times New Roman">SUN公司最q发布的EJB3.0中的实体EJB仿效?FONT face="Times New Roman">Hibernateq种轻量U组件技术?FONT face="Times New Roman">
W四?数据持久?
数据持久化问题关键在于它的复杂性?复杂性是应用开发过E中最令h头疼的一个问题。每当在一个应用中增加一个功能时Q它的复杂性通常呈几何的增ѝ这U复杂性往往DE序的开发无法再l箋下去?
专家应用开发过E生的复杂性分Zc,即非本质的(accidentalQ?和本质的QessentialQ。本质的复杂性是对于解决目标问题所必然产生的复杂性,非本质的复杂性是׃选择了不适当的开发工具和设计工具而生的复杂性。对于一个功能确定的E序来讲Q本质的复杂性是定的,而非本质的复杂性则是没有限制的。因此,一个应用的开发要惌利地取得成功,需要尽可能地减非本质的复杂性?
设计模式使h们可以更加简单方便地复用成功的设计和体系l构。将已证实的技术表q成设计模式Q也会新系l开发者更加容易理解其设计思\?
衡量一个系l优U与否的关键因素,除了能够满用户需求外q有如下斚wQ首先是灉|性。灵zL意指这U结构或模式不依赖于M实际应用Q应该与操作pȝ、应用程序无兟뀂提供独立的l构Q可以提供最大的重用。其ơ是可扩展性。随着业务的扩展,新的业务不断增加Q业务逻辑自然增加Q系l必然会q行修改或添加相?功能模块。再ơ是可配|性。最后是安全性?
数据持久层的设计采纳了多U设计模式,最大限度的降低了系l内部各模块、子pȝ间的耦合性,使得pȝ相对易于扩展Qƈ且能够在q行改变Ӟ保证持久层的业务逻辑层相对稳定,基本不需要因持久层的调整改变而进行逻辑层的变动?
Ҏ数据源不同,数据讉K也不同。根据存储的cd(?pL据库、面向对象数据库{?和供应商不同Q持久性存?比如数据?的访问差别也很大。当业务lg或表C组仉要访问某数据源时Q它们可以用合适的 API来获得连接性,以及操作该数据源。但是在q些lg中包含连接性和数据讉K代码会引入这些组件及数据源实C间的紧密耦合。组件中q类代码依赖性应用E序从某U数据源q移到其它种cȝ数据源将变得非常ȝ和困难,当数据源变化Ӟlg也需要改变,以便于能够处理新cd的数据源?
数据持久层通过调整抽象工厂(Abstract Factory)模式和工厂方?Factory Method) 模式QDAO模式辑ֈ了很高的灉|度?数据持久层用数据访问对象来抽象和封装所有对数据源的讉K。DAO理着与数据源的连接以便于索和存储数据QDAO实现了用来操作数据源的访问机Ӟ内部装了对 Hibernate数据操纵、事务处理、会话管理等API的封装。外界依赖于DAO的业务组件ؓ其客L使用DAO提供了更单的接口QDAO完全?客户端隐藏了数据源实现细节。由于当低层数据源实现变化时QDAO向客L提供的接口不会变化,采用该设计模式允许DAO调整C同的存储模式Q而不会媄 响其客户端或业务lgQ即使将来不再采用Hibernate作ؓ关系映射框架Q上层客L也不会受CQ何媄响。另外,DAOq充当组件和数据源之间的适配 器的角色?
当底层存储随着实现的变化而变化时Q该{略可以通过使用抽象工厂模式实现。抽象工厂可以基于工厂方法实现而创建,q可使用工厂Ҏ实现。该{略提供一个DAO的抽象工厂对象,其中该对象可以构造多U类型的具体的DAO工厂Q每个工厂支持一U不同类型的持久性存储实现。一旦你获取某特定实现的具体DAO工厂Q可以用它来生成该实现中所支持和实现的DAO?
W五?数据库连接池、缓存及pȝ性能的提?
通过使用框架和设计模式对数据讉K的封装,极大的提高了软g的可扩展可维护性,同时也带来了pȝ的性能问题QJ2EEpȝ通过以下一些技术解册些问题?B>
~存QCacheQ,对于数据库来_厂商的做法往往是在内存中开辟相应的区域来存储可能被多次存取的数据和可能被多ơ执行的语句Q以使这些数据在下次被访问时不必再次提交对DBMS的请求和那些语句在下ơ执行时不必再次~译。同P数据持久层采用缓存技术来保存已经从数据库中检索出来的部分常用数据。客L讉K持久层时Q持久层首先访问缓存,如果能够命中则直接从~存中提取数据,否则再向数据库发送提取数据的指o。这U设计能够大q度地提高数据访问速度?
数据库连接池QConnection PoolQ,池是一个很普遍的概念,和缓冲存储有机制相近的地方,都是~减了访问的环节Q但它更注重于资源的׃n。对于访问数据库来说Q徏立连接的代h比较昂贵Q因此,数据持久层徏立了“连接池”以提高讉K的性能。数据持久层把连接当作对象,整个pȝ启动后,q接池首先徏立若q连接,讉K本来需要与数据库连接的区域Q都改ؓ和池相连Q池临时分配q接供访问用,l果q回后,讉K连接交q。这U设计消除了JDBC与数据源建立q接的gӞ同时在应用提供了对数据源的q发讉K?
享元模式QFlyweightQ,面向对象语言的原则就是一切都是对象,但是如果真正使用hQ有时对象数可能昑־很庞大,比如Q数据库中的记录Q如果以每条记录作ؓ一个对象,提取几千条记录,对象数就是几千,q无疑相当耗费内存。数据持久层依据享元模式设计了若q元c,装可以被共享的cR这U设计策略显著降低了pȝ的内存消耗?
W六?Java反射技?
在不了解的情况下要想操纵一个Java对象Q需要用Java的反技术。反技术的出现为Java开发工具和服务容器目的开发提供了新的技术手D,例如W四章中提到的Hibernate在运行时使用cglibcd用Java反射技术动态地POJO转化为PO?
Java的J2SE开发包中包含一个特D的部分QJava反射接口Q被攄在java.lang.reflect包中。反Java的类Q包和接口实C自我描述和动态操作的功能Q这些功能对于Java应用E序的开发者来_gq于基础化了Q但是反提供的不仅仅是是一功能那么简单,通过反射QJava提供了新的一U非直接参与调用的方式,打破了一些固有的限制。反已lؓ多个成功的项目所q用Q生了Z意料的成功效果。配合一些把基础的反功能扩展的工具目QJava的动态功能得以出色地发挥出来。Hibernate也得益于反射Q反Hibernate的代码更z有效,在操作时增强了功能?
反射技术机制很多原来困难的Q务变得容易实CQ反技术的功能很强大,但是开发者在实际的开发过E中Qƈ不一定非要用反技术不可,需要根据具体的情Ş来选择技术方案。即使一定要使用反射技术,也需要一些已有的工具的支持?
W五?J2EE架构中各层的数据表示
W一节MVC三层体系l构中的数据表示要求
三层体系l构中的数据表示首先要做到的是数据的低耦合度,以Struts三层体系l构ZQ三层数据的表示应该如下:
按照MVC的设计原则,层与层之间应该保持相对独立,数据的传递在不同的层之间通常利用Java Bean来创建数据传输对?FONT face="Times New Roman">(Data Transfer ObjectQ简U?FONT face="Times New Roman">DTO)Q从技术的角度上面来说Q采?FONT face="Times New Roman">DTO来传输数据可以减传输数据的冗余Q提高传输效率,更重要的是实C各个层之间的独立Q每个层分工明。模型层负责业务逻辑Q视囑ֱ负责向用户展C模型状态。采?FONT face="Times New Roman">DTOQ模型层对视囑ֱ屏蔽了业务逻辑l节Q向视图层提供可以直接显C给用户的数据。在一个规范的J2EE架构中,不同层的数据表示应该被限制在层内Q而不应该扩散到其它层Q这样可以降低层间的耦合性,提高J2EE架构整体的可l护性和可扩展性。比如说Web层的逻辑q行了修改,那么只需要修?FONT face="Times New Roman">Web层的Form Beanl构Q而不需要触动业务层和持久层的代码修攏V同LQ当数据库表q行了小的调_那么也只需要修Ҏ久层数据表示Q而不需要触动业务层代码?FONT face="Times New Roman">Web层代码?
先来谈谈ActionFormBean和持久层?FONT face="Times New Roman">PO之间的重大区?FONT face="Times New Roman">:在简单的应用中,ActionFormBean和PO几乎是没有区别,所以很多hq脆是用ActionFormBean来充当POQ于?ActionFormBean从JSP面到Servlet控制层再C务层Q然后穿q持久层Q最后一直映到数据库表。系l以后需要修改其工作量无法想像。但是在复杂的应用中QActionFormBean和PO是分ȝQ它们也不可能一栗ActionFormBean是和|页里面的Form表单一一对应的,Form里面有什么元素,Bean里面有什么属性。而PO和数据库表对应,因此如果数据库表不修改,那么PO也不会修改,如果面的流E和数据库表字段对应关系不一_那么又如何能够用ActionFormBean来取代PO呢?例如一个用h册页面要求注册用L基本信息Q因此HTML Form里面包含了基本信息属性,于是你需要一个ActionFormBean来一一对应Q每个Bean属性对应一个文本框或者选择框等。而用戯个持久对象的属性和ActionFormBean有什么不同呢Q它会有一些ActionFormBean所没有的集合属性,如用L权限属性,用户的组属性,用户的帖子等{。另外还有可能的是在ActionFormBean里面?个属性,分别是用LFirst NameQ?Middle NameQ?Last NameQ或者干脆在Userq个持久对象中就是一?Name 对象属性。假设注册页面原来只要提供First NameQ那么ActionFormBeanp一个属性,后来要提供全名,要改ActionFormBeanQ加两个属性。但是这个时候PO是不应该修改Q因为数据库没有攏V?
W二?J2EEpȝ中各层数据表C的设计
在一个完整的N层J2EEpȝ中应该如何进行合理数据表C计呢QStruts是这样做的:
JSP(View) ---> Action Form Bean (Module) ---> Action(Control)Action
Form Bean是Web层的数据表示Q它和HTML面Form对应Q只要Web面的操作流E发生改变,它就要相应的q行修改Q它不应该也不能被传递到业务层和持久层,否则一旦页面修改,会一直牵q到业务层和持久层的大面U的代码q行修改QAction是它的边界?
Action(Web Control) ---> Business Bean ---> DAO ---> ORM --->DB
PO则是业务层和持久层的数据表示Q它在业务层和持久层之间q行动Q它不应该也不能被传递到Web层的View中去Q而ActionServlet是它的边界?
再来看看整个架构的数据流E:当用户通过览器访问网,提交了一个页面。于是Action得到了这个Form BeanQ它会把Form Bean属性读出来Q然后构造一个PO对象Q再调用业务层的Beanc,完成了注册操作,重定向到成功面。而业务层Bean收到q个PO对象之后Q调用DAO接口ҎQ进行持久对象的持久化操作。当用户查询某个会员的信息的时候,他用全名q行查询Q于是Action得到一个UserNameFormBean包括?个属性,分别是first nameQ?middle nameQ?last nameQ然后Action把UserNameFormBean?个属性读出来Q构造Name对象Q再调用BOQ把Name对象传递给BOQ进行查询。BO取得Name(注意: Name对象只是User的一个属?对象之后调用DAO接口Q返回一个User的PO对象Q注意这个User不同于在Web层用的UserFormBean。然后BO把User对象q回lAction。Action得到User对象之后Q把User的基本属性取出,构造UserFormBeanQ然后把UserFormBean request.setAttribute(?Q然后重定向到查询结果页面。查询页面拿到request对象里面的ActionFormBeanQ自动调用tag昄?
W六?设计模式的概念与几种常用的J2EE设计模式
W一?设计模式的概?
E序设计是思维具体化的一U方式,是思考如何解决问题的q程Q设计模式是在解決问题的q程中,一些良好思\的经验集成。最早提到设计模式,ZM提到Gof的著作,它最早将l典?3U模式集合在一赯明,对后期学习程序设计,其是对从事物g导向E序的h们v了莫大的影响。对于Java设计师来_源代码的汇聚按尺度来分,可以分ؓ由Java语句l成的“代码模式”,由Javacd对象l成的“设计模式”,由大度的构件组成的“架构模式”?
Gof 提到的OOP中设计模式涵盖三大类?
(1) 创徏Creational 模式
对象的生需要消耗系l资源,所以如何有效率的生、管理与操作对象Q一直都是值得讨论的课题, Creational 模式即与对象的徏立相养I在这个分cM的模式给Z一些指导原则及设计的方向?
l 单工?Simple Factory) 模式
l 抽象工厂(Abstract Factory) 模式
l 建?Builder) 模式
l 工厂Ҏ(Factory Method) 模式
l 原始模型(Prototype) 模式
l 单例(Singleton) 模式
l 多例(Multition)模式
(2) l构Structural 模式
如何设计对象之间的静态结构,如何完成物g之间的ѝ实C依赖关系Q这关系到系l设计出来是否健壮(robustQ:是否易懂、易l护、易修改、耦合度低{。Structural 模式正如其名Q其分类下的模式l出了在不同场合下所适用的各U对象关pȝ构?
l ~省适配(Default Adapter) 模式
l 适配(Adapter)模式
l 桥梁(Bridge) 模式
l 合成(Composite) 模式
l 装饰(Decorator) 模式
l 门面(Façade) 模式
l 享元(Flyweight) 模式
l 代理(Proxy) 模式
(3) 行ؓBehavioral 模式
对象之间的合作行为构成了E序的最l行为,对象之间若有良好的行Z动,不仅使得E序执行时更有效率,更可以让对象的职责更为清晰、整个程序的动态结构(对象之间的互相调用)更有Ҏ?
l 责Q?Chain of Responsibility) 模式
l 命o(Command) 模式
l 解释?Interpreter) 模式
l q代?Iterator) 模式
l 调停?Mediator) 模式
l 备忘?Memento) 模式
l 观察?Observer) 模式
l 状?State) 模式
l {略(Strategy) 模式
l 模版Ҏ(Template Method) 模式
l 讉K?Visitor) 模式
W二?工厂创徏模式与单例模?
l 单工?Simple Factory)模式:又称静态工厂方法模?Static Factory Method Pattern)
l 工厂Ҏ(Factory Method)模式:又称多态性工?Polymorphic Factory)模式或虚拟构造子(Virtual Constructor)模式
l 抽象工厂(Abstract Factory)模式:又称工具?Toolkit)模式
下面以简单工厂设计模式ؓ例说明代码模式在Java~程中的应用?
从上囑֏以看出,单工厂模式涉及到工厂角色Q抽象品角色以及具体品角色等三个角色:
l 工厂c?Creator)角色:担Qq个角色的是工厂Ҏ模式的核心,含有与应用紧密相关的商业逻辑Q工厂类在客L的直接调用下创徏产品对象Q它往往׃个具体JavacL实现
l 抽象产品(Product)角色:担Qq个角色的类是由工厂Ҏ模式所创徏的对象的父类Q或它们共同拥有接口。抽象品角色可以用一个Java接口或者Java抽象cd?
l 具体产品(Concrete Product)角色:工厂Ҏ模式所创徏的Q何对象都是这个角色的实例Q具体品角色由一个具体Javacd?
例如我们要在E序中生两个对象:一个圆形与一个方形,建立时要同时讑֮它们的中心位|,然后它们会负责画己。我们可以设计一?Shape Factory工厂c,负责创徏指定的对象,调用者只指定对象名UC中心位置Q而不这些对象如何生,对象生成后的中心位置讑֮被隐藏于 Shape Factory工厂cM?
如上图所C的QMain代表了客L角色Q它只依赖于表层业务调用Q而不兛_特定的实例,实例的细节由Shape Factory完成Q我们以一个简单的E序来实C面这个UMLcdQ?
public interface IShape { //建立IShape接口
public void setCenter(int xQ?int y);
public void draw(); //定义一个接口方?BR>}
public class Circle implements IShape {
private int x;
private int y;
public void setCenter(int xQ?int y) {//实现IShape接口setCenterҎ
this.x = x;
this.y = y;
}
public void draw() { //实现IShape接口draw()Ҏ
System.out.println("Circle center at ("
+ x + "Q?" + y + ")");
}
}
public class Square implements IShape {
private int x;
private int y;
public void setCenter(int xQ?int y) { //实现IShape接口setCenterҎ
this.x = x;
this.y = y;
}
public void draw() {//实现IShape接口draw()Ҏ
System.out.println("Square center at ("
+ x + "Q?" + y + ")");
}
}
public class ShapeFactory {
public static IShape createShapeAt(String nameQ?int xQ?int y) {
try {
IShape shape
= (IShape) Clas.forName(name).newInstance();//使用Java反射技术获得名为name产品实例Qƈ让IShape接口持有此实例对?BR> shape.setCenter(x,y);
return shape;
}
catch(Exception e) {
System.out.println(
"Sorry! No such class defined!"); return null;
}
}
}
public class Main {
public static void main(String args[]) {
// 产生一个圆形ƈ且显C它
ShapeFactory.createShapeAt("Circle"Q?10Q?10).draw();
System.Out.println();
// 产生一个方形ƈ昄?BR> ShapeFactory.createShapeAt("Square"Q?20Q?25).draw();
}
}
客户只要面对FactoryQ客户依赖于产品的调用介面,产品的具体实例是可以与客户隔开的,它们也是可以互换的。简单工厂模式是工厂Ҏ模式与抽象工厂模式的一U特D情况,关于它们的实现可以参考相兌料?
单例模式保某一个类只有一个实例,而且自行实例化ƈ向整个系l提供这个实例。单例模式在pȝ设计时用非常广泛,常用的资源管理器一般用此模式Q在一些线E安全的情况下用也比较多,如数据库q接池访问接口,属性文件管理等?
以上面的UML图ؓ例来说明单例模式的用方法,我们可以在第一ơ需要实例时再创建对象,也就是采用所谓的Lazy Initialization懒汉式:
public class Singleton {
private static Singleton instance = null;
private Singleton() {
// .......
}
public static Singleton getInstance() { //获得pȝ唯一实例的静态方?BR> if (instance == null) instance = new Singleton();
return instance;
}
// ...... 其它代码
}
上面的代码适用于单U程的程序,在多U程的程序下Q以下的写法在多个线E的竞争资源下,仍有可能生两个以上的对象Q存在线E安全性问题,例如下面的情况:
Thread1: if(instance == null) // true
Thread2: if(instance == null) // true
Thread1: instance = new Singleton(); // 产生一个实?BR>Thread2: instance = new Singleton(); // 又生一个实?BR>Thread1: return instance; // q回一个实?BR>Thread2: return instance; // 又返回一个实?BR> 在多U程环境下,Z了避免资源同时竞争而导致如上生多个实例的情况Q我们加上同步机Ӟ
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
synchronized static public Singleton getInstance() {//得系l唯一实例的静态方法加上线E同步机Ӟ保证此方法同时只能被一U程调用
if (instance == null) instance = new Singleton();
return instance;
} }
W三?使用工厂模式实现DAO
׃J2EE模式众多Q篇q有限,q里只概要介l其中的一U用工厂模式实现数据访问对象?BR> 使用数据讉K对象(DAO)来抽象和装所有对数据源的讉K?DAO理着与数据源的连接以便于索和存储数据QDAO实现了用来操作数据源的访问机制。依赖于DAO的业务组件ؓ其客L使用DAO提供了更单的接口QDAO完全向客L隐藏了数据源实现l节。由于当低层数据源实现变化时QDAO向客L提供的接口不会变化,所以该模式允许DAO调整C同的存储模式Q而不会媄响其客户端或业务lg。重要的是,DAO充当lg和数据源之间的适配器?BR> 当低层存储随着实现的变化而变化时Q策略可以通过使用抽象工厂模式而实现。抽象工厂可以基于工厂方法实现而创建,q可使用工厂Ҏ实现Q该{略提供一?DAO的抽象工厂对象,其中该对象可以构造多U类型的具体的DAO工厂Q每个工厂支持一U不同类型的持久性存储实现。一旦你获取某特定实现的具体DAO工厂Q你可以使用它来生成该实C所支持和实现的DAOQ如下面cd所C?
例如在一个项目中有四张表Q分别是用户信息?user Info)Q论坛表QForumQ,主题表(TopicQ,回复?Reply)。先创徏与数据库表相对应lgJava BeanQ然后ؓ每一个数据库表配|一个数据库操作接口。如下所C:
UserInfo讉K对象接口
package com.webclass.dao;
public interface UserInfoDao {
//讄帖子属性时Q用L属?
public void upUserState(String stateQString usrName);
// 查询用户是否存在判断(q回整个用户)
public UserInfo selectUser(String usrName);
//讄用户权限
public void upUserRole(int i QString usrRoleQint usrId)Q?
//修改用户信息
public boolean editUser(UserInfo user);
……………………………等操作逻辑Ҏ
?
Forum讉K对象接口
package com.webclass.dao;
public interface ForumDao {
…………………操作逻辑Ҏ
}
Reply讉K对象接口
package com.webclass.dao;
public interface ReplyDao {
………………操作逻辑Ҏ
}
Topic讉K对象接口
package com.webclass.dao;
public interface TopicDao {
………………操作逻辑Ҏ
}
接下来就是写具体cdC上其接口Q而接口方法不依赖于类的具体实现。数据库的访问对象已l创建好之后Q应用程序将调用q些对象q行数据库操作,如何调用q些对象呢?我们使用一个工厂类来专门负责这些对象的创徏工作Q?
public class DBFactory {
public static ForumDao dBForum=null;
public static ReplyDao dBReply=null;
public static TopicDao dBTopic=null;
public static UserInfoDao dBUserInfo=null;
synchronized public static ForumDao getDBForum(){
if(dBForum==null) dBForum=new DBForum();
return dBForum;
}
synchronized public static ReplyDao getDBReply(){
if(dBReply==null) dBReply=new DBReply();
return dBReply;
}
synchronized public static TopicDao getDBTopic(){
if(dBTopic==null) dBTopic=new DBTopic();
return dBTopic;
}
synchronized public static UserInfoDao getDBUserInfo(){
if(dBUserInfo==null) dBUserInfo=new DBUserInfo();
return dBUserInfo;
}
}
q样应用E序的上层组件就可以直接调用DBFactory工厂对象所持有的静态对象来q来数据库操作了Q更重要的是当底层数据库讉K操作发生改变时只需修改讉K对象Q而不会L及到上层lgQ用Y件健壮性和灉|性大大提高?
ȝ
即是利用当今最先进的Y件^台J2EEQ开发企业应用程序仍然是一个难题,因ؓ软g的复杂性和脆弱性无法回ѝJ2EE通过J2EE API提供了技术与服务的高层抽象,使企业开发得C一定的化。但是,仅仅知道J2EE API是不够的。要设计良好的体pȝ构,得到高质量的应用E序Q要知道何时如何正确的用J2EE APIQ就要用更为实用的方式?
计算机技术更新发展很快,新技术方面由于经验缺乏,通常我们要自q如何正用这些技术,要通过不断的试验,直到扑և最佳的ҎQ最佳的Ҏ昄是从实践中得到的Q不是发明出来的Q而是发现和不断完善的?
工程学中的一大原则就是ȝl验和利用实践证明行之有效的ҎQY件开发也是这栗经验有助于更快更顺利的建立良好的解x案,从而节省成本,提高质量。唯一的问题就是要需要获得经验,但这个经验可以从别h那里间接获得Q而不一定需要自q直接l验。别人的l验如何描述Q多q来Q模式已l成为收集,规范和分析某些情境中常见问题的有效方法,学习模式可以节省自己的时_知道如何Ҏ许多开发h员的间接l验q行合理的设计?
l束?
在撰写这论文期_我查阅了大量的技术书c和文章Q学C很多的知识,使自q技术水q_C提高。同时得C袁健老师的悉心指导和帮助Q在此,我向袁健老师表达诚挚的谢意?
参考文献:
1. Bruce Eckel. Think in JavaW三?.电子工业出版C? 北京. 2002
2. Khawar Zaman Ahmed. J2EE和UML开发Java企业U应用程? 清华大学出版C? 2003
3. Crig Bery. 实用J2EE设计模式~程指南. www.china-pub.com. 2003
4. 孙卫? Tomcat与Java Web开发技? 电子工业出版C? 2004
5. 孙卫? _NStruts. 电子工业出版C? 2004
6. Christopher Alexande. The Timeless Way of Building. Arrangement with Oxford University Press, Inc. 2003
7. 夏昕. Hibernate开发指? www.china-pub.com. 2004
?struts+ hibernate q种l构中,是不应该把Hibernate产生的PO直接传递给JSP的,不管他是IteratorQ还是ListQ这是一个设计错误?
我来谈谈在J2EE架构中各层的数据表示ҎQ?
Web层的数据表示是FormBeanQ数据来源于HTML Form POST
业务层的数据表示是VO
持久层的数据表示是POQ其数据来源于数据库Q持久层的数据表CZ如CMP
在一个规范的J2EE架构中,不同层的数据表示应该被限制在层内Q而不应该扩散到其它层Q这样可以降低层间的耦合性,提高J2EE架构整体的可l护性和可扩展性。比如说Web层的逻辑q行了修改,那么只需要修改FormBean的结构,而不需要触动业务层和持久层的代码修攏V同hQ当数据库表q行了小的调_那么也只需要修Ҏ久层数据表示Q而不需要触动业务层代码和Web层代码?
不过׃Hibernate的强大功能,例如动态生成POQPO的状态管理可以脱SessionQ得在应用了Hibernate的J2EE框架中,PO完全可以充当VOQ因此我们下面把PO和VO合ƈQ统UCؓPO?
先来谈谈ActionFormBean和持久层的PO之间的重大区别?
在简单的应用中,ActionFormBean和PO几乎是没有区别,所以很多hq脆是用ActionFormBean来充当POQ于是ActionFormBean从JSP面到Servlet控制层再C务层Q然后穿q持久层Q最后一直映到数据库表。真是一竿子捅到了底Q?
但是在复杂的应用中,ActionFormBean和PO是分ȝQ他们也不可能一栗ActionFormBean是和|页里面的Form表单一一对应的,Form里面有什么元素,Bean里面有什么属性。而PO和数据库表对应,因此如果数据库表不修改,那么PO也不会修改,如果面的流E和数据库表字段对应关系不一_那么你又如何能够使用ActionFormBean来取代PO呢?
比如说吧Q用h册页面要求注册用L基本信息Q因此HTML Form里面包含了基本信息属性,于是你需要一个ActionFormBean来一一对应(注意Q是一一对应)Q每个Bean属性对应一个文本框或者选择框什么的?
而用戯个持久对象呢Q他的属性和ActionFormBean有什么明显不同呢Q他会有一些ActionFormBean所没有的集合属性,比如说用L权限属性,用户的组属性,用户的帖子等{。另外还有可能的是在ActionFormBean里面?个属性,分别是用LFirst Name, Middle Name, Last NameQ而在我的Userq个持久对象中就是一?Name 对象属性?
假设我的注册面原来只要你提供First NameQ那么ActionFormBeanp一个属性,后来我要你提供全名,你要改ActionFormBeanQ加两个属性。但是这个时候PO是不应该修改_因ؓ数据库没有改?
那么在一个完整的J2EEpȝ中应该如何进行合理的设计呢?
JSP(View) ---> ActionFormBean(Module) ---> Action(Control)
ActionFormBean是Web层的数据表示Q它和HTML面Form对应Q只要Web面的操作流E发生改变,它就要相应的q行修改Q它不应该也不能被传递到业务层和持久层,否则一旦页面修改,会一直牵q到业务层和持久层的大面U的代码q行修改Q对于Y件的可维护性和可扩展性而言Q是一个灾难,Actiont是他的边界Q到此ؓ止!
Action(Web Control) ---> Business Bean ---> DAO ---> ORM --->DB
而PO则是业务层和持久层的数据表示Q它在业务层和持久层之间q行动Q他不应该也不能被传递到Web层的View中去Q而ActionServlet是他的边界Q到此ؓ止!
然后来看一看整个架构的程Q?
当用户通过览器访问网,提交了一个页面。于是Action拿到了这个FormBeanQ他会把FormBean属性读出来Q然后构造一个PO对象Q再调用业务层的Beanc,完成了注册操作,重定向到成功面。而业务层Bean收到q个PO对象之后Q调用DAO接口ҎQ进行持久对象的持久化操作?
当用h询某个会员的信息的时候,他用全名q行查询Q于是Action得到一个UserNameFormBean包括?个属性,分别是first name, middle name, last nameQ然后Action把UserNameFormBean?个属性读出来Q构造Name对象Q再调用业务BeanQ把Name对象传递给业务BeanQ进行查询?
业务Bean取得Name(注意: Name对象只是User的一个属?对象之后调用DAO接口Q返回一个User的PO对象Q注意这个User不同于在Web层用的UserFormBeanQ他有很多集合属性滴。然后业务Bean把User对象q回lAction?
Action拿到User之后Q把User的基本属性取?集合属性如果不需要就免了)Q构造UserFormBeanQ然后把UserFormBean request.setAttribute(...)Q然后重定向到查询结果页面?
查询面拿到request对象里面的ActionFormBeanQ自动调用tag昄之?
ȝQ?
FormBean是Web层的数据表示Q他不能被传递到业务层;PO是持久层的数据表C,在特定情况下Q例如Hibernate中,他可以取代VO出现在业务层Q但是不POq是VO都必限制在业务层内使用Q最多到达Web层的ControlQ绝不能被扩散到View厅R?
FormBean和PO之间的数据{化是在Action中进行滴?
BTW:
JDO1.xq不能像Hibernate功能q样强大QPO不能q持久层,所以必d业务层用VOQ因此必d业务层进行大量的VO和PO的{化操作,相对于Hibernate来说Q编E比较烦琐?
当然咯,理论是一回事Q实际操作也不一定非要这样干Q你可以自行取舍Q在实际目中灵zM点,增加一点bad smellQ提高开发效率。只不过在大型项目中最好还是严丝合~,不然的话Q改版的时候会痛苦的很滴?BR>===============
中间?VO 层要有自动的转化框架好Q手动{好麻烦的?BR>
谁能解释一下这个:
当用户通过览器访问网,提交了一个页面。于是Action拿到了这个FormBeanQ他会把FormBean属性读出来Q然后构造一个PO对象Q再调用业务层的Beanc,完成了注册操作,重定向到成功面。而业务层Bean收到q个PO对象之后Q调用DAO接口ҎQ进行持久对象的持久化操作?