DeLi Linux 中文翻译备忘录

DeLi Linux 是一个致力于为老旧电脑(486~PII)提供自由操作系统的轻量级桌面型 linux 发行版。它认为,扔掉那些老旧电脑是可耻的,一些不愿扔掉老旧电脑或者买不起新电脑的人可以用这些老旧电脑装上 DeLi Linux ,从而变为一台可用的系统。虽然,这些电脑也可以装上 Windows 95 类似的操作系统,不过,这些操作系统微软不再生产和支持了。针对于这些操作系统的软件也不再有了。所以,DeLi Linux 决定来承担这一使命。

我想说,DeLi Linux 的愿望是良好的,我赞赏他们的愿望。我试用了一下 DeLi Linux,确实,它能在我的 486DX100 + 24M 内存的机器上顺畅运行,但是,它的中文支持相当的差,我向DeLi Linux 的论坛提交了一则反映中文支持极差这个问题的帖子:Some experiments of using DeLi Linux with chinese,据 DeLi Linux 的作者 haary 回复,因为DeLi Linux-0.7.2 使用的是GTK1,GTK1 对unicode 没有支持,所以如此。DeLi Linux 未来的 0.8 版本将转换为使用GTK2,非 latin 字体将得到完全支持。所以,我想,DeLi Linux-0.8 的中文支持将有巨大的提升。

我觉得,如果 DeLi Linux 发展得好,那些老旧电脑的使用者将受益;如果 DeLi Linux 的中文支持发展得好,那么,老旧电脑的中文使用者将受益(包括我)。于是,当我看见了 DeLi Linux 的作者 haary 发的需要翻译人员的帖子:Translators wanted 后,我决定加入 DeLi Linux 现有的10种语言之一的中文的翻译。下面是翻译的网页地址:

DeLi Linux 英文主页 DeLi Linux 中文主页

DeLi Linux 英文WiKi DeLi Linux 中文WiKi

因为我的英文水平实在有限,错误之处在所难免。所以,如果你发现翻译中有什么错误的话,请点击这里反馈给我,谢谢。

在这篇日记的评论中记录我在翻译过程中碰到的一些问题。所以这篇日记取名叫备忘录。

把下面WiKi链接中出现的“chinese:” 去掉就是英文原文的地址。如果您对我的这些问题有什么意见或建议的话,请在评论中回复一下吧。谢谢。

DeLi Linux 中文翻译反馈 (Feedback for DeLi Linux's translation for chinese)

我们已经把 DeLi Linux 的主页翻译成了中文,我们将陆续翻译它的 WiKi 文档和其它东西。 如果你发现了任何关于中文翻译的问题或者有任何建议的话,请在这里回复或者发送邮件到 mdx-xx#tom.com (把#换成@)。谢谢。

DeLi Linux 英文主页      DeLi Linux 中文主页

DeLi Linux 英文WiKi     DeLi Linux 中文WiKi 

We have tranlated DeLi Linux's homepage into chinese, and, we will translate its WiKi documents and some other things. If you find any problem or any advice for its chinese translation, please comment here or contact us with email: mdx-xx#tom.com (change # with @). Thanks a lot.

DeLi Linux english homepage      DeLi Linux chinese homepage

DeLi Linux english WiKi     DeLi Linux chinese WiKi 

什么是AndroMDA?(翻译稿v1.0)

版权声明:

原文摘自:http://www.andromda.org/index.php?option=com_content&task=blogcategory&id=0&Itemid=42

本译文为“123行动”网站(http://www.123go.org.cn )版权所有,以<a href="http://creativecommons.org/licenses/by/2.0/">Creative Commons License</a>方式授权。欢迎转载,但请注明译文原始出处(http://www.123go.org.cn/disDiaryContentAction.do?searchDiaryID=1778&goalID=1778&naviStr=a10 )

另外,由于译者水平相当有限,错漏之处敬请指正,联系信箱:mdx-xx@tom.com,或在上述译文原始出处回复。 最新译文也会在

上述译文原始出处随时更新。

×××××××××××××××××××××××××××××××××××××××××××××××××××××××

什么是AndroMDA?

  AndroMDA(发音:Andromeda)是一个依附于模型驱动架构范例(MDA)的可扩展的生成器框架。来自UML工具的模型能被转换成你喜欢的平台(J2EE, Spring, .NET)的可布署的组件。不像其它MDA工具包,AndroMDA带来许多已经做好的盒子,这些盒子征对现在的Axis, jBPM, Struts, JSF, Spring 和 Hibernate之类的开发工具包。AndroMDA也包含一个工具包来制造你自己的盒子或定制元盒子(已经存在的东西)。使用它,你可以用你喜欢的UML工具制造一个定制的代码生成器。

核心特性

AndroMDA当前带来下列特性:

模块设计:AndroMDA所有主要的构成块是可插接的,可以被改变来满足你的需要

支持主要的UML工具,像:MagicDraw, Poseidon, Enterprise Architect 和其它的UML工具

带来完全的UML1.4元模型(当前正在开发对UML2.0的支持)-你也有另外的选择,你可以带来你自己的元模型在MOF XMI里,并从基于它的模型产生代码

使用联系到元模型类的OCL 限制来验证输入的模型。预先配置的限制也保护你不犯大多数普通的建模错误,即添加你自己项目专用的限制

模型到模型的转换帮助你提高抽象水平,现在在java里你可以写你自己的转换,在AndroMDA的下一个主版本里,你也可以在其它的转换语言里写这种转换,例如在 QVT里-一种像 Atlas Transformation Language (ATL)的转换语言

能够使用模版产生任何种类的文本输出(像:源代码,数据库脚本,网页,O/R映射配置文件等等)-你教AndroMDA,它就能做!

模版是基于著名的模版引擎。  现在支持Velocity 和 FreeMarker

现存可用的征对普通企业架构(EJB, Spring, Hibernate, Struts, JSF, Axis, jBPM)的盒子

来自世界各地的队伍成员的全天候的支持:测量在forum.andromda.org的问题响应时间你会非常吃惊!论坛已经包含超过10,000篇文章。

 

盒子

  非常像Eclipse,AndroMDA以插件架构为特色。AndroMDA本身基本上是一个转换引擎。为了支持任意的目标架构,你可以插入定制的转换。这些转换被打包成所谓的盒子。

  

  AndroMDA 带来许多现存可用的盒子,比如:

Spring

EJB 2 / 3

Webservices

Hibernate

Struts

JSF

Java

XSD

 你也可以写你自己的盒子来支持你自己的架构或框架。AndroMDA能够为任何你能够想像得到的架构和计算机语言产生输出。写作盒子的课程可以在AndroMDA.com上找到。  

                                             -littlebat

                                                                              2006.3.15

What is AndroMDA?(翻译草稿)

What is AndroMDA?       

AndroMDA (pronounced "Andromeda") is an extensible generator framework that adheres to the Model Driven Architecture (MDA) paradigm. Models from UML tools will be transformed into deployable components for your favorite platform (J2EE, Spring, .NET). Unlike other MDA toolkits, AndroMDA comes with a host of ready-made cartridges that target today's development toolkits like Axis, jBPM, Struts, JSF, Spring and Hibernate. AndroMDA also contains a toolkit for building your own cartridges or customize existing ones - the meta cartridge. Using it, you can build a custom code generator using your favorite UML tool. 

什么是AndroMDA?

  AndroMDA(发音:Andromeda)是一个依附于模型驱动架构范例(MDA)的可扩展的生成器框架。来自UML工具的模型能被转换成你喜欢的平台(J2EE, Spring, .NET)的可布署的组件。不像其它MDA工具包,AndroMDA带来许多已经做好的盒子,这些盒子是征对现在的Axis, jBPM, Struts, JSF, Spring 和 Hibernate之类的开发工具包。AndroMDA也包含一个工具包来制造你自己的盒子或定制元盒子(已经存在的东西)。使用它,你可以制造一个定制的、使用你喜欢的UML工具的代码生成器。

  

Core Features       

AndroMDA currently comes with the following features:

Modular design: all major building blocks of AndroMDA are pluggable and can be exchanged to meet your needs

Support for major UML tools like MagicDraw, Poseidon, Enterprise Architect and more

Comes with the complete UML 1.4 metamodel (support for UML 2.0 is currently being developed) - alternatively, you can bring your own metamodel in MOF XMI and generate code from models based on it

Validates the input models using OCL constraints which are related to the metamodel classes. Comes with pre-configured constraints that protect you against the most common modeling mistakes - add your own project-specific constraints, too.

Model-to-model transformations help to raise abstraction level. Write your own transformations, currently in Java, or in any transformation language, e.g. the QVT-like Atlas Transformation Language (ATL), in the next major AndroMDA release.

Can generate any kind of text output using templates (source code, database scripts, web pages, O/R mapping configuration files, etc.) -  you teach it, AndroMDA does it!

Templates are based on well-known template engines. Currently, Velocity and FreeMarker are supported

Ready-to-use cartridges for common enterprise architectures (EJB, Spring, Hibernate, Struts, JSF, Axis, jBPM)

Support around the clock by team members around the globe: Measure the response time for questions in forum.andromda.org and be amazed by it! The forum already contains more than 10.000 articles.

核心特性

AndroMDA当前带来下列特性:

模块设计:AndroMDA所有主要的构成块是可插接的,可以被改变来满足你的需要

支持主要的UML工具,像:MagicDraw, Poseidon, Enterprise Architect 和其它的UML工具

带来完全的UML1.4元模型(当前正在开发对UML2.0的支持)-你也有另外的选择,你可以带来你自己的元模型在MOF XMI里,并从基于它的模型产生代码

使用联系到元模型类的OCL限制来验证输入的模型。预先配置的限制也保护你不犯大多数普通的建模错误,即添加你自己项目专用的限制

模型到模型的转换帮助你提高抽象水平,现在在java里你可以写你自己的转换,在AndroMDA的下一个主版本里,你也可以在其它的转换语言里写这种转换,例如在 QVT里-一种像 Atlas Transformation Language (ATL)的转换语言

能够使用模版产生任何种类的文本输出(像:源代码,数据库脚本,网页,O/R映射配置文件等等)-你教AndroMDA,它就能做!

模版是基于著名的模版引擎。  现在支持Velocity 和 FreeMarker

现存可用的征对普通企业架构(EJB, Spring, Hibernate, Struts, JSF, Axis, jBPM)的盒子

来自世界各地的AndroMDA队伍成员的全天候的支持:测量在forum.andromda.org的问题响应时间你会非常吃惊!论坛已经包含超过10,000篇文章。

Cartridges       

Very much like Eclipse, AndroMDA features a plug-in architecture. AndroMDA itself basically is a transformation engine. To support arbitrary target architectures, you can plug-in custom transformations. These transformations are packaged as so-called cartridges.

AndroMDA comes with a host of ready-to-use cartridges such as:

Spring

EJB 2 / 3

Webservices

Hibernate

Struts

JSF

Java

XSD

You can also write your own cartridge to support your own architecture or framework. AndroMDA can produce output for any architecture and computer language you might imagine. Courses for cartridge writing are available at AndroMDA.com.

 

盒子

  非常像Eclipse,AndroMDA以插件架构为特色。AndroMDA本身基本上是一个转换引擎。为了支持任意的目标架构,你可以插入定制的转换。这些转换被打包成所谓的盒子。

  

  AndroMDA 带来许多现存可用的盒子,比如:

Spring

EJB 2 / 3

Webservices

Hibernate

Struts

JSF

Java

XSD

 你也可以写你自己的盒子来支持你自己的架构或框架。AndroMDA能够为任何你能够想像得到的架构和计算机语言产生输出。写作盒子的课程可以在AndroMDA.com上找到。  

(转帖)再译:使用struts+spring+hibernate 组装web应用

转自:http://blog.matrix.org.cn/page/littlebat?entry=%C3%A5%C2%86%C2%8D%C3%A8%C2%AF%C2%91_%C3%A4%C2%BD%C2%BF%C3%A7%C2%94%C2%A8

struts_spring_hibernate_%C3%A7%C2%BB%C2%84%C3%A8%C2%A3%C2%85web%C3%A5%C2%BA%C2%94%C3%A7%C2%94%C2%A8

的“再译:使用struts+spring+hibernate 组装web应用”

原作者: Mark Eagle 04/07/2004(http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html

译者:孟大兴 来自学习日记( http://www.learndiary.com ) 联系方式:mdx-xx@tom.com

[译者前言:这篇文章由totodo在2004-09-16已经翻译过( http://www.matrix.org.cn/resource/article/1034.html ),

本译文借鉴了不少他的成果。希望各位朋友指出我译文中的不足,并能根据上面的联系方式及时反馈给我,我将第一时间内在

http://blog.matrix.org.cn/page/littlebat?entry=%C3%A5%C2%86%C2%8D%C3%A8%C2%AF%C2%91_%C3%A4%C2%BD%C2%BF%C3%A7%C2%94%C2%A8

struts_spring_hibernate_%C3%A7%C2%BB%C2%84%C3%A8%C2%A3%C2%85web%C3%A5%C2%BA%C2%94%C3%A7%C2%94%C2%A8

中更新译文,争取为广大不熟悉英文的朋友提供尽可能准确的译文。

另外,如果你在运行本文章的例程时碰到问题:请参考:

1、原作者的网站上的答疑( http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=3 );

2、我的试验文中的例程的日记( http://www.learndiary.com/disDiaryContentAction.do?goalID=1468

http://www.learndiary.com/disDiaryContentAction.do?goalID=1470 )]

正文

*********************************************************************************************************

    其实,就算用Java建造一个不是很烦琐的web应用程序,也不是件轻松的事情。当为一个应用程序建造一个构架时有许多事情需要考虑。

从高层来说,开发者需要考虑:怎样建立用户接口(user interfaces)?在哪里处理业务逻辑?和怎样持久化应用数据。这三层每一层都有它

们各自的问题需要回答。 各个层次应该使用什么技术?怎样才能把应用程序设计得松耦合和能灵活改变?构架允许层的替换不会影响到其

它层吗?应用程序怎样处理容器级的服务(container level services),比如事务处理(transactions)?

当为你的web应用程序创建一个构架时,需要涉及到相当多的问题。幸运的是,已经有不少开发者已经遇到过这类重复发生的问题,并且

建立了处理这类问题的框架。一个好框架具备以下几点: 减轻开发者处理复杂的问题的负担(“不重复发明轮子”);内部定义为可扩展

的;有一个强大的用户群支持。框架通常能够很好的解决一方面的问题。然而,你的应用程序有几个层可能都需要它们各自的框架。就如解

决你的用户接口(UI)问题时你就不应该把事务逻辑和持久化逻辑掺杂进来。例如,你不应该在控制器(controller)里面写jdbc代码,使它包

含有业务逻辑,这不是控制器应该提供的功能。它应该是轻量级的,代理来自用户接口(UI)外的调用请求给其它服务于这些请求的应用层。

好的框架自然的形成代码如何分布的指导。更重要的是,框架减轻开发者从头开始写像持久层这样的代码的痛苦,使他们专注于对客户来说很

重要的应用逻辑。

这篇文章将讨论怎样组合几个著名的框架去做到松耦合的目的,怎样建立你的构架,怎样让你的各个应用层保持一致。富于挑战的是:

组合这些框架使得每一层都以一种松耦合的方式彼此沟通,而与底层的技术无关。这篇文章将使用3种流行的开源框架来讨论组合框架的策

略。表现层我们将使用Struts(http://jakarta.apache.org/struts);业务层我们将使用Spring(http://www.springframework.org/);持久层使用Hibrenate

(http://www.hibernate.org/).你也可以在你的应用程序中替换这些框架中的任何一种而得到同样的效果。图1展示了当这些框架组合在一起时

从高层看是什么样子。

图1用Struts, Spring, 和 Hibernate框架构建的概览

应用程序的分层 (Application Layering)

大多数不复杂的web应用都能被分成至少4个各负其责的层次。这些层次是:表现层(presentation)、持久层(persistence)、业务层

(business)、领域模型层(domain model)。每层在应用程序中都有明确的责任,不应该和其它层混淆功能。每一应用层应该彼此独立但要给

他们之间放一个通讯接口。让我们从审视各个层开始,讨论这些层应该提供什么和不应该提供什么。

表现层 (The Presentation Layer)

在一个典型的web应用的一端是表现层。很多Java开发者也理解Struts所提供的。然而,太常见的是,他们把像业务逻辑之类的耦合的代码

放进了一个org.apache.struts.Action。所以,让我们在像Struts这样一个框架应该提供什么上取得一致意见。这儿是Struts负责的:

为用户管理请求和响应;

提供一个控制器(controller)代理调用业务逻辑和其它上层处理;

处理从其它层掷出给一个Struts Action的异常;

为显示提供一个模型;

执行用户接口(UI)验证。

这儿是一些经常用Struts编写的但是却不应该和Struts表现层相伴的项目:

直接和数据库通讯,比如JDBC调用;

业务逻辑和与你的应用程序相关的验证;

事务管理;

在表现层中引入这种代码将导致典型耦合(type coupling)和讨厌的维护。

持久层 (The Persistence Layer )

在典型web应用的另一端是持久层。这通常是使事情迅速失控的地方。开发者低估了构建他们自己的持久层框架的挑战性。一般来说,机构内

部自己写的持久层不仅需要大量的开发时间,而且还经常缺少功能和变得难以控制。有几个开源的“对象-关系映射”(ORM)框架非常解决

问题。尤其是,Hibernate框架为java提供了"对象-关系持久化"(object-to-relational persistence)机制和查询服务。Hibernate对那些已经熟悉

了SQL和JDBC API的Java开发者有一个适中的学习曲线。Hibernate持久对象是基于简单旧式Java对象(POJO)和Java集合(Java collections)。

此外,使用Hibernate并不妨碍你正在使用的IDE。下面的列表包含了你该写在一个持久层框架里的代码类型:

查询相关的信息成为对象。Hibernate通过一种叫作HQL的面向对象(OO)的查询语言或者使用条件表达式API(expressive criteria API)来做这

个事情。 HQL非常类似于SQL-- 只是把SQL里的table和columns用Object和它的fields代替。有一些新的专用的HQL语言成分要学;不过,它们容

易理解而且文档做得好。HQL是一种使用来查询对象的自然语言,花很小的代价就能学习它。

保存、更新、删除储存在数据库中的信息。

像Hibernate这样的高级“对象-关系”映射(object-to-relational mapping)框架提供对大多数主流SQL数据库的支持,它们支持“父/子”

(parent/child)关系、事务处理、继承和多态。

这儿是一些应该在持久层里被避免的项目:

业务逻辑应该在你的应用的一个高一些的层次里。持久层里仅仅允许数据存取操作。

你不应该把持久层逻辑(persistence logic)和你的表现层逻辑(presentation logic)搅在一起。避免像JSPs或基于servlet的类这些表现层组件里的

逻辑和数据存取直接通讯。通过把持久层逻辑隔离进它自己的层,应用程序变得易于修改而不会影响在其它层的代码。例如:Hebernate能够被

其它持久层框架或者API代替而不会修改在其它任何层的代码。

业务层(The Business Layer)

在一个典型的web应用程序的中间的组件是业务层或服务层。从编码的视角来看,这个服务层是最容易被忽视的一层。不难在用户接口(UI)

层或者持久层里找到散布在其中的这种类型的代码。这不是正确的地方,因为这导致了应用程序的紧耦合,这样一来,随着时间推移代码将很

难维护。幸好,针对这一问题有好几种Frameworks存在。在这个领域两个最流行的框架是Spring和PicoContainer,它们叫作微容器

(microcontainers),你可以不费力不费神的把你的对象连在一起。所有这些框架都工作在一个简单的叫作“依赖注入”(dependency

injection)(也通称“控制反转”(inversion of control))的概念上。这篇文章将着眼于Spring的为指定的配置参数通过bean属性的setter注入

(setter injection)的使用。Spring也提供了一个构建器注入(constructor injection)的复杂形式作为setter注入的一个替代。对象们被一个简单的

XML文件连在一起,这个XML文件含有到像事务管理器(transaction management handler)、对象工厂(object factories)、包含业务逻辑的服务

对象(service objects)、和数据存取对象(DAO)这些对象的引用(references)。

这篇文章的后面将用例子来把Spring使用这些概念的方法说得更清楚一些。业务层应该负责下面这些事情:

处理应用程序的业务逻辑和业务验证;

管理事务;

预留和其它层交互的接口;

管理业务层对象之间的依赖;

增加在表现层和持久层之间的灵活性,使它们互不直接通讯;

从表现层中提供一个上下文(context)给业务层获得业务服务(business services );

管理从业务逻辑到持久层的实现。

领域模型层 (The Domain Model Layer )

最后,因为我们讨论的是一个不是很复杂的、基于web的应用程序,我们需要一组能在不同的层之间移动的对象。领域对象层由那些代表现实

世界中的业务对象的对象们组成,比如:一份订单(Order)、订单项(OrderLineItem)、产品(Product)等等。这个层让开发者停止建立和维

护不必要的数据传输对象(或者叫作DTOs),来匹配他们的领域对象。例如,Hibernate允许你把数据库信息读进领域对象(domain objects)的

一个对象图,这样你可以在连接断开的情况下把这些数据显示到UI层。那些对象也能被更新和送回到持久层并在数据库里更新。而且,你不必

把对象转化成DTOs,因为DTOs在不同的应用层间移动,可能在转换中丢失。这个模型使得Java开发者自然地以一种面向对象的风格和对象打交

道,没有附加的编码。

结合一个简单的例子

  既然我们已经从一个高的层次上理解了这些组件, 现在就让我们开始实践吧。在这个例子中,我们还是将合并Struts、Spring、Hibernate框

架。每一个这些框架在一篇文章中都有太多的细节覆盖到。这篇文章将用一个简单的例子代码展示怎样把它们结合在一起,而不是进入每个框

架的许多细节。示例应用程序将示范一个请求怎样跨越每一层被服务的。这个示例应用程序的一个用户能保存一个订单到数据库中和查看一个

在数据库中存在的订单。进一步的增强可以使用户更新或删除一个存在的订单。

你可以下载这个应用的源码(http://www.onjava.com/onjava/2004/04/07/examples/wiring.zip)。

  因为领域对象(domain objects)将和每一层交互,我们将首先创建它们。这些对象将使我们定义什么应该被持久化,什么业务逻辑应该被

提供,和哪种表现接口应该被设计。然后,我们将配置持久层和用Hibernate为我们的领域对象(domain objects)定义“对象-关系”映射

(object-to-relational mappings)。然后,我们将定义和配置我们的业务对象(business objects)。在有了这些组件后,我们就能讨论用Spring把

这些层连在一起。最后,我们将提供一个表现层(presentation layer),它知道怎样和业务服务层(business service layer)交流和知道怎样处理

从其它层产生的异常(exceptions)。

领域对象层(Domain Object Layer)

因为这些对象将和所有层交互,这也许是一个开始编码的好地方。这个简单的领域模型将包括一个代表一份订单(order)的对象和一个代表

一个订单项(line item for an order)的对象。订单(order)对象将和一组订单项(a collection of line item)对象有一对多(one-to-many)的

关系。例子代码在领域层有两个简单的对象:

com.meagle.bo.Order.java: 包括一份订单(oder)的概要信息;

com.meagle.bo.OrderLineItem.java: 包括一份订单(order)的详细信息;

考虑一下为你的对象选择包名,它将反映你的应用程序是怎样分层的。例如:简单应用的领域对象(domain objects)可以放进com.meagle.bo包

[译者注:bo-business object?]。更多专门的领域对象将放入在com.meagle.bo下面的子包里。业务逻辑在com.meagle.service包里开始打包,

DAO对象放进com.meagle.service.dao.hibernate包。对于forms和actions的表现类(presentation classes)分别放入com.meagle.action 和

com.meagle.forms包。准确的包命名为你的类提供的功能提供一个清楚的区分,使当故障维护时更易于维护,和当给应用程序增加新的类或包时

提供一致性。

持久层配置(Persistence Layer Configuration)

用Hibernate设置持久层涉及到几个步骤。第一步是进行配置持久化我们的领域业务对象(domain business objects )。因为我们用于领域对象

(domain objects )持久化的Hibernate和POJOs一起工作( 此句原文:Since Hibernate works with POJOs we will use our domain objects for

persistence.),因此,订单和订单项对象包括的所有的字段的都需要提供getter和setter方法。订单对象将包括像ID、用户名、合计、和订单项这

样一些字段的标准的JavaBean格式的setter和getter方法。订单项对象将同样的用JavaBean的格式为它的字段设置setter和getter方法。

  Hibernate在XML文件里映射领域对象到关系数据库。订单和订单项对象将有两个映射文件来表达这种映射。有像XDoclet

(http://xdoclet.sourceforge.net/)这样的工具来帮助这种映射。Hibernate将映射领域对象到这些文件:

Order.hbm.xml

OrderLineItem.hbm.xml

你可以在WebContent/WEB-INF/classes/com/meagle/bo目录里找到这些生成的文件。配置Hibernate SessionFactory

http://www.hibernate.org/hib_docs/api/net/sf/hibernate/SessionFactory.html)使它知道是在和哪个数据库通信,使用哪个数据源或连接

池,加载哪些持久对象。SessionFactory提供的Session(http://www.hibernate.org/hib_docs/api/net/sf/hibernate/Session.html)对象是Java对象

和像选取、保存、更新、删除对象这样一些持久化功能间的翻译接口。我们将在后面的部分讨论Hibernate操作Session对象需要的SessionFactory

配置。    

业务层配置(Business Layer Configuration )

  既然我们已经有了领域对象(domain objects),我们需要有业务服务对象来执行应用逻辑、执行向持久层的调用、获得从用户接口层

(UI layer)的请求、处理事务、处理异常。为了将所有这些连接起来并且易于管理,我们将使用Spring框架的bean管理方面

(bean management aspect)。Spring使用“控制反转”(IoC),或者“setter依赖注入”来把这些对象连好,这些对象在一个外部的XML文件中

被引用。“控制反转”是一个简单的概念,它允许对象接受其它的在一个高一些的层次被创建的对象。使用这种方法,你的对象从必须创建其

它对象中解放出来并降低对象耦合。

  这儿是个不使用IoC的对象创建它的从属对象( object creating its dependencies without IoC)的例子,这导致紧的对象耦合:

  图2:没有使用IoC的对象组织。对象A创建对象B和C。

    

  这儿是一个使用IoC的例子,它允许对象在一个高一些层次被创建和传进另外的对象,所以另外的对象能直接使用现成的对象·

[译者注:另外的对象不必再亲自创建这些要使用的对象](allows objects to be created at higher levels and passed into objects so that they

can use the implementations directly):

  图3:对象使用IoC组织。对象A包含setter方法,它们接受到对象B和C的接口。这也可以用对象A里的接受对象B和C的构建器完成。

    

建立我们的业务服务对象(Building Our Business Service Objects)

  我们将在我们的业务对象中使用的setter方法接受的是接口,这些接口允许对象的松散定义的实现,这些对象将被设置或者注入。在我们这

个例子里我们将使我们的业务服务对象接受一个DAO去控制我们的领域对象的持久化。当我们在这篇文章的例子中使用Hibernate( While the

examples in this article use Hibernate),我们可以容易的转换到一个不同的持久框架的实现,通知Spring使用新的实现的DAO对象。你能明白编

程到接口和使用“依赖注入”模式是怎样宽松耦合你的业务逻辑和你的持久化机制的。

  这儿是业务服务对象的接口,它是一个DAO对象依赖的桩。(Here is the interface for the business service object that is stubbed for a DAO

object dependency: )


public interface IOrderService {

  public abstract Order saveNewOrder(Order order)

    throws OrderException,

           OrderMinimumAmountException;

  public abstract List findOrderByUser(

                                     String user)

                           throws OrderException;

  public abstract Order findOrderById(int id)

                           throws OrderException;

  public abstract void setOrderDAO(

                             IOrderDAO orderDAO);

}

  注意上面的代码有一个为DAO对象准备的setter方法。这儿没有一个getOrderDAO方法因为它不是必要的,因为不太有从外面访问连着的

OrderDAO对象的需要。DAO对象将被用来和我们的持久层沟通。我们将用Spring把业务服务对象和DAO对象连在一起。因为我们编码到接口,

我们不会紧耦合实现。

下一步是写我们的DAO实现对象。因为Spring有内建的对Hibernate的支持,这个例子DAO将继承HibernateDaoSupport

http://www.springframework.org/docs/api/org/springframework/orm/hibernate/support/HibernateDaoSupport.html)类,这使得我们容易取得

一个到HibernateTemplate(http://www.springframework.org/docs/api/org/springframework/orm/hibernate/HibernateTemplate.html)类的引用,

HibernateTemplate是一个帮助类,它能简化Hibernate Session的编码和处理HibernateExceptions。这儿是DAO的接口:


public interface IOrderDAO {

  public abstract Order findOrderById(

                                    final int id);

  public abstract List findOrdersPlaceByUser(

                           final String placedBy);

  public abstract Order saveOrder(

                               final Order order);

}

  我们还有两个对象要和我们的业务层连在一起。这包括HibernateSessionFactory和一个TransactionManager对象。这在Spring配置文件里直接完

成。Spring提供一个HibernateTransactionManager

http://www.springframework.org/docs/api/org/springframework/orm/hibernate/HibernateTransactionManager.html),它将从工厂绑定一个

Hibernate Session到一个线程来支持事务(见ThreadLocal(http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ThreadLocal.html)获取更多的信

息)。这儿是HibernateSessionFactory和HibernateTransactionManager的Spring配置。


<bean id="mySessionFactory"

       class="org.springframework.orm.hibernate.

              LocalSessionFactoryBean">

  <property name="mappingResources">

    <list>

      <value>

        com/meagle/bo/Order.hbm.xml

      </value>

      <value>

        com/meagle/bo/OrderLineItem.hbm.xml

      </value>

    </list>

  </property>

  <property name="hibernateProperties">

    <props>

      <prop key="hibernate.dialect">

        net.sf.hibernate.dialect.MySQLDialect

      </prop>

      <prop key="hibernate.show_sql">

        false

      </prop>

      <prop key="hibernate.proxool.xml">

        C:/MyWebApps/.../WEB-INF/proxool.xml

      </prop>

      <prop key="hibernate.proxool.pool_alias">

          spring

      </prop>

    </props>

  </property>

</bean>

<!-- Transaction manager for a single Hibernate

SessionFactory (alternative to JTA) -->

<bean id="myTransactionManager"

         class="org.

                springframework.

                orm.

                hibernate.

                HibernateTransactionManager">

  <property name="sessionFactory">

    <ref local="mySessionFactory"/>

  </property>

  </bean>

  每一个对象能被Spring配置里的一个<bean>标记引用。在这个例子里,bean “mySessionFactory”代表一个HibernateSessionFactory,bean

“myTransactionManager”代表一个Hibernate transaction manager。注意transactionManger bean有一个叫作sessionFactory的属性元素。

HibernateTransactionManager有一个为sessionFactory准备的setter和getter方法,它们是用来当Spring容器启动时的依赖注入。sessionFactory属性引用

mySessionFactory bean。这两个对象现在当Spring容器初始化时将被连在一起。这种连接把你从为引用和创建这些对象而创建singleton对象和工

厂中解放出来,这减少了你应用程序中的代码维护。mySessionFactory bean有两个属性元素,它们翻译成为mappingResources 和 hibernatePropertes

准备的setter方法。通常,如果你在Spring之外使用Hibernate,这个配置将被保存在hibernate.cfg.xml文件中。不管怎样,Spring提供了一个便捷的方式

--在Spring配置文件中合并Hibernate的配置。获得更多的信息查阅Spring API(http://www.springframework.org/docs/api/index.html)。

既然我们已经配置了我们的容器服务beans和把它们连在了一起,我们需要把我们的业务服务对象和我们的DAO对象连在一起。然后,我们需要

把这些对象连接到事务管理器。

这是在Spring配置文件里的样子:


<!-- ORDER SERVICE -->

<bean id="orderService"

  class="org.

         springframework.

         transaction.

         interceptor.

         TransactionProxyFactoryBean">

  <property name="transactionManager">

    <ref local="myTransactionManager"/>

  </property>

  <property name="target">

    <ref local="orderTarget"/>

  </property>

  <property name="transactionAttributes">

    <props>

      <prop key="find*">

     PROPAGATION_REQUIRED,readOnly,-OrderException

      </prop>

      <prop key="save*">

     PROPAGATION_REQUIRED,-OrderException

      </prop>

    </props>

  </property>

</bean>

<!-- ORDER TARGET PRIMARY BUSINESS OBJECT:

Hibernate implementation -->

<bean id="orderTarget"

         class="com.

                meagle.

                service.

                spring.

                OrderServiceSpringImpl">

  <property name="orderDAO">

    <ref local="orderDAO"/>

  </property>

</bean>

<!-- ORDER DAO OBJECT -->

<bean id="orderDAO"

         class="com.

                meagle.

                service.

                dao.

                hibernate.

                OrderHibernateDAO">

  <property name="sessionFactory">

    <ref local="mySessionFactory"/>

  </property>

</bean>

图4是我们已经连在一起的东西的一个概览。它展示了每个对象是怎样相关联的和怎样被Spring设置进其它对象中。把这幅图和示例应用中的

Spring配置文件对比查看它们之间的关系。

图4:这是Spring怎样将在这个配置的基础上装配beans

  这个例子使用一个TransactionProxyFactoryBean,它有一个为我们已经定义了的事务管理者准备的setter方法。这是一个有用的对象,它知道

怎样处理声明的事务操作和你的服务对象。你可以通过transactionAttributes属性定义事务怎样被处理,transactionAttributes属性为方法名定义模式

和它们怎样参与进一个事务。获得更多的关于在一个事务上配置隔离层和提交或回滚查阅TransactionAttributeEditor

http://www.springframework.org/docs/api/org/springframework/transaction/interceptor/TransactionAttributeEditor.html)。

  TransactionProxyFactoryBean

http://www.springframework.org/docs/api/org/springframework/transaction/interceptor/TransactionProxyFactoryBean.html)类也有一个为一个

target准备的setter,target将是一个到我们的叫作orderTarget的业务服务对象的引用(a reference)。 orderTarget bean定义使用哪个业务服务对象并

有一个指向setOrderDAO()的属性。orderDAO bean将居于这个属性中,orderDAO bean是我们的和持久层交流的DAO对象。

  还有一个关于Spring和bean要注意的是bean能以两种模式工作。这两种模式被定义为singleton和prototype。一个bean默认的模式是singleton,

意味着一个共享的bean的实例将被管理。这是用于无状态操作--像一个无状态会话bean将提供的那样。当bean由Spring提供时,prototype模式允

许创建bean的新实例。你应当只有在每一个用户都需要他们自己的bean的拷贝时才使用prototype模式。

提供一个服务定位器(Providing a Service Locator)

  既然我们已经把我们的服务和我们的DAO连起来了,我们需要把我们的服务暴露给其它层。通常是一个像使用Struts或Swing这样的用户接

口层里的代码来使用这个服务。一个简单的处理方法是使用一个服务定位器模式的类从一个Spring上下文中返回资源。这也可以靠引用bean ID

通过Spring来直接完成。

  这儿是一个在Struts Action中怎样配置一个服务定位器的例子:


public abstract class BaseAction extends Action {

  private IOrderService orderService;

  public void setServlet(ActionServlet

                                 actionServlet) {

    super.setServlet(actionServlet);

    ServletContext servletContext =

               actionServlet.getServletContext();

    WebApplicationContext wac =

      WebApplicationContextUtils.

         getRequiredWebApplicationContext(

                                 servletContext);

      this.orderService = (IOrderService)

                     wac.getBean("orderService");

  }

  protected IOrderService getOrderService() {

    return orderService;

  }

}

用户接口层配置 (UI Layer Configuration)

  示例应用的用户接口层使用Struts框架。这儿我们将讨论当为一个应用分层时和Struts相关的部分。让我们从在struts-config.xml文件里检查一

个Action配置开始。


<action path="/SaveNewOrder"

    type="com.meagle.action.SaveOrderAction"

    name="OrderForm"

    scope="request"

    validate="true"

    input="/NewOrder.jsp">

  <display-name>Save New Order</display-name>

  <exception key="error.order.save"

    path="/NewOrder.jsp"

    scope="request"

    type="com.meagle.exception.OrderException"/>

  <exception key="error.order.not.enough.money"

    path="/NewOrder.jsp"

    scope="request"

    type="com.

          meagle.

          exception.

          OrderMinimumAmountException"/>

  <forward name="success" path="/ViewOrder.jsp"/>

  <forward name="failure" path="/NewOrder.jsp"/>

</action>

  SaveNewOrder Action被用来持久化一个用户从用户接口层提交的订单。这是一个典型的Struts Action;然而,注意这个action的异常配置。

这些Exceptions为我们的业务服务对象也在Spring 配置文件(applicationContext-hibernate.xml)中配置了(在transactionAttributes属性里)。当这些异

常被从业务层掷出我们能在我们的用户接口里恰当的处理它们。第一个异常,OrderException,当在持久层里保存订单对象失败时将被这个

action使用。这将引起事务回滚和通过业务对象传递把异常传回给Struts层。OrderMinimumAmountException,在业务对象逻辑里的一个事务因为

提交的订单达不到最小订单数量而失败也将被处理。然后,事务将回滚和这个异常能被用户接口层恰当的处理。

  最后一个连接步骤是使我们的表现层和我们的业务层交互。这已经通过使用前面讨论的服务定位器来完成了。服务层充当一个到我们的业

务逻辑和持久层的接口。这儿是 Struts中的SaveNewOrder Action可能怎样使用一个服务定位器调用一个业务方法:


public ActionForward execute(

  ActionMapping mapping,

  ActionForm form,

  javax.servlet.http.HttpServletRequest request,

  javax.servlet.http.HttpServletResponse response)

  throws java.lang.Exception {

  OrderForm oForm = (OrderForm) form;

  // Use the form to build an Order object that

  // can be saved in the persistence layer.

  // See the full source code in the sample app.

  // Obtain the wired business service object

  // from the service locator configuration

  // in BaseAction.

  // Delegate the save to the service layer and

  // further upstream to save the Order object.

  getOrderService().saveNewOrder(order);

  oForm.setOrder(order);

  ActionMessages messages = new ActionMessages();

  messages.add(

      ActionMessages.GLOBAL_MESSAGE,

new ActionMessage(

      "message.order.saved.successfully"));

  saveMessages(request, messages);

  return mapping.findForward("success");

}

结论

  这篇文章按照技术和架构覆盖了许多话题。从中而取出的主要思想是怎样更好的给你的应用程序分层:用户接口层、持久逻辑层、和其它

任何你需要的应用层。这样可以解耦你的代码,允许添加新的代码组件,使你的应用在将来更易维护。这里覆盖的技术能很好的解决这类的问

题。不管怎样,使用这样的构架可以让你用其他技术代替现在的层。例如,你也许不想使用Hibernate持久化。因为你在你的DAO对象中编码到

接口,你能怎样使用其它的技术或框架,比如 iBATIS(http://www.ibatis.com/),作为一个替代是显而易见的。或者你可能用不同于

Struts的框架替代你的UI层。改变UI层的实现不会直接影响你的业务逻辑层或者你的持久层。替换你的持久层不会影响你的UI逻辑或业务服务

层。集成一个web应用其实也不是一件烦琐的工作,靠解耦你的各应用层和用适当的框架组成它,它能变得更容易处理。

Mark Eagle 是一位在MATRIX智囊团的高级软件工程师, Inc. in Atlanta, GA。

再译Wiring Your Web Application with Open Source Java(完整)

(由admin转自:http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html)

[注:这个翻译任务是从matrix的文档wiki那里看到的,我的英文水平只能勉强看懂,但是翻译它是一举三得:学技术、学英语、为网络学习作贡献,听说这篇文章在csdn上有人翻译了,可我就是没有找到,有人找到了在这里告诉一下,以免大家重复劳动。我采用从粗到精的翻译方法,先忽略细节,按我的理解粗翻一遍,然后再请大家指正,精确化细节问题。-admin ]

[原来totodo已经翻译了这篇文章|#7]译者注:今天再次在google上用文中的包关键字"com.meagle.bo""com.meagle.service.dao.hibernate"搜索了一下(上次用的关键字是"Wiring Your Web Application with Open Source Java""中文",结果没有找到,大家吸取我的教训哦:)),发现totodo在2004年就已经翻译了这篇文章([使用struts+spring+hibernate 组装web应用|http://www.matrix.org.cn/resource/article/1034.html])。总体翻译得还可以,但是也有不少没有忠于原文甚至错误的地方(我想,我的错误也许更多:)。现在我将结合两篇译文来修改、精确化中文译文,并希望在大家的指点下,得到一篇精确忠于原作者意图的译文。

  -admin 2006.1.3 14:02

Tags: java spring struts hibernate programming

Bookmark with del.icio.us

   

Wiring Your Web Application with Open Source Java

by Mark Eagle

04/07/2004

用Java开源技术构建你的web应用

Building non-trivial web applications with Java is no trivial task. There are many things to consider when structuring an architecture to house an application. From a high-level, developers are faced with decisions about how they are going to construct user interfaces, where the business logic will reside, and how to persist application data. Each of these three layers has their own questions to be answered. What technologies should be implemented across each layer? How can the application be designed so that it is loosely coupled and flexible to change? Does the architecture allow layers to be replaced without affecting other layers? How will the application handle container level services such as transactions?

  其实,就算用Java建造一个不是很烦琐的web应用,也不是件轻松的事情。 在构架的一开始就有很多事情要考虑。 从高处看,摆在开发者面前有很多问题:要考虑是怎样建立用户接口?在哪里处理业务逻辑? 怎样持久化的数据。 而这三层构架中,每一层都有他们要仔细考虑的。 各个层该使用什么技术? 怎样的设计能松散耦合还能灵活改变? 怎样替换某个层而不影响整体构架?应用程序如何做各种级别的业务处理(比如事务处理)?

   其实,就算用Java建造一个不是很烦琐的web应用程序,也不是件轻松的事情。当为一个应用程序建造一个构架时有许多事情需要考虑。从高层来说,开发者需要考虑:怎样建立用户接口(user interfaces)?在哪里处理业务逻辑?和怎样持久化应用数据。这三层每一层都有它们各自的问题需要回答。 各个层次应该使用什么技术?怎样才能把应用程序设计得松耦合和能灵活改变?构架允许层的替换不会影响到其它层吗?应用程序怎样处理容器级的服务(container level services),比如事务处理(transactions)?

There are definitely a number of questions that need to be addressed when creating an architecture for your web application. Fortunately, there have been developers that have run into these reoccurring problems and built frameworks to address these issues. A good framework relieves developers from attempting to reinvent the wheel for complex problems; it is extensible for internal customization; and it has a strong user community to support it. Frameworks generally address one problem well. However, your application will have several layers that might require their own framework. Just solving your UI problem does not mean that you should couple your business logic and persistence logic into a UI component. For example, you should not have business logic with JDBC code inside of a controller. This is not the functionality that a controller was intended to provide. A UI controller should be a lightweight component that delegates calls to other application layers for services outside the UI scope. Good frameworks naturally form guidelines where code should be placed. More importantly, frameworks alleviate developers from building code such as persistence from scratch and allow them to concentrate on the application logic that is important to a client.

  构架一个Web应用需要弄明白好多问题。 幸运的是,已经有不少开发者已经遇到过这类问题,并且建立了处理这类问题的框架。 一个好框架具备以下几点: 减轻开发者处理复杂的问题的负担(“不重复发明轮子”); 内部有良好的扩展; 并且有一个支持它的强大的用户团体。 好的构架一般有针对性的处理某一类问题,并且能将它做好(Do One Thing well)。 然而,你的程序中有几个层可能需要使用特定的框架,已经完成的UI(用户接口) 并不代表你也可以把你的业务逻辑和持久逻辑偶合到你的UI部分。 举个例子, 你不该在一个Controller(控制器)里面写JDBC代码作为你的业务逻辑, 这不是控制器应该提供的。 一个UI 控制器应该委派给其它给在UI范围之外的轻量级组件。 好的框架应该能指导代码如何分布。 更重要的是,框架能把开发者从编码中解放出来,使他们能专心于应用程序的逻辑(这对客户来说很重要)。

  当为你的web应用程序创建一个构架时,需要涉及到相当多的问题。幸运的是,已经有不少开发者已经遇到过这类重复发生的问题,并且建立了处理这类问题的框架。一个好框架具备以下几点: 减轻开发者处理复杂的问题的负担(“不重复发明轮子”);内部定义为可扩展的;有一个强大的用户群支持。框架通常能够很好的解决一方面的问题。然而,你的应用程序有几个层可能都需要它们各自的框架。就如解决你的用户接口(UI)问题时你就不应该把事务逻辑和持久化逻辑掺杂进来。例如,你不应该在控制器(controller)里面写jdbc代码,使它包含有业务逻辑,这不是控制器应该提供的功能。它应该是轻量级的,代理来自用户接口(UI)外的调用请求给其它服务于这些请求的应用层。好的框架自然的形成代码如何分布的指导。更重要的是,框架减轻开发者从头开始写像持久层这样的代码的痛苦,使他们专注于对客户来说很重要的应用逻辑。

This article will discuss how to combine several well-known frameworks to achieve loose coupling, how to structure your architecture, and how to enforce a consistent design across all application layers. The challenge is combining frameworks so that each layer is exposed to each other in a loosely coupled manner, regardless of the underlying technologies. This article will discuss one strategy for combining frameworks using three popular open source frameworks. For the presentation layer we will use Struts; for our business layer we will use Spring; and for our persistence layer we will use Hibernate. You should be able to substitute any one of these frameworks in your application and get the same effect. Figure 1 shows what this looks like from a high level when the frameworks are combined.

  这篇文章将讨论怎样结合几种著名的框架来使得你的应用程序做到松弛耦合。 如何建立你的架构,并且怎样让你的各个应用层保持一致。?如何整合框架以便让每个层在以一种松散偶合的方式彼此作用而不用管低层的技术细节?这对我们来说真是一种挑战。 这里讨论一个整合框架的策略( 使用3 种受欢迎的开源框架) :表示层我们用Struts; 业务层我们用Spring;而持久层则用Hibernate。 你也可以用其他FrameWork替换只要能得到同样的效果。 见图1 (框架组合示意图)

  这篇文章将讨论怎样组合几个著名的框架去做到松耦合的目的,怎样建立你的构架,怎样让你的各个应用层保持一致。富于挑战的是:组合这些框架使得每一层都以一种松耦合的方式彼此沟通,而与底层的技术无关。这篇文章将使用3种流行的开源框架来讨论组合框架的策略。表现层我们将使用Struts;业务层我们将使用Spring;持久层使用Hibrenate.你也可以在你的应用程序中替换这些框架中的任何一种而得到同样的效果。图1展示了当这些框架组合在一起时从高层看是什么样子。

Figure 1. Overview of framework architecture with Struts, Spring, and Hibernate.

图1用Struts, Spring, 和 Hibernate框架构建的概览

Application Layering

Most non-trivial web applications can be divided into at least four layers of responsibility. These layers are the presentation, persistence, business, and domain model layers. Each layer has a distinct responsibility in the application and should not mix functionality with other layers. Each application layer should be isolated from other layers but allow an interface for communication between them. Let's start by inspecting each of these layers and discuss what these layers should provide and what they should not provide.

应用程序的分层

大部分的Web应用在职责上至少能被分成4层。 这四层是:presentation(描述),persistence(持久),business(业务)和domain model(域模块)。每个层在处理程序上都应该有一项明确的责任, 而不应该在功能上与其它层混合,并且每个层要与其它层分开的,但要给他们之间放一个通信接口。 我们就从介绍各个层开始,讨论一下这些层应该提供什么,不应该提供什么。

应用程序的分层

大多数不复杂的web应用都能被分成至少4个各负其责的层次。这些层次是:表现层(presentation)、持久层(persistence)、业务层(business)、领域模型层(domain model)。每层在应用程序中都有明确的责任,不应该和其它层混淆功能。每一应用层应该彼此独立但要给他们之间放一个通讯接口。让我们从审视各个层开始,讨论这些层应该提供什么和不应该提供什么。

The Presentation Layer

表示层(The Presentation Layer)

表现层 (The Presentation Layer)

  

At one end of a typical web application is the presentation layer. Many Java developers understand what Struts provides. However, too often, coupled code such as business logic is placed into an org.apache.struts.Action. So, let's agree on what a framework like Struts should provide. Here is what Struts is responsible for:

  一般来讲,一个典型的Web应用的的末端应该是表示层。 很多Java发者也理解Struts所提供的。 象业务逻辑之类的被打包到org.apache.struts.Action., 因此,我们很赞成使用Struts这样的框架。

  在一个典型的web应用的一端是表现层。很多Java开发者也理解Struts所提供的。然而,太常见的是,他们把像业务逻辑之类的耦合的代码放进了一个org.apache.struts.Action。所以,让我们在像Struts这样一个框架应该提供什么上取得一致意见。这儿是Struts负责的:

Managing requests and responses for a user.

Providing a controller to delegate calls to business logic and other upstream processes.

Handling exceptions from other tiers that throw exceptions to a Struts Action.

Assembling a model that can be presented in a view.

Performing UI validation.

下面是Struts所负责的:

* 管理用户的请求,做出相应的响应。

* 提供一个Controller ,委派调用业务逻辑和其它上层处理。

* 处理异常,抛给Struts Action

* 为显示提供一个模型

* UI验证。

为用户管理请求和响应;

提供一个控制器(controller)代理调用业务逻辑和其它上层处理;

处理从其它层掷出给一个Struts Action的异常;

为显示提供一个模型;

执行用户接口(UI)验证。

Here are some items that are often coded using Struts but should not be associated with the presentation layer:

Direct communication with the database, such as JDBC calls.

Business logic and validation related to your application.

Transaction management.

Introducing this type of code in the presentation layer leads to type coupling and cumbersome maintenance.

以下条款,不该在Struts显示层的编码中经常出现。 它们与显示层无关的。

* 直接的与数据库通信,例如JDBC调用。

* 与你应用程序相关联的业务逻辑以及校验。

* 事物管理。

在表示层引入这些代码,则会带来高偶合和麻烦的维护。

这儿是一些经常用Struts编写的但是却不应该和Struts表现层相伴的项目:

直接和数据库通讯,比如JDBC调用;

业务逻辑和与你的应用程序相关的验证;

事务管理;

在表现层中引入这种代码将导致典型耦合(type coupling)和讨厌的维护。

The Persistence Layer

At the other end of a typical web application is the persistence layer. This is usually where things get out of control fast. Developers underestimate the challenges in building their own persistence frameworks. A custom, in-house persistence layer not only requires a great amount of development time, but also often lacks functionality and becomes unmanageable. There are several open source object-to-relational mapping (ORM) frameworks that solve much of this problem. In particular, the Hibernate framework allows object-to-relational persistence and query service for Java. Hibernate has a medium learning curve for Java developers who are already familiar with SQL and the JDBC API. Hibernate persistent objects are based on plain-old Java objects and Java collections. Furthermore, using Hibernate does not interfere with your IDE. The following list contains the type of code that you would write inside a persistence framework:

持久层(The Persistence Layer)

典型的Web应用的另一个末端是持久层。这里通常是程序最容易失控的地方。开发者总是低估构建他们自己的持久框架的挑战性。系统内部的持续层不但需要大量调试时间,而且还经常缺少功能使之变得难以控制,这是持久层的通病。 还好有几个ORM开源框架很好的解决了这类问题。尤其是Hibernate。 Hibernate为java提供了OR持久化机制和查询服务, 它还给已经熟悉SQL和JDBC API 的Java开发者一个学习桥梁,他们学习起来很方便。 Hibernate的持久对象是基于POJO和Java collections。此外,使用Hibernate并不妨碍你正在使用的IDE。

请看下面的条目,你在持久层编码中需要了解的。

持久层 (The Persistence Layer )

在典型web应用的另一端是持久层。这通常是使事情迅速失控的地方。开发者低估了构建他们自己的持久层框架的挑战性。一般来说,机构内部自己写的持久层不仅需要大量的开发时间,而且还经常缺少功能和变得难以控制。有几个开源的“对象-关系映射”(ORM)框架非常解决问题。尤其是,Hibernate框架为java提供了"对象-关系持久化"(object-to-relational persistence)机制和查询服务。Hibernate对那些已经熟悉了SQL和JDBC API的Java开发者有一个适中的学习曲线。Hibernate持久对象是基于简单旧式Java对象(POJO)和Java集合(Java collections)。此外,使用Hibernate并不妨碍你正在使用的IDE。下面的列表包含了你该写在一个持久层框架里的代码类型:

[注:由admin翻译上述部分2005年12月28日22:40分;由***在***修改了上述部分;由***在***修改了上述部分...请自行填写,以便联系]

Querying relational information into objects. Hibernate does this through an OO query language called HQL, or by using an expressive criteria API. HQL is very similar to SQL except you use objects instead of tables and fields instead of columns. There are some new specific HQL language elements to learn; however, they are easy to understand and well documented. HQL is a natural language to use for querying objects that require a small learning curve.

* 查询对象的相关信息的语句。 Hibernate通过一个OO查询语言(HQL)或者正则表达的API来完成查询。 HQL非常类似于SQL-- 只是把SQL里的table和columns用Object和它的fields代替。 你需要学习一些新的HQL语言; 不管怎样,他们容易理解而文档也做的很好。 HQL是一种对象查询的自然语言,花很小的代价就能学习它。

查询相关的信息成为对象。Hibernate通过一种叫作HQL的面向对象(OO)的查询语言或者使用条件表达式API(expressive criteria API)来做这个事情。 HQL非常类似于SQL-- 只是把SQL里的table和columns用Object和它的fields代替。有一些新的专用的HQL语言成分要学;不过,它们容易理解而且文档做得好。HQL是一种使用来查询对象的自然语言,花很小的代价就能学习它。

Saving, updating, and deleting information stored in a database.

* 如何存储,更新,删除数据库记录。

保存、更新、删除储存在数据库中的信息。

Advanced object-to-relational mapping frameworks like Hibernate have support for most major SQL databases, and they support parent/child relationships, transactions, inheritance, and polymorphism.

* 象Hibernate这类的高级ORM框架支持大部分主流数据库,并且他们支持 Parent/child关系,事物处理,继承和多态。

 

像Hibernate这样的高级“对象-关系”映射(object-to-relational mapping)框架提供对大多数主流SQL数据库的支持,它们支持“父/子”(parent/child)关系、事务处理、继承和多态。

Here are some items that should be avoided in the persistence layer:

这儿是一些应该在持久层里被避免的项目:

Business logic should be in a higher layer of your application. Only data access operations should be permitted.

业务逻辑应该在你的应用的一个高一些的层次里。持久层里仅仅允许数据存取操作。

You should not have persistence logic coupled with your presentation logic. Avoid logic in presentation components such as JSPs or servlet-based classes that communicate with data access directly. By isolating persistence logic into its own layer, the application becomes flexible to change without affecting code in other layers. For example, Hibernate could be replaced with another persistence framework or API without modification to the code in any other layer.

你不应该把持久层逻辑(persistence logic)和你的表现层逻辑(presentation logic)搅在一起。避免像JSPs或基于servlet的类这些表现层组件里的逻辑和数据存取直接通讯。通过把持久层逻辑隔离进它自己的层,应用程序变得易于修改而不会影响在其它层的代码。例如:Hebernate能够被其它持久层框架或者API代替而不会修改在其它任何层的代码。

The Business Layer

The middle component of a typical web application is the business or service layer. This service layer is often the most ignored layer from a coding perspective. It is not uncommon to find this type of code scattered around in the UI layer or in the persistence layer. This is not the correct place because it leads to tightly coupled applications and code that can be hard to maintain over time. Fortunately, several frameworks exist that address these issues. Two of the most popular frameworks in this space are Spring and PicoContainer. These are referred to as microcontainers that have a very small footprint and determine how you wire your objects together. Both of these frameworks work on a simple concept of dependency injection (also known as inversion of control). This article will focus on Spring's use of setter injection through bean properties for named configuration parameters. Spring also allows a sophisticated form of constructor injection as an alternative to setter injection as well. The objects are wired together by a simple XML file that contains references to objects such as the transaction management handler, object factories, service objects that contain business logic, and data access objects (DAO).

业务层(The Business Layer)

一个典型Web应用的中间部分是业务层或者服务层。 从编码的视角来看,这层是最容易被忽视的一层。 而我们却往往在UI层或持久层周围看到这些业务处理的代码,这其实是不正确的,因为它导致了程序代码的紧密偶合,这样一来,随着时间推移这些代码很难维护。幸好,针对这一问题有好几种Frameworks存在。 最受欢迎的两个框架是Spring和PicoContainer。 这些为也被称为microcontainers,他们能让你很好的把对象搭配起来。 这两个框架都着手于‘依赖注射’(dependency injection)(还有我们知道的‘控制反转’Inversion of Control=IoC)这样的简单概念。 这篇文章将关注于Spring的注射(译注:通过一个给定参数的Setter方法来构造Bean,有所不同于Factory), Spring还提供了Setter Injection(type2),Constructor Injection(type3)等方式供我们选择。 Spring把程序中所涉及到包含业务逻辑和Dao的Objects——例如transaction management handler(事物管理控制)、Object Factoris(对象工厂)、service objects(服务组件)——都通过XML来配置联系起来。

[注:糟糕,还没有接触过Spring和PicoContainer,这下面的翻译肯定是漏洞百出,还望大虾不吝赐教:)]

业务层

在一个典型的web应用程序的中间的组件是业务层或服务层。从编码的视角来看,这个服务层是最容易被忽视的一层。不难在用户接口(UI)层或者持久层里找到散布在其中的这种类型的代码。这不是正确的地方,因为这导致了应用程序的紧耦合,这样一来,随着时间推移代码将很难维护。幸好,针对这一问题有好几种Frameworks存在。在这个领域两个最流行的框架是Spring和PicoContainer,它们叫作微容器(microcontainers),你可以不费力不费神的把你的对象连在一起。所有这些框架都工作在一个简单的叫作“依赖注入”(dependency injection)(也通称“控制反转”(inversion of control))的概念上。这篇文章将着眼于Spring的为指定的配置参数通过bean属性的setter注入(setter injection)的使用。Spring也提供了一个构建器注入(constructor injection)的复杂形式作为setter注入的一个替代。对象们被一个简单的XML文件连在一起,这个XML文件含有到像事务管理器(transaction management handler)、对象工厂(object factories)、包含业务逻辑的服务对象(service objects)、和数据存取对象(DAO)这些对象的引用(references)。

The way Spring uses these concepts will be made clearer with examples later in this article. The business layer should be responsible for the following:

Handling application business logic and business validation

Managing transactions

Allowing interfaces for interaction with other layers

Managing dependencies between business level objects

Adding flexibility between the presentation and the persistence layer so they do not directly communicate with each other

Exposing a context to the business layer from the presentation layer to obtain business services

Managing implementations from the business logic to the persistence layer

后面我们会举个例子来揭示一下Spring 是怎样运用这些概念。

业务层所负责的如下:

* 处理应用程序的 业务逻辑和业务校验

* 管理事物

* 允许与其它层相互作用的接口

* 管理业务层级别的对象的依赖。

* 在显示层和持久层之间增加了一个灵活的机制,使得他们不直接的联系在一起。

* 通过揭示 从显示层到业务层之间的Context来得到business services。

* 管理程序的执行(从业务层到持久层)。

这篇文章的后面将用例子来把Spring使用这些概念的方法说得更清楚一些。业务层应该负责下面这些事情:

处理应用程序的业务逻辑和业务验证;

管理事务;

预留和其它层交互的接口;

管理业务层对象之间的依赖;

增加在表现层和持久层之间的灵活性,使它们互不直接通讯;

从表现层中提供一个上下文(context)给业务层获得业务服务(business services );

管理从业务逻辑到持久层的实现。

The Domain Model Layer

Finally, since we are addressing non-trivial, web-based applications we need a set of objects that can move between the different layers. The domain object layer consists of objects that represent real-world business objects such as an Order, OrderLineItem, Product, and so on. This layer allows developers to stop building and maintaining unnecessary data transfer objects, or DTOs, to match their domain objects. For example, Hibernate allows you to read database information into an object graph of domain objects, so that you can present it to your UI layer in a disconnected manner. Those objects can be updated and sent back across to the persistence layer and updated within the database. Furthermore, you do not have to transform objects into DTOs, which can get lost in translation as they are moved between different application layers.This model allows Java developers to work with objects naturally in an OO fashion without additional coding.

域模块层(The Domain Model Layer )

既然我们致力于的是一个不是很复杂的Web的应用, 我们需要一个对象集合,让它在不同层之间移动的。 域模块层由实际需求中的业务对象组成 比如, OrderLineItem , Product等等。 开发者在这层 不用管那些DTOs,仅关注domain object即可。 例如,Hibernate允许你将数据库中的信息存放入对象(domain objects),这样你可以在连接断开的情况下把这些数据显示到UI层。 而那些对象也可以返回给持续层,从而在数据库里更新。 而且,你不必把对象转化成DTOs(这可能似的它在不同层之间的在传输过程中丢失),这个模型使得Java开发者能很自然运用OO,而不需要附加的编码。

领域模型层 (The Domain Model Layer )

最后,因为我们讨论的是一个不是很复杂的、基于web的应用程序,我们需要一组能在不同的层之间移动的对象。领域对象层由那些代表现实世界中的业务对象的对象们组成,比如:一份订单(Order)、订单项(OrderLineItem)、产品(Product)等等。这个层让开发者停止建立和维护不必要的数据传输对象(或者叫作DTOs),来匹配他们的领域对象。例如,Hibernate允许你把数据库信息读进领域对象(domain objects)的一个对象图,这样你可以在连接断开的情况下把这些数据显示到UI层。那些对象也能被更新和送回到持久层并在数据库里更新。而且,你不必把对象转化成DTOs,因为DTOs在不同的应用层间移动,可能在转换中丢失。这个模型使得Java开发者自然地以一种面向对象的风格和对象打交道,没有附加的编码。

[注:由admin翻译上述部分2005年12月30日20:57分;由***在***修改了上述部分;由***在***修改了上述部分...请自行填写,以便联系] 

相关资源

转自:http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html 

 日记标题 (转帖)Wiring Your Web Application with Open Source Java(2)  作者: guest  创建时间: 2005-12-28 20:58:18  最近更新: 2005-12-28 20:58:18  编辑 我要评论  

内容

(由admin转自:http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=2)

Wiring Together a Simple Example

Now that we understand the components from a high level, let's put this into practice. Again, for this example, we will combine the Struts, Spring, and Hibernate frameworks. Each one of these frameworks has too much detail to cover in one article. Instead of going into many details about each framework, this article will show how to wire them together with simple example code. The sample application will demonstrate how a request is serviced across each layer. A user of this sample application can save a new order to the database and view an existing order in the database. Further enhancements might allow the user to update or delete an existing order.

一个简单例子

既然我们已经从全局上理解这些组件。 现在就让我们开始实践吧。 我们还是用 Struts,Spring 和Hibernate。这三个框架已经被描述够多了,这里就不重复介绍了。 这篇文章举例指导你如何使用这三个框架整合开发, 并向你揭示 一个请求是如何贯穿于各个层的。(从用户的加入一个Order到数据库,显示;进而更新、删除)。

结合一个简单的例子

  既然我们已经从一个高的层次上理解了这些组件, 现在就让我们开始实践吧。在这个例子中,我们还是将合并Struts、Spring、Hibernate框架。每一个这些框架在一篇文章中都有太多的细节覆盖到。这篇文章将用一个简单的例子代码展示怎样把它们结合在一起,而不是进入每个框架的许多细节。示例应用程序将示范一个请求怎样跨越每一层被服务的。这个示例应用程序的一个用户能保存一个订单到数据库中和查看一个在数据库中存在的订单。进一步的增强可以使用户更新或删除一个存在的订单。  

 

You can download the source code of the application.

从这里可以下载到程序程序原代码(download)

你可以下载这个应用的源码。

First, we will create our domain objects since they will interoperate with each layer. These objects will allow us to define what should be persisted, what business logic should be provided, and what type of presentation interface should be designed. Next, we will configure the persistence layer and define object-to-relational mappings with Hibernate for our domain objects. Then we will define and configure our business objects. After we have these components we can discuss wiring these layers using Spring. Finally, we will provide a presentation layer that knows how to communicate with the business service layer and knows how to handle exceptions that arise from other layers.

  既然每个层是互相作用的,我们就先来创建domain objects。首先,我们要在这些Object中要确定那些是需要持久化的,哪些是提供给business logic,那些是显示接口的设计。 下一步,我们将配置我们的持久层并且定义好Hibernate的OR mappings。然后定义好Business Objects。有了这些组成部分之后,我们将 使用Spring把这些连接起来。 最后,我们提供给Spring一个持久层,从这个持久层里我们可以知道它是如何与业务逻辑层(business service layer)通信的,以及它是怎样处理其他层抛出的异常的。。

  因为领域对象(domain objects)将和每一层交互,我们将首先创建它们。这些对象将使我们定义什么应该被持久化,什么业务逻辑应该被提供,和哪种表现接口应该被设计。然后,我们将配置持久层和用Hibernate为我们的领域对象(domain objects)定义“对象-关系”映射(object-to-relational mappings)。然后,我们将定义和配置我们的业务对象(business objects)。在有了这些组件后,我们就能讨论用Spring把这些层连在一起。最后,我们将提供一个表现层(presentation layer),它知道怎样和业务服务层(business service layer)交流和知道怎样处理从其它层产生的异常(exceptions)。

Domain Object Layer

Since these objects will interoperate across all layers this might be a good place to start coding. This simple domain model will contain an object that represents an order and an object that represents a line item for an order. The order object will have a one-to-many relationship to a collection of line item objects. The example code has two simple objects in the domain layer:

com.meagle.bo.Order.java: contains the header-level information for an order.

com.meagle.bo.OrderLineItem.java: contains the detail-level information for an order.

Consider choosing package names for your objects that reflect how your application is layered. For example, the domain objects in the sample application can be located in the com.meagle.bo package. More specialized domain objects would be located in subpackages under the com.meagle.bo package. The business logic begins in the com.meagle.service package and DAO objects are located in the com.meagle.service.dao.hibernate package. The presentation classes for forms and actions reside in com.meagle.action and com.meagle.forms, respectively. Accurate package naming provides a clear separation for the functionality that your classes provide, allows for easier maintenance when troubleshooting, and provides consistency when adding new classes or packages to the application.

域对象层(Domain Object Layer)

这层是编码的着手点,我们的编码就从这层开始。 例子中Order 与OrderItem 是一个One—To—Many的关系。 下面就是Domain Object Layer的两个对象:

· com.meagle.bo.Order.java: 包含了一个Order的概要信息

· com.meagle.bo.OrderLineItem.java: 包含了Order的详细信息

好好考虑怎你的package命名,这反应出了你是怎样分层的。 例如 domain objects在程序中可能打包在com.meagle.bo内。 更详细一点将打包在com. meagle.bo的子目录下面。business logic应该从com.meagle.serice开始打包,而DAO 对象应该位于com.meagle.service.dao.hibernate。反应Forms和Actions的 持久对象(presentation classes) 应该分别放在 com.meagle.action和com.meagle.forms包。 准确的给包命名使得你的classes很好分割并且易于维护,并且在你添加新的classes时,能使得程序结构上保持上下一致。

领域对象层

因为这些对象将和所有层交互,这也许是一个开始编码的好地方。这个简单的领域模型将包括一个代表一份订单(order)的对象和一个代表一个订单项(line item for an order)的对象。订单(order)对象将和一组订单项(a collection of line item)对象有一对多(one-to-many)的关系。例子代码在领域层有两个简单的对象:

com.meagle.bo.Order.java: 包括一份订单(oder)的概要信息;

com.meagle.bo.OrderLineItem.java: 包括一份订单(order)的详细信息;

考虑一下为你的对象选择包名,它将反映你的应用程序是怎样分层的。例如:简单应用的领域对象(domain objects)可以放进com.meagle.bo包[译者注:bo-business object?]。更多专门的领域对象将放入在com.meagle.bo下面的子包里。业务逻辑在com.meagle.service包里开始打包,DAO对象放进com.meagle.service.dao.hibernate包。对于forms和actions的表现类(presentation classes)分别放入com.meagle.action 和 com.meagle.forms包。准确的包命名为你的类提供的功能提供一个清楚的区分,使当故障维护时更易于维护,和当给应用程序增加新的类或包时提供一致性。

Persistence Layer Configuration

There are several steps involved in setting up the persistence layer with Hibernate. The first step is to configure our domain business objects to be persisted. Since Hibernate works with POJOs we will use our domain objects for persistence. Therefore the Order and OrderLineItem objects will need to provide getter and setter methods for all fields that they contain. The Order object would contain setter and getter methods such as ID, UserName, Total, and OrderLineItems in a standard JavaBean format. The OrderLineItem would similarly follow the JavaBean format for its fields.

Hibernate maps domain objects-to-relational databases in XML files. For our Order and OrderLineItem objects there will be two mapping files to express this. There are tools such as XDoclet to assist with this mapping. Hibernate will map the domain objects to these files:

Order.hbm.xml

OrderLineItem.hbm.xml

You will find these generated files in the WebContent/WEB-INF/classes/com/meagle/bo directory. The Hibernate SessionFactory is configured to know which database it is communicating with, the DataSource or connection pool to use, and what persistent objects are available for persistence. Session objects provided by the SessionFactory are the interface used to translate between Java objects and persistence functions such as selecting, saving, updating, and deleting objects. We will discuss configuring the SessionFactory that Hibernate requires to handle Session objects in a later section.

持久层的配置(Persistence Layer Configuration)

建立Hibernate的持久层 需要好几个步骤。 第一步让我们把BO持久化。 既然Hibernate是通过POJO工作的, 因此Order和 OrderLineItem对象需要给所有的fileds 加上getter,setter方法。 Hibernate通过XML文件来映射(OR)对象,以下两个xml文件分别映射了Order 和OrderItem对象。(这里有个叫XDoclet工具可以自动生成你的XML影射文件)

- Order.hbm.xml

- OrderLineItem.hbm.xml

- Order.hbm.xml

- OrderLineItem.hbm.xml

你可以在WebContent/WEB-INF/classes/com/meagle/bo目录下找到这些xml文件。Hibernate的 [urlhttp://www.hibernate.org/hib_docs/api/net/sf/hibernate/SessionFactory.html]SessionFactory [/url]是用来告诉程序 应该与哪个数据库通信,该使用哪个连接池或使用了DataSource, 应该加载哪些持久对象。而Session接口是用来完成Selecting,Saving,Delete和Updating这些操作。 后面的我们将讲述SessionFactory和Session是怎样设置的。

持久层配置

用Hibernate设置持久层涉及到几个步骤。第一步是进行配置持久化我们的领域业务对象(domain business objects )。因为我们用于领域对象(domain objects )持久化的Hibernate和POJOs一起工作( 此句原文:Since Hibernate works with POJOs we will use our domain objects for persistence.),因此,订单和订单项对象包括的所有的字段的都需要提供getter和setter方法。订单对象将包括像ID、用户名、合计、和订单项这样一些字段的标准的JavaBean格式的setter和getter方法。订单项对象将同样的用JavaBean的格式为它的字段设置setter和getter方法。

  Hibernate在XML文件里映射领域对象到关系数据库。订单和订单项对象将有两个映射文件来表达这种映射。有像XDoclet这样的工具来帮助这种映射。Hibernate将映射领域对象到这些文件:

Order.hbm.xml

OrderLineItem.hbm.xml

你可以在WebContent/WEB-INF/classes/com/meagle/bo目录里找到这些生成的文件。配置Hibernate SessionFactory使它知道是在和哪个数据库通信,使用哪个数据源或连接池,加载哪些持久对象。SessionFactory提供的Session对象是Java对象和像选取、保存、更新、删除对象这样一些持久化功能间的翻译接口。我们将在后面的部分讨论Hibernate操作Session对象需要的SessionFactory配置。                                                                                                                                                                                                                                                                                                                                  Business Layer Configuration

Now that we have our domain objects we need to have business service objects that perform application logic, make calls to the persistence layer, take requests from the UI layer, deal with transactions, and handle exceptions. To wire all of this together and make this easy to manage we will use the bean management aspect of the Spring framework. Spring uses inversion of control (IoC), or setter dependency injection, to wire up objects that are referenced in an external XML file. Inversion of control is a simple concept that allows objects to accept other objects that are created at a higher level. This way your object is free from having to create objects and reduces object coupling.

Here is an example of an object creating its dependencies without IoC, which leads to tight object coupling:

Figure 2. Objects arranged without IoC. Object A creates objects B and C.

And here is an example with IoC that allows objects to be created at higher levels and passed into objects so that they can use the implementations directly:

Figure 3. Objects arranged with IoC. Object A contains setter methods that accept interfaces to objects B and C. This could have also been achieved with constructors in object A that accepts objects B and C.

业务层的配置(Business Layer Configuration)

既然我们已经有了domain objects,接下来我们就要business service objects了,用他们来执行程序的logic,调用持久层,得到UI层的requests,处理transactions,并且控制exceptions。 为了将这些连接起来并且易于管理,我们将使用面向方面的 SpringFramework。 Spring 提供了 控制倒置(inversion of control 0==IoC)和注射依赖设置(setter dependency injection)这些方式(可供选择),用XML文件将对象连接起来。 IoC是一个简单概念(它允许一个对象在上层接受其他对象的创建),用IoC这种方式让你的对象从创建中释放了出来,降低了偶合度。

这里是一个没有使用IoC的对象创建的例子,它有很高偶合度。

图 2.没有使用 IoC. A 创建了 B 和 C

而这里是一个使用IoC的例子,这种方式允许对象在高层可以创建并进入另外一个对象,所以这样可以直接被执行。

 图 3. 对象使用了 IoC。 A 包含了接受B,C的 setter方法 , 这同样达到了 由A创建B,C的目的。

业务层配置(Business Layer Configuration )

  既然我们已经有了领域对象(domain objects),我们需要有业务服务对象来执行应用逻辑、执行向持久层的调用、获得从用户接口层(UI layer)的请求、处理事务、处理异常。为了将所有这些连接起来并且易于管理,我们将使用Spring框架的bean管理方面(bean management aspect)。Spring使用“控制反转”(IoC),或者“setter依赖注入”来把这些对象连好,这些对象在一个外部的XML文件中被引用。“控制反转”是一个简单的概念,它允许对象接受其它的在一个高一些的层次被创建的对象。使用这种方法,你的对象从必须创建其它对象中解放出来并降低对象耦合。

  这儿是个不使用IoC的对象创建它的从属对象( object creating its dependencies without IoC)的例子,这导致紧的对象耦合:

  图2:没有使用IoC的对象组织。对象A创建对象B和C。

  这儿是一个使用IoC的例子,它允许对象在一个高一些层次被创建和传进另外的对象,所以另外的对象能直接使用现成的对象·[译者注:另外的对象不必再亲自创建这些要使用的对象](allows objects to be created at higher levels and passed into objects so that they can use the implementations directly):

  图3:对象使用IoC组织。对象A包含setter方法,它们接受到对象B和C的接口。这也可以用对象A里的接受对象B和C的构建器完成。

Building Our Business Service Objects

The setters we will use in our business objects accept interfaces that allow loosely defined implementations of the objects that will be set, or injected. In our case we will allow our business service object to accept a DAO to handle the persistence of our domain objects. While the examples in this article use Hibernate, we can easily switch implementations to a different persistence framework and inform Spring of the new implementation DAO object to use. You can see how programming to interfaces and using the dependency injection pattern loosely couples your business logic from your persistence mechanism.

Here is the interface for the business service object that is stubbed for a DAO object dependency:

建立我们的业务服务对象(Building Our Business Service Objects)

Business Object中的Setter方法接受的是接口,这样我们可以很松散的定义对象实现,然后注入。 在我们的案例中,我们将用一个business service object接收一个DAO,用它来控制domain objects的持久化。 由于在这个例子中使用了Hibernate,我们可以很方便的用其他持久框架实现 同时通知Spring 有新的DAO可以使用了。

在面向接口的编程中,你会明白 “注射依赖”模式是怎样松散耦合你的业务逻辑和持久机制的:)。

下面是一个接口business service object,DAO代码片段:

 代码:

建立我们的业务服务对象(Building Our Business Service Objects)

  我们将在我们的业务对象中使用的setter方法接受的是接口,这些接口允许对象的松散定义的实现,这些对象将被设置或者注入。在我们这个例子里我们将使我们的业务服务对象接受一个DAO去控制我们的领域对象的持久化。当我们在这篇文章的例子中使用Hibernate( While the examples in this article use Hibernate),我们可以容易的转换到一个不同的持久框架的实现,通知Spring使用新的实现的DAO对象。你能明白编程到接口和使用“依赖注入”模式是怎样宽松耦合你的业务逻辑和你的持久化机制的。

  这儿是业务服务对象的接口,它是一个DAO对象依赖的桩。(Here is the interface for the business service object that is stubbed for a DAO object dependency: )

public interface IOrderService {

  public abstract Order saveNewOrder(Order order)

    throws OrderException,

           OrderMinimumAmountException;

  public abstract List findOrderByUser(

                                     String user)

                           throws OrderException;

  public abstract Order findOrderById(int id)

                           throws OrderException;

  public abstract void setOrderDAO(

                             IOrderDAO orderDAO);

}

Notice that the code above has a setter for a DAO object. There is not a getOrderDAO method because it is not necessary since there is often no need to access the wired OrderDAO object from the outside. The DAO object will be used to communicate with our persistence layer. We will wire the business service object and the DAO object together with Spring. Because we are coding to interfaces, we do not tightly couple the implementation.

  注意到这段代码里有一个 setOrderDao(),它就是一个DAO Object设置方法(注射器)。 但这里并没有一个getOrderDao的方法,这不必要,因为你并不会在外部访问这个orderDao。这个DAO Objecte将被调用,和我们的persistence layer 通信。我们将用Spring把DAO Object 和 business service object搭配起来的。因为我们是面向接口编程的,所以并不需要将实现类紧密的耦合在一起。

  注意上面的代码有一个为DAO对象准备的setter方法。这儿没有一个getOrderDAO方法因为它不是必要的,因为不太有从外面访问连着的OrderDAO对象的需要。DAO对象将被用来和我们的持久层沟通。我们将用Spring把业务服务对象和DAO对象连在一起。因为我们编码到接口,我们不会紧耦合实现。

The next step is to code our DAO implementation object. Since Spring has built-in support for Hibernate this example DAO will extend the HibernateDaoSupport class, which allows us to easily get a reference to a HibernateTemplate, which is a helper class that simplifies coding with a Hibernate Session and handles HibernateExceptions. Here is the interface for the DAO:

接下去我们开始我们的DAO的实现类进行编码。 既然Spring已经有对Hibernate的支持,那这个例子就直接继承HibernateDaoSupport类了,这个类很有用,我们可以参考HibernateTemplate(它主要是针对HibernateDaoSupport的一个用法,译注:具体可以查看Srping 的API)。 下面是这个DAO接口代码: 代码:

下一步是写我们的DAO实现对象。因为Spring有内建的对Hibernate的支持,这个例子DAO将继承HibernateDaoSupport类,这使得我们容易取得一个到HibernateTemplate类的引用,HibernateTemplate是一个帮助类,它能简化Hibernate Session的编码和处理HibernateExceptions。这儿是DAO的接口:

public interface IOrderDAO {

  public abstract Order findOrderById(

                                    final int id);

  public abstract List findOrdersPlaceByUser(

                           final String placedBy);

  public abstract Order saveOrder(

                               final Order order);

}

We still have a couple more objects to wire together for our business layer. This includes the HibernateSessionFactory and a TransactionManager object. This is done directly in the Spring configuration file. Spring provides a HibernateTransactionManager, which will bind a Hibernate Session from the factory to a thread to support transactions (see ThreadLocal for more information). Here is the Spring configuration of the HibernateSessionFactory and the HibernateTransactionManager:

  我们仍然要给我们持久层组装很多关联的对象,这里包含了HibernateSessionFactory 和TransactionManager。 Spring 提供了一个 HibernateTransactionManager,他用线程捆绑了一个Hibernate Session,用它来支持transactions(请查看ThreadLocal) 。 下面是HibernateSessionFactory 和 HibernateTransactionManager:的配置:  代码:

  我们还有两个对象要和我们的业务层连在一起。这包括HibernateSessionFactory和一个TransactionManager对象。这在Spring配置文件里直接完成。Spring提供一个HibernateTransactionManager,它将从工厂绑定一个Hibernate Session到一个线程来支持事务(见ThreadLocal获取更多的信息)。这儿是HibernateSessionFactory和HibernateTransactionManager的Spring配置。

<bean id="mySessionFactory"

       class="org.springframework.orm.hibernate.

              LocalSessionFactoryBean">

  <property name="mappingResources">

    <list>

      <value>

        com/meagle/bo/Order.hbm.xml

      </value>

      <value>

        com/meagle/bo/OrderLineItem.hbm.xml

      </value>

    </list>

  </property>

  <property name="hibernateProperties">

    <props>

      <prop key="hibernate.dialect">

        net.sf.hibernate.dialect.MySQLDialect

      </prop>

      <prop key="hibernate.show_sql">

        false

      </prop>

      <prop key="hibernate.proxool.xml">

        C:/MyWebApps/.../WEB-INF/proxool.xml

      </prop>

      <prop key="hibernate.proxool.pool_alias">

          spring

      </prop>

    </props>

  </property>

</bean>

<!-- Transaction manager for a single Hibernate

SessionFactory (alternative to JTA) -->

<bean id="myTransactionManager"

         class="org.

                springframework.

                orm.

                hibernate.

                HibernateTransactionManager">

  <property name="sessionFactory">

    <ref local="mySessionFactory"/>

  </property>

  </bean>

Each object can be referenced in the Spring configuration within a <bean> tag. In this case the bean mySessionFactory represents a HibernateSessionFactory and the bean myTransactionManager represents a Hibernate transaction manager. Notice that the transactionManger bean has a property element called sessionFactory. The HibernateTransactionManager class has a setter and getter for sessionFactory, which is used for dependency injection when the Spring container starts. The sessionFactory property references the mySessionFactory bean. These two objects will now be wired together when the Spring container initializes. This wiring relieves you from creating singleton objects and factories for referencing and creating these objects, which reduces code maintenance in your application. The mySessionFactory bean has two property elements, which translate to setters for mappingResources and hibernatePropertes. Normally, this configuration would be stored in the hibernate.cfg.xml file if you were using Hibernate outside of Spring. However, Spring provides an easy way to incorporate the Hibernate configuration within the Spring configuration file. For more information see the Spring API.

 

  可以看出:每个对象都可以在Spring 配置信息中用<bean>标签引用。在这里,mySessionFactory引用了HibernateSessionFactory,而myTransactionManager引用了HibernateTransactionManage。 注意代码中myTransactionManger Bean有个sessionFactory属性。 HibernateTransactionManager有个sessionFactory setter 和 getter方法,这是用来在Spring启动的时候实现“依赖注入” (dependency injection)的。 在sessionFactory 属性里 引用mySessionFactory。这两个对象在Spring容器初始化后就被组装了起来了。 这样的搭配让你从 单例(singleton objects)和工厂(factories)中解放了出来,降低了代码的维护代价。 mySessionFactory.的两个属性,分别是用来注入mappingResources 和 hibernatePropertes的。通常,如果你在Spring之外使用Hibernate,这样的设置应该放在hibernate.cfg.xml中的。 不管怎样,Spring提供了一个便捷的方式-----在Spring内部配置中并入了Hibernate的配置。 如果要得到更多的信息,可以查阅Spring API。

  每一个对象能被Spring配置里的一个<bean>标记引用。在这个例子里,bean “mySessionFactory”代表一个HibernateSessionFactory,bean “myTransactionManager”代表一个Hibernate transaction manager。注意transactionManger bean有一个叫作sessionFactory的属性元素。HibernateTransactionManager有一个为sessionFactory准备的setter和getter方法,它们是用来当Spring容器启动时的依赖注入。sessionFactory属性引用mySessionFactory bean。这两个对象现在当Spring容器初始化时将被连在一起。这种连接把你从为引用和创建这些对象而创建singleton对象和工厂中解放出来,这减少了你应用程序中的代码维护。mySessionFactory bean有两个属性元素,它们翻译成为mappingResources 和 hibernatePropertes准备的setter方法。通常,如果你在Spring之外使用Hibernate,这个配置将被保存在hibernate.cfg.xml文件中。不管怎样,Spring提供了一个便捷的方式--在Spring配置文件中合并Hibernate的配置。获得更多的信息查阅Spring API.

相关资源

转自:http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=2 

 日记标题 (转帖)Wiring Your Web Application with Open Source Java(3)  作者: guest  创建时间: 2005-12-28 21:04:44  最近更新: 2005-12-28 21:05:26  编辑 我要评论  

内容

(由admin转自:http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=3)

Now that we have our container service beans configured and wired together we need to wire our business service object and our DAO object together. Then we need to wire these objects to the transaction manager.

既然我们已经组装配置好了Service Beans,就需要把Business Service Object和 DAO也组装起来,并把这些对象配到一个事务管理器(transaction manager)里。

既然我们已经配置了我们的容器服务beans和把它们连在了一起,我们需要把我们的业务服务对象和我们的DAO对象连在一起。然后,我们需要把这些对象连接到事务管理器。

 

Here is what this looks like in the Spring configuration file:

 在Spring中的配置信息:  代码:

这是在Spring配置文件里的样子:

<!-- ORDER SERVICE -->

<bean id="orderService"

  class="org.

         springframework.

         transaction.

         interceptor.

         TransactionProxyFactoryBean">

  <property name="transactionManager">

    <ref local="myTransactionManager"/>

  </property>

  <property name="target">

    <ref local="orderTarget"/>

  </property>

  <property name="transactionAttributes">

    <props>

      <prop key="find*">

     PROPAGATION_REQUIRED,readOnly,-OrderException

      </prop>

      <prop key="save*">

     PROPAGATION_REQUIRED,-OrderException

      </prop>

    </props>

  </property>

</bean>

<!-- ORDER TARGET PRIMARY BUSINESS OBJECT:

Hibernate implementation -->

<bean id="orderTarget"

         class="com.

                meagle.

                service.

                spring.

                OrderServiceSpringImpl">

  <property name="orderDAO">

    <ref local="orderDAO"/>

  </property>

</bean>

<!-- ORDER DAO OBJECT -->

<bean id="orderDAO"

         class="com.

                meagle.

                service.

                dao.

                hibernate.

                OrderHibernateDAO">

  <property name="sessionFactory">

    <ref local="mySessionFactory"/>

  </property>

</bean>

Figure 4 is an overview of what we have wired together. This shows how each object is related and set into other objects by Spring. Compare this with the Spring configuration file in the sample application to see these relationships.

图4 是我们对象搭建的一个提纲。 从中可以看出,每个对象都联系着Spring,并且能通过Spring注入到其他对象。把它与Spring的配置文件比较,观察他们之间的关系

图4是我们已经连在一起的东西的一个概览。它展示了每个对象是怎样相关联的和怎样被Spring设置进其它对象中。把这幅图和示例应用中的Spring配置文件对比查看它们之间的关系。

Figure 4. This is how Spring will assemble the beans based on this configuration.

图 4. Spring就是这样基于配置文件,将各个Bean搭建在一起。

图4:这是Spring怎样将在这个配置的基础上装配beans。

This example uses a TransactionProxyFactoryBean, which has a setter for a transaction manager that we have already defined. This is a convenience object that knows how to deal with declarative transaction handling and your service objects. You can define how transactions are handled through the transactionAttributes property, which defines patterns for method names, and how they participate in a transaction. For more information about configuring isolation levels and commits or rollbacks on a transaction see TransactionAttributeEditor.

这个例子使用一个TransactionProxyFactoryBean,它定义了一个setTransactionManager()。 这对象很有用,他能很方便的处理你申明的事物还有Service Object。 你可以通过transactionAttributes属性来定义怎样处理。 想知道更多还是参考TransactionAttributeEditor吧。

这个例子使用一个TransactionProxyFactoryBean,它有一个为我们已经定义了的事务管理者准备的setter方法。这是一个有用的对象,它知道怎样处理声明的事务操作和你的服务对象。你可以通过transactionAttributes属性定义事务怎样被处理,transactionAttributes属性为方法名定义模式和它们怎样参与进一个事务。获得更多的关于在一个事务上配置隔离层和提交或回滚查阅TransactionAttributeEditor。

The class TransactionProxyFactoryBean also has a setter for a target, which will be a reference to our business service object called orderTarget. The orderTarget bean defines which business service class to use and it has a property which refers to setOrderDAO(). This property will populate the orderDAO bean that is our DAO object to communicate with our persistence layer.

TransactionProxyFactoryBean 还有个setter. 这会被我们 Business service object(orderTarget)引用, orderTarget定义了 业务服务层,并且它还有个属性,由setOrderDAO()引用。这个属性

TransactionProxyFactoryBean类也有一个为一个target准备的setter,target将是一个到我们的叫作orderTarget的业务服务对象的引用(a reference)。 orderTarget bean定义使用哪个业务服务对象并有一个指向setOrderDAO()的属性。orderDAO bean将居于这个属性中,orderDAO bean是我们的和持久层交流的DAO对象。

One more note about Spring and beans is that beans can operate in two modes. These are defined as singleton and prototype. The default mode for a bean is singleton that means that one shared instance of the bean will be managed. This is used for stateless operations like a stateless session bean would provide. The prototype mode allows new instances of the bean to be create when the bean is served through Spring. You should only use prototype mode when each user needs their own copy of the bean.

Spring 和Bean 的还有一点要注意的: bean可以以用两种方式创造。 这些都在单例模式(Sington)和原型模式(propotype)中定义了。 默认的方式是singleton,这意味着共享的实例将被束缚。 而原形模式是在Spring用到bean的时候允许新建实例的。当每个用户需要得到他们自己Bean的Copy时,你应该仅使用prototype模式。(更多的请参考设计模式中的单例模式和原形模式)

还有一个关于Spring和bean要注意的是bean能以两种模式工作。这两种模式被定义为singleton和prototype。一个bean默认的模式是singleton,意味着一个共享的bean的实例将被管理。这是用于无状态操作--像一个无状态会话bean将提供的那样。当bean由Spring提供时,prototype模式允许创建bean的新实例。你应当只有在每一个用户都需要他们自己的bean的拷贝时才使用prototype模式。

Providing a Service Locator

Now that we have wired up our services with our DAO we need to expose our services to other layers. This is generally used from code in a layer such as UI that uses Struts or Swing. An easy way to handle this is with a service locator patterned class to return resources from a Spring context. This can also be done directly through Spring by referencing the bean ID.

提供一个服务定位器(Providing a Service Locator)

既然我们已经将我们的Serices和DAO搭配起来了。我们需要把我们的Service显示到其他层。 这个通常是在Struts或者Swing这层里编码。一个简单方法就是用 服务定位器返回给Spring context 。当然,可以通过直接调用Spring中的Bean来做。

下面是一个Struts Actin 中的服务定位器的一个例子。

 代码:

提供一个服务定位器

  既然我们已经把我们的服务和我们的DAO连起来了,我们需要把我们的服务暴露给其它层。通常是一个像使用Struts或Swing这样的用户接口层里的代码来使用这个服务。一个简单的处理方法是使用一个服务定位器模式的类从一个Spring上下文中返回资源。这也可以靠引用bean ID通过Spring来直接完成。

Here is an example of how a service locator can be configured in a Struts Action:

这儿是一个在Struts Action中怎样配置一个服务定位器的例子:

public abstract class BaseAction extends Action {

  private IOrderService orderService;

  public void setServlet(ActionServlet

                                 actionServlet) {

    super.setServlet(actionServlet);

    ServletContext servletContext =

               actionServlet.getServletContext();

    WebApplicationContext wac =

      WebApplicationContextUtils.

         getR

再译Wiring Your Web Application with Open Source Java

(由admin转自:http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html)

[注:这个翻译任务是从matrix的文档wiki那里看到的,我的英文水平只能勉强看懂,但是翻译它是一举三得:学技术、学英语、为网络学习作贡献,听说这篇文章在csdn上有人翻译了,可我就是没有找到,有人找到了在这里告诉一下,以免大家重复劳动。我采用从粗到精的翻译方法,先忽略细节,按我的理解粗翻一遍,然后再请大家指正,精确化细节问题。-admin ]

[原来totodo已经翻译了这篇文章|#7]译者注:今天再次在google上用文中的包关键字"com.meagle.bo""com.meagle.service.dao.hibernate"搜索了一下(上次用的关键字是"Wiring Your Web Application with Open Source Java""中文",结果没有找到,大家吸取我的教训哦:)),发现totodo在2004年就已经翻译了这篇文章([使用struts+spring+hibernate 组装web应用|http://www.matrix.org.cn/resource/article/1034.html])。总体翻译得还可以,但是也有不少没有忠于原文甚至错误的地方(我想,我的错误也许更多:)。现在我将结合两篇译文来修改、精确化中文译文,并希望在大家的指点下,得到一篇精确忠于原作者意图的译文。

  -admin 2006.1.3 14:02

Tags: java spring struts hibernate programming

Bookmark with del.icio.us

  

Wiring Your Web Application with Open Source Java

by Mark Eagle

04/07/2004

用Java开源技术构建你的web应用

Building non-trivial web applications with Java is no trivial task. There are many things to consider when structuring an architecture to house an application. From a high-level, developers are faced with decisions about how they are going to construct user interfaces, where the business logic will reside, and how to persist application data. Each of these three layers has their own questions to be answered. What technologies should be implemented across each layer? How can the application be designed so that it is loosely coupled and flexible to change? Does the architecture allow layers to be replaced without affecting other layers? How will the application handle container level services such as transactions?

  其实,就算用Java建造一个不是很烦琐的web应用,也不是件轻松的事情。 在构架的一开始就有很多事情要考虑。 从高处看,摆在开发者面前有很多问题:要考虑是怎样建立用户接口?在哪里处理业务逻辑? 怎样持久化的数据。 而这三层构架中,每一层都有他们要仔细考虑的。 各个层该使用什么技术? 怎样的设计能松散耦合还能灵活改变? 怎样替换某个层而不影响整体构架?应用程序如何做各种级别的业务处理(比如事务处理)?

   其实,就算用Java建造一个不是很烦琐的web应用程序,也不是件轻松的事情。当为一个应用程序建造一个构架时有许多事情需要考虑。从高层来说,开发者需要考虑:怎样建立用户接口(user interfaces)?在哪里处理业务逻辑?和怎样持久化应用数据。这三层每一层都有它们各自的问题需要回答。 各个层次应该使用什么技术?怎样才能把应用程序设计得松耦合和能灵活改变?构架允许层的替换不会影响到其它层吗?应用程序怎样处理容器级的服务(container level services),比如事务处理(transactions)?

There are definitely a number of questions that need to be addressed when creating an architecture for your web application. Fortunately, there have been developers that have run into these reoccurring problems and built frameworks to address these issues. A good framework relieves developers from attempting to reinvent the wheel for complex problems; it is extensible for internal customization; and it has a strong user community to support it. Frameworks generally address one problem well. However, your application will have several layers that might require their own framework. Just solving your UI problem does not mean that you should couple your business logic and persistence logic into a UI component. For example, you should not have business logic with JDBC code inside of a controller. This is not the functionality that a controller was intended to provide. A UI controller should be a lightweight component that delegates calls to other application layers for services outside the UI scope. Good frameworks naturally form guidelines where code should be placed. More importantly, frameworks alleviate developers from building code such as persistence from scratch and allow them to concentrate on the application logic that is important to a client.

  构架一个Web应用需要弄明白好多问题。 幸运的是,已经有不少开发者已经遇到过这类问题,并且建立了处理这类问题的框架。 一个好框架具备以下几点: 减轻开发者处理复杂的问题的负担(“不重复发明轮子”); 内部有良好的扩展; 并且有一个支持它的强大的用户团体。 好的构架一般有针对性的处理某一类问题,并且能将它做好(Do One Thing well)。 然而,你的程序中有几个层可能需要使用特定的框架,已经完成的UI(用户接口) 并不代表你也可以把你的业务逻辑和持久逻辑偶合到你的UI部分。 举个例子, 你不该在一个Controller(控制器)里面写JDBC代码作为你的业务逻辑, 这不是控制器应该提供的。 一个UI 控制器应该委派给其它给在UI范围之外的轻量级组件。 好的框架应该能指导代码如何分布。 更重要的是,框架能把开发者从编码中解放出来,使他们能专心于应用程序的逻辑(这对客户来说很重要)。

  当为你的web应用程序创建一个构架时,需要涉及到相当多的问题。幸运的是,已经有不少开发者已经遇到过这类重复发生的问题,并且建立了处理这类问题的框架。一个好框架具备以下几点: 减轻开发者处理复杂的问题的负担(“不重复发明轮子”);内部定义为可扩展的;有一个强大的用户群支持。框架通常能够很好的解决一方面的问题。然而,你的应用程序有几个层可能都需要它们各自的框架。就如解决你的用户接口(UI)问题时你就不应该把事务逻辑和持久化逻辑掺杂进来。例如,你不应该在控制器(controller)里面写jdbc代码,使它包含有业务逻辑,这不是控制器应该提供的功能。它应该是轻量级的,代理来自用户接口(UI)外的调用请求给其它服务于这些请求的应用层。好的框架自然的形成代码如何分布的指导。更重要的是,框架减轻开发者从头开始写像持久层这样的代码的痛苦,使他们专注于对客户来说很重要的应用逻辑。

This article will discuss how to combine several well-known frameworks to achieve loose coupling, how to structure your architecture, and how to enforce a consistent design across all application layers. The challenge is combining frameworks so that each layer is exposed to each other in a loosely coupled manner, regardless of the underlying technologies. This article will discuss one strategy for combining frameworks using three popular open source frameworks. For the presentation layer we will use Struts; for our business layer we will use Spring; and for our persistence layer we will use Hibernate. You should be able to substitute any one of these frameworks in your application and get the same effect. Figure 1 shows what this looks like from a high level when the frameworks are combined.

  这篇文章将讨论怎样结合几种著名的框架来使得你的应用程序做到松弛耦合。 如何建立你的架构,并且怎样让你的各个应用层保持一致。?如何整合框架以便让每个层在以一种松散偶合的方式彼此作用而不用管低层的技术细节?这对我们来说真是一种挑战。 这里讨论一个整合框架的策略( 使用3 种受欢迎的开源框架) :表示层我们用Struts; 业务层我们用Spring;而持久层则用Hibernate。 你也可以用其他FrameWork替换只要能得到同样的效果。 见图1 (框架组合示意图)

  这篇文章将怎样组合几个著名的框架去做到松耦合的目的,怎样建立你的构架,怎样让你的各个应用层保持一致。富于挑战的是:组合这些框架使得每一层都以一种松耦合的方式彼此沟通,而与底层的技术无关。这篇文章将使用3种流行的开源框架来讨论组合框架的策略。表现层我们将使用Struts;业务层我们将使用Spring;持久层使用Hibrenate.你也可以在你的应用程序中替换这些框架中的任何一种而得到同样的效果。图1展示了当这些框架组合在一起时从高层看是什么样子。

Figure 1. Overview of framework architecture with Struts, Spring, and Hibernate.

图1用Struts, Spring, 和 Hibernate框架构建的概览

Application Layering

Most non-trivial web applications can be divided into at least four layers of responsibility. These layers are the presentation, persistence, business, and domain model layers. Each layer has a distinct responsibility in the application and should not mix functionality with other layers. Each application layer should be isolated from other layers but allow an interface for communication between them. Let's start by inspecting each of these layers and discuss what these layers should provide and what they should not provide.

应用程序的分层

大部分的Web应用在职责上至少能被分成4层。 这四层是:presentation(描述),persistence(持久),business(业务)和domain model(域模块)。每个层在处理程序上都应该有一项明确的责任, 而不应该在功能上与其它层混合,并且每个层要与其它层分开的,但要给他们之间放一个通信接口。 我们就从介绍各个层开始,讨论一下这些层应该提供什么,不应该提供什么。

应用程序的分层

大多数不复杂的web应用都能被分成至少4个各负其责的层次。这些层次是:表现层(presentation)、持久层(persistence)、业务层(business)、领域模型层(domain model)。每层在应用程序中都有明确的责任,不应该和其它层混淆功能。每一应用层应该彼此独立但要给他们之间放一个通信接口。让我们从审视各个层开始,讨论这些层应该提供什么和不应该提供什么。

The Presentation Layer

表示层(The Presentation Layer)

表现层 (The Presentation Layer)

  

At one end of a typical web application is the presentation layer. Many Java developers understand what Struts provides. However, too often, coupled code such as business logic is placed into an org.apache.struts.Action. So, let's agree on what a framework like Struts should provide. Here is what Struts is responsible for:

  一般来讲,一个典型的Web应用的的末端应该是表示层。 很多Java发者也理解Struts所提供的。 象业务逻辑之类的被打包到org.apache.struts.Action., 因此,我们很赞成使用Struts这样的框架。

  在一个典型的web应用的一端是表现层。很多Java开发者也理解Struts所提供的。然而,太常见的是,他们把像业务逻辑之类的耦合的代码放进了一个org.apache.struts.Action。所以,让我们在像Struts这样一个框架应该提供什么上取得一致意见。这儿是Struts负责的:

Managing requests and responses for a user.

Providing a controller to delegate calls to business logic and other upstream processes.

Handling exceptions from other tiers that throw exceptions to a Struts Action.

Assembling a model that can be presented in a view.

Performing UI validation.

下面是Struts所负责的:

* 管理用户的请求,做出相应的响应。

* 提供一个Controller ,委派调用业务逻辑和其它上层处理。

* 处理异常,抛给Struts Action

* 为显示提供一个模型

* UI验证。

为用户管理请求和响应;

提供一个控制器(controller)代理调用业务逻辑和其它上层处理;

处理从其它层掷出给一个Struts Action的异常;

为显示提供一个模型;

执行用户接口(UI)验证。

Here are some items that are often coded using Struts but should not be associated with the presentation layer:

Direct communication with the database, such as JDBC calls.

Business logic and validation related to your application.

Transaction management.

Introducing this type of code in the presentation layer leads to type coupling and cumbersome maintenance.

以下条款,不该在Struts显示层的编码中经常出现。 它们与显示层无关的。

* 直接的与数据库通信,例如JDBC调用。

* 与你应用程序相关联的业务逻辑以及校验。

* 事物管理。

在表示层引入这些代码,则会带来高偶合和麻烦的维护。

这儿是一些经常用Struts编写的但是却不应该和Struts表现层相伴的项目:

直接和数据库通信,比如JDBC调用;

业务逻辑和与你的应用程序相关的验证;

事务管理;

在表现层中引入这种代码将导致典型耦合(type coupling)和讨厌的维护。

The Persistence Layer

At the other end of a typical web application is the persistence layer. This is usually where things get out of control fast. Developers underestimate the challenges in building their own persistence frameworks. A custom, in-house persistence layer not only requires a great amount of development time, but also often lacks functionality and becomes unmanageable. There are several open source object-to-relational mapping (ORM) frameworks that solve much of this problem. In particular, the Hibernate framework allows object-to-relational persistence and query service for Java. Hibernate has a medium learning curve for Java developers who are already familiar with SQL and the JDBC API. Hibernate persistent objects are based on plain-old Java objects and Java collections. Furthermore, using Hibernate does not interfere with your IDE. The following list contains the type of code that you would write inside a persistence framework:

持久层(The Persistence Layer)

典型的Web应用的另一个末端是持久层。这里通常是程序最容易失控的地方。开发者总是低估构建他们自己的持久框架的挑战性。系统内部的持续层不但需要大量调试时间,而且还经常缺少功能使之变得难以控制,这是持久层的通病。 还好有几个ORM开源框架很好的解决了这类问题。尤其是Hibernate。 Hibernate为java提供了OR持久化机制和查询服务, 它还给已经熟悉SQL和JDBC API 的Java开发者一个学习桥梁,他们学习起来很方便。 Hibernate的持久对象是基于POJO和Java collections。此外,使用Hibernate并不妨碍你正在使用的IDE。

请看下面的条目,你在持久层编码中需要了解的。

持久层 (The Persistence Layer )

在典型web应用的另一端是持久层。这通常是使事情迅速失控的地方。开发者低估了构建他们自己的持久层框架的挑战性。一般来说,机构内部自己写的持久层不仅需要大量的开发时间,而且还经常缺少功能和变得难以控制。有几个开源的“对象-关系映射”(ORM)框架非常解决问题。尤其是,Hibernate框架为java提供了"对象-关系持久化"(object-to-relational persistence)机制和查询服务。Hibernate对那些已经熟悉了SQL和JDBC API的Java开发者有一个适中的学习曲线。Hibernate持久对象是基于简单旧式Java对象(POJO)和Java集合(Java collections)。此外,使用Hibernate并不妨碍你正在使用的IDE。下面的列表包含了你该写在一个持久层框架里的代码类型:

[注:由admin翻译上述部分2005年12月28日22:40分;由***在***修改了上述部分;由***在***修改了上述部分...请自行填写,以便联系]

Querying relational information into objects. Hibernate does this through an OO query language called HQL, or by using an expressive criteria API. HQL is very similar to SQL except you use objects instead of tables and fields instead of columns. There are some new specific HQL language elements to learn; however, they are easy to understand and well documented. HQL is a natural language to use for querying objects that require a small learning curve.

* 查询对象的相关信息的语句。 Hibernate通过一个OO查询语言(HQL)或者正则表达的API来完成查询。 HQL非常类似于SQL-- 只是把SQL里的table和columns用Object和它的fields代替。 你需要学习一些新的HQL语言; 不管怎样,他们容易理解而文档也做的很好。 HQL是一种对象查询的自然语言,花很小的代价就能学习它。

查询相关的信息成为对象。Hibernate通过一种叫作HQL的面向对象(OO)的查询语言或者使用条件表达式API(expressive criteria API)来做这个事情。 HQL非常类似于SQL-- 只是把SQL里的table和columns用Object和它的fields代替。有一些新的专用的HQL语言成分要学;不过,它们容易理解而且文档做得好。HQL是一种使用来查询对象的自然语言,花很小的代价就能学习它。

Saving, updating, and deleting information stored in a database.

* 如何存储,更新,删除数据库记录。

保存、更新、删除储存在数据库中的信息。

Advanced object-to-relational mapping frameworks like Hibernate have support for most major SQL databases, and they support parent/child relationships, transactions, inheritance, and polymorphism.

* 象Hibernate这类的高级ORM框架支持大部分主流数据库,并且他们支持 Parent/child关系,事物处理,继承和多态。

像Hibernate这样的高级“对象-关系”映射(object-to-relational mapping)框架提供对大多数主流SQL数据库的支持,它们支持“父/子”(parent/child)关系、事务处理、继承和多态。

Here are some items that should be avoided in the persistence layer:

这儿是一些应该在持久层里被避免的项目:

Business logic should be in a higher layer of your application. Only data access operations should be permitted.

业务逻辑应该在你的应用的一个高一些的层次里。持久层里仅仅允许数据存取操作。

You should not have persistence logic coupled with your presentation logic. Avoid logic in presentation components such as JSPs or servlet-based classes that communicate with data access directly. By isolating persistence logic into its own layer, the application becomes flexible to change without affecting code in other layers. For example, Hibernate could be replaced with another persistence framework or API without modification to the code in any other layer.

你不应该把持久层逻辑(persistence logic)和你的表现层逻辑(presentation logic)搅在一起。避免像JSPs或基于servlet的类这些表现层组件里的逻辑和数据存取直接通信。通过把持久层逻辑隔离进它自己的层,应用程序变得易于修改而不会影响在其它层的代码。例如:Hebernate能够被其它持久层框架或者API代替而不会修改在其它任何层的代码。

The Business Layer

The middle component of a typical web application is the business or service layer. This service layer is often the most ignored layer from a coding perspective. It is not uncommon to find this type of code scattered around in the UI layer or in the persistence layer. This is not the correct place because it leads to tightly coupled applications and code that can be hard to maintain over time. Fortunately, several frameworks exist that address these issues. Two of the most popular frameworks in this space are Spring and PicoContainer. These are referred to as microcontainers that have a very small footprint and determine how you wire your objects together. Both of these frameworks work on a simple concept of dependency injection (also known as inversion of control). This article will focus on Spring's use of setter injection through bean properties for named configuration parameters. Spring also allows a sophisticated form of constructor injection as an alternative to setter injection as well. The objects are wired together by a simple XML file that contains references to objects such as the transaction management handler, object factories, service objects that contain business logic, and data access objects (DAO).

业务层(The Business Layer)

一个典型Web应用的中间部分是业务层或者服务层。 从编码的视角来看,这层是最容易被忽视的一层。 而我们却往往在UI层或持久层周围看到这些业务处理的代码,这其实是不正确的,因为它导致了程序代码的紧密偶合,这样一来,随着时间推移这些代码很难维护。幸好,针对这一问题有好几种Frameworks存在。 最受欢迎的两个框架是Spring和PicoContainer。 这些为也被称为microcontainers,他们能让你很好的把对象搭配起来。 这两个框架都着手于‘依赖注射’(dependency injection)(还有我们知道的‘控制反转’Inversion of Control=IoC)这样的简单概念。 这篇文章将关注于Spring的注射(译注:通过一个给定参数的Setter方法来构造Bean,有所不同于Factory), Spring还提供了Setter Injection(type2),Constructor Injection(type3)等方式供我们选择。 Spring把程序中所涉及到包含业务逻辑和Dao的Objects——例如transaction management handler(事物管理控制)、Object Factoris(对象工厂)、service objects(服务组件)——都通过XML来配置联系起来。

[注:糟糕,还没有接触过Spring和PicoContainer,这下面的翻译肯定是漏洞百出,还望大虾不吝赐教:)]

业务层

在一个典型的web应用程序的中间的组件是业务层或服务层。从编码的视角来看,这个服务层是最容易被忽视的一层。不难在用户接口(UI)层或者持久层里找到散布在其中的这种类型的代码。这不是正确的地方,因为这导致了应用程序的紧耦合,这样一来,随着时间推移代码将很难维护。幸好,针对这一问题有好几种Frameworks存在。在这个领域两个最流行的框架是Spring和PicoContainer,它们叫作微容器(microcontainers),你可以不费力不费神的把你的对象连在一起。所有这些框架都工作在一个简单的叫作“依赖注入”(dependency injection)(也通称“控制反转”(inversion of control))的概念上。这篇文章将着眼于Spring的为指定的配置参数通过bean属性的setter注入(setter injection)的使用。Spring也提供了一个构建器注入(constructor injection)的复杂形式作为setter注入的一个替代。对象们被一个简单的XML文件连在一起,这个XML文件含有到像事务管理器(transaction management handler)、对象工厂(object factories)、包含业务逻辑的服务对象(service objects)、和数据存取对象(DAO)这些对象的引用(references)。

The way Spring uses these concepts will be made clearer with examples later in this article. The business layer should be responsible for the following:

Handling application business logic and business validation

Managing transactions

Allowing interfaces for interaction with other layers

Managing dependencies between business level objects

Adding flexibility between the presentation and the persistence layer so they do not directly communicate with each other

Exposing a context to the business layer from the presentation layer to obtain business services

Managing implementations from the business logic to the persistence layer

后面我们会举个例子来揭示一下Spring 是怎样运用这些概念。

业务层所负责的如下:

* 处理应用程序的 业务逻辑和业务校验

* 管理事物

* 允许与其它层相互作用的接口

* 管理业务层级别的对象的依赖。

* 在显示层和持久层之间增加了一个灵活的机制,使得他们不直接的联系在一起。

* 通过揭示 从显示层到业务层之间的Context来得到business services。

* 管理程序的执行(从业务层到持久层)。

这篇文章的后面将用例子来把Spring使用这些概念的方法说得更清楚一些。业务层应该负责下面这些事情:

处理应用程序的业务逻辑和业务验证;

管理事务;

预留和其它层交互的接口;

管理业务层对象之间的依赖;

增加在表现层和持久层之间的灵活性,使它们互不直接通信;

从表现层中提供一个上下文(context)给业务层获得业务服务(business services );

管理从业务逻辑到持久层的实现。

The Domain Model Layer

Finally, since we are addressing non-trivial, web-based applications we need a set of objects that can move between the different layers. The domain object layer consists of objects that represent real-world business objects such as an Order, OrderLineItem, Product, and so on. This layer allows developers to stop building and maintaining unnecessary data transfer objects, or DTOs, to match their domain objects. For example, Hibernate allows you to read database information into an object graph of domain objects, so that you can present it to your UI layer in a disconnected manner. Those objects can be updated and sent back across to the persistence layer and updated within the database. Furthermore, you do not have to transform objects into DTOs, which can get lost in translation as they are moved between different application layers. This model allows Java developers to work with objects naturally in an OO fashion without additional coding.

域模块层(The Domain Model Layer )

既然我们致力于的是一个不是很复杂的Web的应用, 我们需要一个对象集合,让它在不同层之间移动的。 域模块层由实际需求中的业务对象组成 比如, OrderLineItem , Product等等。 开发者在这层 不用管那些DTOs,仅关注domain object即可。 例如,Hibernate允许你将数据库中的信息存放入对象(domain objects),这样你可以在连接断开的情况下把这些数据显示到UI层。 而那些对象也可以返回给持续层,从而在数据库里更新。 而且,你不必把对象转化成DTOs(这可能似的它在不同层之间的在传输过程中丢失),这个模型使得Java开发者能很自然运用OO,而不需要附加的编码。

领域模型层

最后,因为我们讨论不平凡的、基于web的应用,我们需要一组对象能在不同的层之间移动。领域对象层由那些代表真实世界业务对象,比如:一份订单、订单项、产品等等组成。这个层允许开发者停止建造和维护不必要的数据传输对象,或者DTOs,来匹配他们的领域对象。例如,Hibernate允许你把数据库信息读进领域对象的一个对象图,所以你能以一种分离的方式把它交给你的用户界面层。那些对象能被更新和送回到持久层在数据库里更新。进一步,你不必转换对象到DTOs,DTOs能在传输中迷路,因为他们在不同的应用层间移动。这种模式允许Java开发者自然地以一种面向对象的风格和对象一起工作,没有附加的编码。

[注:由admin翻译上述部分2005年12月30日20:57分;由***在***修改了上述部分;由***在***修改了上述部分...请自行填写,以便联系] 

相关资源

转自:http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html 

 日记标题 (转帖)Wiring Your Web Application with Open Source Java(2)  作者: guest  创建时间: 2005-12-28 20:58:18  最近更新: 2005-12-28 20:58:18  编辑 我要评论  

内容

(由admin转自:http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=2)

Wiring Together a Simple Example

Now that we understand the components from a high level, let's put this into practice. Again, for this example, we will combine the Struts, Spring, and Hibernate frameworks. Each one of these frameworks has too much detail to cover in one article. Instead of going into many details about each framework, this article will show how to wire them together with simple example code. The sample application will demonstrate how a request is serviced across each layer. A user of this sample application can save a new order to the database and view an existing order in the database. Further enhancements might allow the user to update or delete an existing order.

一个简单例子

既然我们已经从全局上理解这些组件。 现在就让我们开始实践吧。 我们还是用 Struts,Spring 和Hibernate。这三个框架已经被描述够多了,这里就不重复介绍了。 这篇文章举例指导你如何使用这三个框架整合开发, 并向你揭示 一个请求是如何贯穿于各个层的。(从用户的加入一个Order到数据库,显示;进而更新、删除)。

结合一个简单的例子

  现在,我们从一个高的层次理解了组件,让我们把这些用于实践。在这个例子中,我们将合并Struts、Spring、Hibernate框架。每一个这些框架在一篇文章中都有太多的细节覆盖到。这篇文章将用一个简单的例子代码展示怎样把它们结合在一起,而不是进入每个框架的许多细节。示例应用将示范一个请求怎样跨越每一层被服务。这个示例应用的一个用户能保存一个订单到数据库中和查看一个在数据库中存在的订单。进一步的提高也许允许用户更新或删除一个存在的订单。  

 

You can download the source code of the application.

从这里可以下载到程序程序原代码(download)

你可以下载这个应用的源码。

First, we will create our domain objects since they will interoperate with each layer. These objects will allow us to define what should be persisted, what business logic should be provided, and what type of presentation interface should be designed. Next, we will configure the persistence layer and define object-to-relational mappings with Hibernate for our domain objects. Then we will define and configure our business objects. After we have these components we can discuss wiring these layers using Spring. Finally, we will provide a presentation layer that knows how to communicate with the business service layer and knows how to handle exceptions that arise from other layers.

  既然每个层是互相作用的,我们就先来创建domain objects。首先,我们要在这些Object中要确定那些是需要持久化的,哪些是提供给business logic,那些是显示接口的设计。 下一步,我们将配置我们的持久层并且定义好Hibernate的OR mappings。然后定义好Business Objects。有了这些组成部分之后,我们将 使用Spring把这些连接起来。 最后,我们提供给Spring一个持久层,从这个持久层里我们可以知道它是如何与业务逻辑层(business service layer)通信的,以及它是怎样处理其他层抛出的异常的。。

  首先,我们将创建我们的领域对象因为它们将和每一层交互。这些对象将允许我们定义什么应该被持久化,什么业务逻辑应该被提供,和哪种表现界面应该被设计。然后,我们将配置持久层和为我们的领域对象用Hibernate定义“对象-关系”映射。然后,我们将定义和配置我们的业务对象。在有了这些组件后,我们能讨论和Spring把这些层连在一起。最后,我们将提供一个表现层,它知道怎样和业务服务层交流和知道怎样处理从其它层产生的异常。

Domain Object Layer

Since these objects will interoperate across all layers this might be a good place to start coding. This simple domain model will contain an object that represents an order and an object that represents a line item for an order. The order object will have a one-to-many relationship to a collection of line item objects. The example code has two simple objects in the domain layer:

com.meagle.bo.Order.java: contains the header-level information for an order.

com.meagle.bo.OrderLineItem.java: contains the detail-level information for an order.

Consider choosing package names for your objects that reflect how your application is layered. For example, the domain objects in the sample application can be located in the com.meagle.bo package. More specialized domain objects would be located in subpackages under the com.meagle.bo package. The business logic begins in the com.meagle.service package and DAO objects are located in the com.meagle.service.dao.hibernate package. The presentation classes for forms and actions reside in com.meagle.action and com.meagle.forms, respectively. Accurate package naming provides a clear separation for the functionality that your classes provide, allows for easier maintenance when troubleshooting, and provides consistency when adding new classes or packages to the application.

域对象层(Domain Object Layer)

这层是编码的着手点,我们的编码就从这层开始。 例子中Order 与OrderItem 是一个One—To—Many的关系。 下面就是Domain Object Layer的两个对象:

· com.meagle.bo.Order.java: 包含了一个Order的概要信息

· com.meagle.bo.OrderLineItem.java: 包含了Order的详细信息

好好考虑怎你的package命名,这反应出了你是怎样分层的。 例如 domain objects在程序中可能打包在com.meagle.bo内。 更详细一点将打包在com. meagle.bo的子目录下面。business logic应该从com.meagle.serice开始打包,而DAO 对象应该位于com.meagle.service.dao.hibernate。反应Forms和Actions的 持久对象(presentation classes) 应该分别放在 com.meagle.action和com.meagle.forms包。 准确的给包命名使得你的classes很好分割并且易于维护,并且在你添加新的classes时,能使得程序结构上保持上下一致。

领域对象层

因为这些对象将和所有层交互,这也许是一个开始编码的好地方。这个简单的领域模型将包括一个代表一份订单的对象和一个代表一个订单项的对象。订单对象将和一组订单项对象有一对多的关系。例子代码在领域层有两个简单的对象:

com.meagle.bo.Order.java: 包括一份订单的概括信息;

com.meagle.bo.OrderLineItem.java: 包括一份订单的详细信息;

考虑为你的对象选择包名,它将反映你的应用是怎样分层的。例如:简单应用的领域对象可以放进com.meagle.bo包[译者注:bo-business object?]。更多专门的领域对象将放入在com.meagle.bo下面的子包里。业务逻辑在com.meagle.service包里开始,DAO对象被放进com.meagle.service.dao.hibernate包。对于forms和actions的表现类分别驻入com.meagle.action 和 com.meagle.forms包。准确的包命名为你的类提供的功能提供一个清楚的区分,考虑到当故障维护时更易于维护,当增加新的类或包给应用时提供一致性。

Persistence Layer Configuration

There are several steps involved in setting up the persistence layer with Hibernate. The first step is to configure our domain business objects to be persisted. Since Hibernate works with POJOs we will use our domain objects for persistence. Therefore the Order and OrderLineItem objects will need to provide getter and setter methods for all fields that they contain. The Order object would contain setter and getter methods such as ID, UserName, Total, and OrderLineItems in a standard JavaBean format. The OrderLineItem would similarly follow the JavaBean format for its fields.

Hibernate maps domain objects-to-relational databases in XML files. For our Order and OrderLineItem objects there will be two mapping files to express this. There are tools such as XDoclet to assist with this mapping. Hibernate will map the domain objects to these files:

Order.hbm.xml

OrderLineItem.hbm.xml

You will find these generated files in the WebContent/WEB-INF/classes/com/meagle/bo directory. The Hibernate SessionFactory is configured to know which database it is communicating with, the DataSource or connection pool to use, and what persistent objects are available for persistence. Session objects provided by the SessionFactory are the interface used to translate between Java objects and persistence functions such as selecting, saving, updating, and deleting objects. We will discuss configuring the SessionFactory that Hibernate requires to handle Session objects in a later section.

持久层的配置(Persistence Layer Configuration)

建立Hibernate的持久层 需要好几个步骤。 第一步让我们把BO持久化。 既然Hibernate是通过POJO工作的, 因此Order和 OrderLineItem对象需要给所有的fileds 加上getter,setter方法。 Hibernate通过XML文件来映射(OR)对象,以下两个xml文件分别映射了Order 和OrderItem对象。(这里有个叫XDoclet工具可以自动生成你的XML影射文件)

- Order.hbm.xml

- OrderLineItem.hbm.xml

- Order.hbm.xml

- OrderLineItem.hbm.xml

你可以在WebContent/WEB-INF/classes/com/meagle/bo目录下找到这些xml文件。Hibernate的 [urlhttp://www.hibernate.org/hib_docs/api/net/sf/hibernate/SessionFactory.html]SessionFactory [/url]是用来告诉程序 应该与哪个数据库通信,该使用哪个连接池或使用了DataSource, 应该加载哪些持久对象。而Session接口是用来完成Selecting,Saving,Delete和Updating这些操作。 后面的我们将讲述SessionFactory和Session是怎样设置的。

持久层配置

用Hibernate设置持久层涉及到几个步骤。第一步是配置我们的被持久化的领域对象。因为Hibernate和POJOs[译者注:Persistence Objects Java Objects?]一起工作,我们将使用我们的领域对象持久化。因此,订单和订单项对象将需要提供它们包括的所有的字段的getter和setter方法。订单对象将包括像ID、用户名、合计、和订单项这样一些字段的以一种标准的JavaBean的格式的setter和getter方法。订单项对象将同样的用JavaBean的格式为它的字段设置setter和getter方法。

  Hibernate在XML文件里映射领域对象到关系数据库。为我们的订单和订单项对象将有两个映射文件来表达这种映射。有像XDoclet这样的工具来帮助这种映射。Hibernate将映射领域对象到这些文件:

Order.hbm.xml

OrderLineItem.hbm.xml

你可以在WebContent/WEB-INF/classes/com/meagle/bo目录里找到这些生成的文件。Hibernate SessionFactory被配置来知道它正和哪种数据库交流、使用哪种数据源或连接池、什么持久的对象被持久化是有效的。被SessionFactory提供的Session对象是用于在Java对象和像选取、保存、更新、删除对象这样的一些持久化功能间的翻译的接口。我们将在后面的小节讨论配置Hibernate处理Session对象需要的SessionFactory。

Business Layer Configuration

Now that we have our domain objects we need to have business service objects that perform application logic, make calls to the persistence layer, take requests from the UI layer, deal with transactions, and handle exceptions. To wire all of this together and make this easy to manage we will use the bean management aspect of the Spring framework. Spring uses inversion of control (IoC), or setter dependency injection, to wire up objects that are referenced in an external XML file. Inversion of control is a simple concept that allows objects to accept other objects that are created at a higher level. This way your object is free from having to create objects and reduces object coupling.

Here is an example of an object creating its dependencies without IoC, which leads to tight object coupling:

Figure 2. Objects arranged without IoC. Object A creates objects B and C.

And here is an example with IoC that allows objects to be created at higher levels and passed into objects so that they can use the implementations directly:

Figure 3. Objects arranged with IoC. Object A contains setter methods that accept interfaces to objects B and C. This could have also been achieved with constructors in object A that accepts objects B and C.

业务层的配置(Business Layer Configuration)

既然我们已经有了domain objects,接下来我们就要business service objects了,用他们来执行程序的logic,调用持久层,得到UI层的requests,处理transactions,并且控制exceptions。 为了将这些连接起来并且易于管理,我们将使用面向方面的 SpringFramework。 Spring 提供了 控制倒置(inversion of control 0==IoC)和注射依赖设置(setter dependency injection)这些方式(可供选择),用XML文件将对象连接起来。 IoC是一个简单概念(它允许一个对象在上层接受其他对象的创建),用IoC这种方式让你的对象从创建中释放了出来,降低了偶合度。

这里是一个没有使用IoC的对象创建的例子,它有很高偶合度。

图 2.没有使用 IoC. A 创建了 B 和 C

而这里是一个使用IoC的例子,这种方式允许对象在高层可以创建并进入另外一个对象,所以这样可以直接被执行。

 图 3. 对象使用了 IoC。 A 包含了接受B,C的 setter方法 , 这同样达到了 由A创建B,C的目的。

业务层配置

  现在,我们有了我们的领域对象,我们需要有业务服务对象来执行应用逻辑、执行向持久层的调用、获得从用户界面层的请求、处理事务、处理异常。为了把所有这些连在一起使它易于管理,我们将使用Spring框架的bean管理方面的功能。Spring使用“控制反转”(IoC),或者“setter依赖注入”来把这些对象连好,这些对象在一个外部的XML文件中被引用。“控制反转”是一个简单的概念,它允许对象接受其它在一个高一些的层次创建的对象。使用这种方法,你的对象从必须创建其它对象中解放出来和减少对象耦合。

  这儿是个不使用IoC的对象创建它的从属对象的例子,这导致紧的对象耦合:

  图2:没有使用IoC的对象组织。对象A创建对象B和C。

  这儿是一个使用IoC的例子,它允许对象在一个高一些层次被创建和传进对象,所以它们能直接使用现存的对象:

  图3:对象使用IoC组织。对象A包含setter方法,它们接受到对象B和C的接口。这也可以用对象A里的接受对象B和C的构建器完成。

Building Our Business Service Objects

The setters we will use in our business objects accept interfaces that allow loosely defined implementations of the objects that will be set, or injected. In our case we will allow our business service object to accept a DAO to handle the persistence of our domain objects. While the examples in this article use Hibernate, we can easily switch implementations to a different persistence framework and inform Spring of the new implementation DAO object to use. You can see how programming to interfaces and using the dependency injection pattern loosely couples your business logic from your persistence mechanism.

Here is the interface for the business service object that is stubbed for a DAO object dependency:

建立我们的业务服务对象(Building Our Business Service Objects)

Business Object中的Setter方法接受的是接口,这样我们可以很松散的定义对象实现,然后注入。 在我们的案例中,我们将用一个business service object接收一个DAO,用它来控制domain objects的持久化。 由于在这个例子中使用了Hibernate,我们可以很方便的用其他持久框架实现 同时通知Spring 有新的DAO可以使用了。

在面向接口的编程中,你会明白 “注射依赖”模式是怎样松散耦合你的业务逻辑和持久机制的:)。

下面是一个接口business service object,DAO代码片段:

 代码:

建造我们的业务服务对象

  我们将在我们的业务对象中使用的setter方法接受接口,这些接口允许将被设置或者注入的对象的宽松实现。在我们这个例子里我们将允许我们的业务服务对象接受一个DAO去控制我们的领域对象的持久化。虽然在这篇文章的例子中使用Hibernate,我们可以容易的转换到一个不同的持久框架的实现,通知Spring使用新的实现的DAO对象。你将看见怎样编程到接口和使用“依赖注入”模式宽松耦合你的业务逻辑和你的持久化机制。

  这儿是业务服务对象的接口,它有一个DAO对象依赖的桩。[译者注:是setOrderDAO方法吗?]

public interface IOrderService {

  public abstract Order saveNewOrder(Order order)

    throws OrderException,

           OrderMinimumAmountException;

  public abstract List findOrderByUser(

                                     String user)

                           throws OrderException;

  public abstract Order findOrderById(int id)

                           throws OrderException;

  public abstract void setOrderDAO(

                             IOrderDAO orderDAO);

}

Notice that the code above has a setter for a DAO object. There is not a getOrderDAO method because it is not necessary since there is often no need to access the wired OrderDAO object from the outside. The DAO object will be used to communicate with our persistence layer. We will wire the business service object and the DAO object together with Spring. Because we are coding to interfaces, we do not tightly couple the implementation.

  注意到这段代码里有一个 setOrderDao(),它就是一个DAO Object设置方法(注射器)。 但这里并没有一个getOrderDao的方法,这不必要,因为你并不会在外部访问这个orderDao。这个DAO Objecte将被调用,和我们的persistence layer 通信。我们将用Spring把DAO Object 和 business service object搭配起来的。因为我们是面向接口编程的,所以并不需要将实现类紧密的耦合在一起。

  注意上面的代码有一个为DAO对象准备的setter方法。这儿不是一个getOrderDAO方法因为它不是必要的,因为不太有从外面访问连着的OrderDAO对象的需要。DAO对象将被用来和我们的持久层沟通。我们将用Spring把业务服务对象和DAO对象连在一起。因为我们编码到接口,我们不会紧耦合实现。

The next step is to code our DAO implementation object. Since Spring has built-in support for Hibernate this example DAO will extend the HibernateDaoSupport class, which allows us to easily get a reference to a HibernateTemplate, which is a helper class that simplifies coding with a Hibernate Session and handles HibernateExceptions. Here is the interface for the DAO:

接下去我们开始我们的DAO的实现类进行编码。 既然Spring已经有对Hibernate的支持,那这个例子就直接继承HibernateDaoSupport类了,这个类很有用,我们可以参考HibernateTemplate(它主要是针对HibernateDaoSupport的一个用法,译注:具体可以查看Srping 的API)。 下面是这个DAO接口代码: 代码:

下一步是写我们的DAO实现对象。因为Spring有Hibernate内建的支持,这个例子DAO将继承HibernateDaoSupport类,它[译者注:英语语法问题:它是指“例子DAO”还是指“HibernateDaoSupport类”?]允许我们容易取得一个到HibernateTemplate的引用,HibernateTemplate是一个帮助类,它能简化Hibernate Session的编码和处理HibernateExceptions。这儿是DAO的接口:

public interface IOrderDAO {

  public abstract Order findOrderById(

                                    final int id);

  public abstract List findOrdersPlaceByUser(

                           final String placedBy);

  public abstract Order saveOrder(

                               final Order order);

}

We still have a couple more objects to wire together for our business layer. This includes the HibernateSessionFactory and a TransactionManager object. This is done directly in the Spring configuration file. Spring provides a HibernateTransactionManager, which will bind a Hibernate Session from the factory to a thread to support transactions (see ThreadLocal for more information). Here is the Spring configuration of the HibernateSessionFactory and the HibernateTransactionManager:

  我们仍然要给我们持久层组装很多关联的对象,这里包含了HibernateSessionFactory 和TransactionManager。 Spring 提供了一个 HibernateTransactionManager,他用线程捆绑了一个Hibernate Session,用它来支持transactions(请查看ThreadLocal) 。 下面是HibernateSessionFactory 和 HibernateTransactionManager:的配置:  代码:

  我们还有两个对象要和我们的业务层连在一起。这包括HibernateSessionFactory和一个TransactionManager对象。这在Spring配置文件里直接完成。Spring提供一个HibernateTransactionManager,它将从工厂绑定一个Hibernate Session到一个线程来支持事务(见ThreadLocal获取更多的信息)。这儿是HibernateSessionFactory和HibernateTransactionManager的Spring配置。

<bean id="mySessionFactory"

       class="org.springframework.orm.hibernate.

              LocalSessionFactoryBean">

  <property name="mappingResources">

    <list>

      <value>

        com/meagle/bo/Order.hbm.xml

      </value>

      <value>

        com/meagle/bo/OrderLineItem.hbm.xml

      </value>

    </list>

  </property>

  <property name="hibernateProperties">

    <props>

      <prop key="hibernate.dialect">

        net.sf.hibernate.dialect.MySQLDialect

      </prop>

      <prop key="hibernate.show_sql">

        false

      </prop>

      <prop key="hibernate.proxool.xml">

        C:/MyWebApps/.../WEB-INF/proxool.xml

      </prop>

      <prop key="hibernate.proxool.pool_alias">

          spring

      </prop>

    </props>

  </property>

</bean>

<!-- Transaction manager for a single Hibernate

SessionFactory (alternative to JTA) -->

<bean id="myTransactionManager"

         class="org.

                springframework.

                orm.

                hibernate.

                HibernateTransactionManager">

  <property name="sessionFactory">

    <ref local="mySessionFactory"/>

  </property>

  </bean>

Each object can be referenced in the Spring configuration within a <bean> tag. In this case the bean mySessionFactory represents a HibernateSessionFactory and the bean myTransactionManager represents a Hibernate transaction manager. Notice that the transactionManger bean has a property element called sessionFactory. The HibernateTransactionManager class has a setter and getter for sessionFactory, which is used for dependency injection when the Spring container starts. The sessionFactory property references the mySessionFactory bean. These two objects will now be wired together when the Spring container initializes. This wiring relieves you from creating singleton objects and factories for referencing and creating these objects, which reduces code maintenance in your application. The mySessionFactory bean has two property elements, which translate to setters for mappingResources and hibernatePropertes. Normally, this configuration would be stored in the hibernate.cfg.xml file if you were using Hibernate outside of Spring. However, Spring provides an easy way to incorporate the Hibernate configuration within the Spring configuration file. For more information see the Spring API.

 

  可以看出:每个对象都可以在Spring 配置信息中用<bean>标签引用。在这里,mySessionFactory引用了HibernateSessionFactory,而myTransactionManager引用了HibernateTransactionManage。 注意代码中myTransactionManger Bean有个sessionFactory属性。 HibernateTransactionManager有个sessionFactory setter 和 getter方法,这是用来在Spring启动的时候实现“依赖注入” (dependency injection)的。 在sessionFactory 属性里 引用mySessionFactory。这两个对象在Spring容器初始化后就被组装了起来了。 这样的搭配让你从 单例(singleton objects)和工厂(factories)中解放了出来,降低了代码的维护代价。 mySessionFactory.的两个属性,分别是用来注入mappingResources 和 hibernatePropertes的。通常,如果你在Spring之外使用Hibernate,这样的设置应该放在hibernate.cfg.xml中的。 不管怎样,Spring提供了一个便捷的方式-----在Spring内部配置中并入了Hibernate的配置。 如果要得到更多的信息,可以查阅Spring API。

  每一个对象能被Spring配置里的一个<bean>标记引用。在这个例子里,bean “mySessionFactory”代表一个HibernateSessionFactory,bean “myTransactionManager”代表一个Hibernate transaction manager。注意transactionManger bean有一个叫作sessionFactory的属性元素。HibernateTransactionManager有一个为sessionFactory准备的setter和getter方法,它们是用来当Spring容器启动时的依赖注入。sessionFactory属性指的是mySessionFactory bean。这两个对象现在当Spring容器初始化时将被连在一起。这种连接把你从为引用和创建这些对象而创建singleton对象和工厂中解放出来,这减少了你的应用中的代码维护。mySessionFactory bean有两个属性元素,它们转换到为mappingResources 和 hibernatePropertes的setter方法。通常,如果你在Spring外面使用Hibernate,这个配置将被保存在hibernate.cfg.xml文件中。然而,Spring提供一个容易的方法在Spring配置文件内合并Hibernate配置。获得更多的信息看Spring API.

相关资源

转自:http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=2 

 日记标题 (转帖)Wiring Your Web Application with Open Source Java(3)  作者: guest  创建时间: 2005-12-28 21:04:44  最近更新: 2005-12-28 21:05:26  编辑 我要评论  

内容

(由admin转自:http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=3)

Now that we have our container service beans configured and wired together we need to wire our business service object and our DAO object together. Then we need to wire these objects to the transaction manager.

既然我们已经组装配置好了Service Beans,就需要把Business Service Object和 DAO也组装起来,并把这些对象配到一个事务管理器(transaction manager)里。

现在我们已经配置了我们的容器服务beans和把它们连在了一起,我们需要把我们的业务服务对象和我们的DAO对象连在一起。然后,我们需要把这些对象和事务manager连起来。

 

Here is what this looks like in the Spring configuration file:

 在Spring中的配置信息:  代码:

这是在Spring配置文件里的样子:

<!-- ORDER SERVICE -->

<bean id="orderService"

  class="org.

         springframework.

         transaction.

         interceptor.

         TransactionProxyFactoryBean">

  <property name="transactionManager">

    <ref local="myTransactionManager"/>

  </property>

  <property name="target">

    <ref local="orderTarget"/>

  </property>

  <property name="transactionAttributes">

    <props>

      <prop key="find*">

     PROPAGATION_REQUIRED,readOnly,-OrderException

      </prop>

      <prop key="save*">

     PROPAGATION_REQUIRED,-OrderException

      </prop>

    </props>

  </property>

</bean>

<!-- ORDER TARGET PRIMARY BUSINESS OBJECT:

Hibernate implementation -->

<bean id="orderTarget"

         class="com.

                meagle.

                service.

                spring.

                OrderServiceSpringImpl">

  <property name="orderDAO">

    <ref local="orderDAO"/>

  </property>

</bean>

<!-- ORDER DAO OBJECT -->

<bean id="orderDAO"

         class="com.

                meagle.

                service.

                dao.

                hibernate.

                OrderHibernateDAO">

  <property name="sessionFactory">

    <ref local="mySessionFactory"/>

  </property>

</bean>

Figure 4 is an overview of what we have wired together. This shows how each object is related and set into other objects by Spring. Compare this with the Spring configuration file in the sample application to see these relationships.

图4 是我们对象搭建的一个提纲。 从中可以看出,每个对象都联系着Spring,并且能通过Spring注入到其他对象。把它与Spring的配置文件比较,观察他们之间的关系

图4是我们已经连在一起的东西的一个概览。它展示了每个对象是怎样被关联的和怎样被Spring设置进其它对象中。把这幅图和Spring配置文件在示例应用中对比看它们之间的关系。

Figure 4. This is how Spring will assemble the beans based on this configuration.

图 4. Spring就是这样基于配置文件,将各个Bean搭建在一起。

图4:这是Spring怎样将在这个配置的基础上装配beans。

This example uses a TransactionProxyFactoryBean, which has a setter for a transaction manager that we have already defined. This is a convenience object that knows how to deal with declarative transaction handling and your service objects. You can define how transactions are handled through the transactionAttributes property, which defines patterns for method names, and how they participate in a transaction. For more information about configuring isolation levels and commits or rollbacks on a transaction see TransactionAttributeEditor.

这个例子使用一个TransactionProxyFactoryBean,它定义了一个setTransactionManager()。 这对象很有用,他能很方便的处理你申明的事物还有Service Object。 你可以通过transactionAttributes属性来定义怎样处理。 想知道更多还是参考TransactionAttributeEditor吧。

这个例子使用一个TransactionProxyFactoryBean,它有一个为我们已经定义了的事务管理者准备的setter。这是一个方便的对象,它知道怎样处理声明的事务操作和你的服务对象。你可以通过transactionAttributes属性定义事务怎样被处理,transactionAttributes属性为方法名定义模式和它们怎样参与进一个事务。获得更多的关于在一个事务上配置隔离层和提交或回滚看TransactionAttributeEditor。

The class TransactionProxyFactoryBean also has a setter for a target, which will be a reference to our business service object called orderTarget. The orderTarget bean defines which business service class to use and it has a property which refers to setOrderDAO(). This property will populate the orderDAO bean that is our DAO object to communicate with our persistence layer.

TransactionProxyFactoryBean 还有个setter. 这会被我们 Business service object(orderTarget)引用, orderTarget定义了 业务服务层,并且它还有个属性,由setOrderDAO()引用。这个属性

TransactionProxyFactoryBean类也有一个为一个target的setter,target将是一个到我们的叫作orderTarget的业务服务对象的引用。 orderTarget bean定义使用哪个业务服务对象和有一个指向setOrderDAO()的属性。这个属性orderDAO bean将居于其中,orderDAO bean是我们的和持久层交流的DAO对象。

One more note about Spring and beans is that beans can operate in two modes. These are defined as singleton and prototype. The default mode for a bean is singleton that means that one shared instance of the bean will be managed. This is used for stateless operations like a stateless session bean would provide. The prototype mode allows new instances of the bean to be create when the bean is served through Spring. You should only use prototype mode when each user needs their own copy of the bean.

Spring 和Bean 的还有一点要注意的: bean可以以用两种方式创造。 这些都在单例模式(Sington)和原型模式(propotype)中定义了。 默认的方式是singleton,这意味着共享的实例将被束缚。 而原形模式是在Spring用到bean的时候允许新建实例的。当每个用户需要得到他们自己Bean的Copy时,你应该仅使用prototype模式。(更多的请参考设计模式中的单例模式和原形模式)

还有一个关于Spring和bean要注意的是bean能以两种模式运作。这两种模式被定义为singleton和prototype.为一个bean默认的模式是singleton,意味着一个共享的bean的实例将被管理。这是用于像一个无状态会话bean将提供的无状态操作。prototype模式允许当bean被通过Spring服务时新的bean的实例被创建。你应当仅仅在每一个用户需要他们自己的bean的拷贝时使用prototype模式。

Providing a Service Locator

Now that we have wired up our services with our DAO we need to expose our services to other layers. This is generally used from code in a layer such as UI that uses Struts or Swing. An easy way to handle this is with a service locator patterned class to return resources from a Spring context. This can also be done directly through Spring by referencing the bean ID.

提供一个服务定位器(Providing a Service Locator)

既然我们已经将我们的Serices和DAO搭配起来了。我们需要把我们的Service显示到其他层。 这个通常是在Struts或者Swing这层里编码。一个简单方法就是用 服务定位器返回给Spring context 。当然,可以通过直接调用Spring中的Bean来做。

下面是一个Struts Actin 中的服务定位器的一个例子。

 代码:

提供一个服务定位器

  现在我们已经把我们的服务和我们的DAO连起来了,我们需要暴露我们的服务给其它层。这通常被从在一个像在使用Struts或Swing的用户界面的层里的代码使用。一个处理这个容易的方法是使用一个服务定位器模式的类来从一个Spring上下文中返回资源。这也能通过Spring引用bean ID被直接完成。

Here is an example of how a service locator can be configured in a Struts Action:

这儿是一个服务定位器怎样能被配置在一个Struts Action中的示例:

public abstract class BaseAction extends Action {

  private IOrderService orderService;

  public void setServlet(ActionServlet

                                 actionServlet) {

    super.setServlet(actionServlet);

    ServletContext servletContext =

               actionServlet.getServletContext();

    WebApplicationContext wac =

      WebApplicationContextUtils.

         getRequiredWebApplicationContext(

                                 servletContext);

      this.orderService = (IOrderService)

                     wac.getBean("orderService");

  }

  protected IOrderService getOrderService() {

    return orderService;

  }

}

UI Layer Configuration

The UI Layer for the example application uses the Struts framework. Here we will discuss what is related to Struts when layering an application. Let's begin by examining an Action configuration within the struts-config.xml file.

UI 层配置 (UI Layer Configuration)

这个例子里UI层 使用了Struts framework. 这里我们要讲述一下在给程序分层的时候, 哪些是和Struts部分的。我们就从一个Struts-config.xml文件中的Action的配置信息开始吧。 代码:

用户界面层配置

  示例应用的用户界面层使用Struts框架。这儿我们将讨论当分层一个应用时和Struts相关的东西。让我们从检查在struts-config.xml文件里的一个Action配置开始。

  

<action path="/SaveNewOrder"

    type="com.meagle.action.SaveOrderAction"

    name="OrderForm"

    scope="request"

    validate="true"

    input="/NewOrder.jsp">

  <display-name>Save New Order</display-name>

  <exception key="error.order.save"

    path="/NewOrder.jsp"

    scope="request"

    type="com.meag

(转帖)Wiring Your Web Application with Open Source Java(3)

(由admin转自:http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=3)

[译者注:欢迎大家直接在这篇译文中修改和完善,并留下你的联系方式。]

Now that we have our container service beans configured and wired together we need to wire our business service object and our DAO object together. Then we need to wire these objects to the transaction manager.

现在我们已经配置了我们的容器服务beans和把它们连在了一起,我们需要把我们的业务服务对象和我们的DAO对象连在一起。然后,我们需要把这些对象和事务manager连起来。

 

Here is what this looks like in the Spring configuration file:

这是在Spring配置文件里的样子:

<!-- ORDER SERVICE -->

<bean id="orderService"

  class="org.

         springframework.

         transaction.

         interceptor.

         TransactionProxyFactoryBean">

  <property name="transactionManager">

    <ref local="myTransactionManager"/>

  </property>

  <property name="target">

    <ref local="orderTarget"/>

  </property>

  <property name="transactionAttributes">

    <props>

      <prop key="find*">

     PROPAGATION_REQUIRED,readOnly,-OrderException

      </prop>

      <prop key="save*">

     PROPAGATION_REQUIRED,-OrderException

      </prop>

    </props>

  </property>

</bean>

<!-- ORDER TARGET PRIMARY BUSINESS OBJECT:

Hibernate implementation -->

<bean id="orderTarget"

         class="com.

                meagle.

                service.

                spring.

                OrderServiceSpringImpl">

  <property name="orderDAO">

    <ref local="orderDAO"/>

  </property>

</bean>

<!-- ORDER DAO OBJECT -->

<bean id="orderDAO"

         class="com.

                meagle.

                service.

                dao.

                hibernate.

                OrderHibernateDAO">

  <property name="sessionFactory">

    <ref local="mySessionFactory"/>

  </property>

</bean>

Figure 4 is an overview of what we have wired together. This shows how each object is related and set into other objects by Spring. Compare this with the Spring configuration file in the sample application to see these relationships.

图4是我们已经连在一起的东西的一个概览。它展示了每个对象是怎样被关联的和怎样被Spring设置进其它对象中。把这幅图和Spring配置文件在示例应用中对比看它们之间的关系。

Figure 4. This is how Spring will assemble the beans based on this configuration.

图4:这是Spring怎样将在这个配置的基础上装配beans。

This example uses a TransactionProxyFactoryBean, which has a setter for a transaction manager that we have already defined. This is a convenience object that knows how to deal with declarative transaction handling and your service objects. You can define how transactions are handled through the transactionAttributes property, which defines patterns for method names, and how they participate in a transaction. For more information about configuring isolation levels and commits or rollbacks on a transaction see TransactionAttributeEditor.

这个例子使用一个TransactionProxyFactoryBean,它有一个为我们已经定义了的事务管理者准备的setter。这是一个方便的对象,它知道怎样处理声明的事务操作和你的服务对象。你可以通过transactionAttributes属性定义事务怎样被处理,transactionAttributes属性为方法名定义模式和它们怎样参与进一个事务。获得更多的关于在一个事务上配置隔离层和提交或回滚看TransactionAttributeEditor。

The class TransactionProxyFactoryBean also has a setter for a target, which will be a reference to our business service object called orderTarget. The orderTarget bean defines which business service class to use and it has a property which refers to setOrderDAO(). This property will populate the orderDAO bean that is our DAO object to communicate with our persistence layer.

TransactionProxyFactoryBean类也有一个为一个target的setter,target将是一个到我们的叫作orderTarget的业务服务对象的引用。 orderTarget bean定义使用哪个业务服务对象和有一个指向setOrderDAO()的属性。这个属性orderDAO bean将居于其中,orderDAO bean是我们的和持久层交流的DAO对象。

One more note about Spring and beans is that beans can operate in two modes. These are defined as singleton and prototype. The default mode for a bean is singleton that means that one shared instance of the bean will be managed. This is used for stateless operations like a stateless session bean would provide. The prototype mode allows new instances of the bean to be create when the bean is served through Spring. You should only use prototype mode when each user needs their own copy of the bean.

还有一个关于Spring和bean要注意的是bean能以两种模式运作。这两种模式被定义为singleton和prototype.为一个bean默认的模式是singleton,意味着一个共享的bean的实例将被管理。这是用于像一个无状态会话bean将提供的无状态操作。prototype模式允许当bean被通过Spring服务时新的bean的实例被创建。你应当仅仅在每一个用户需要他们自己的bean的拷贝时使用prototype模式。

Providing a Service Locator

Now that we have wired up our services with our DAO we need to expose our services to other layers. This is generally used from code in a layer such as UI that uses Struts or Swing. An easy way to handle this is with a service locator patterned class to return resources from a Spring context. This can also be done directly through Spring by referencing the bean ID.

提供一个服务定位器

  现在我们已经把我们的服务和我们的DAO连起来了,我们需要暴露我们的服务给其它层。这通常被从在一个像在使用Struts或Swing的用户界面的层里的代码使用。一个处理这个容易的方法是使用一个服务定位器模式的类来从一个Spring上下文中返回资源。这也能通过Spring引用bean ID被直接完成。

Here is an example of how a service locator can be configured in a Struts Action:

这儿是一个服务定位器怎样能被配置在一个Struts Action中的示例:

public abstract class BaseAction extends Action {

  private IOrderService orderService;

  public void setServlet(ActionServlet

                                 actionServlet) {

    super.setServlet(actionServlet);

    ServletContext servletContext =

               actionServlet.getServletContext();

    WebApplicationContext wac =

      WebApplicationContextUtils.

         getRequiredWebApplicationContext(

                                 servletContext);

      this.orderService = (IOrderService)

                     wac.getBean("orderService");

  }

  protected IOrderService getOrderService() {

    return orderService;

  }

}

UI Layer Configuration

The UI Layer for the example application uses the Struts framework. Here we will discuss what is related to Struts when layering an application. Let's begin by examining an Action configuration within the struts-config.xml file.

用户界面层配置

  示例应用的用户界面层使用Struts框架。这儿我们将讨论当分层一个应用时和Struts相关的东西。让我们从检查在struts-config.xml文件里的一个Action配置开始。

  

<action path="/SaveNewOrder"

    type="com.meagle.action.SaveOrderAction"

    name="OrderForm"

    scope="request"

    validate="true"

    input="/NewOrder.jsp">

  <display-name>Save New Order</display-name>

  <exception key="error.order.save"

    path="/NewOrder.jsp"

    scope="request"

    type="com.meagle.exception.OrderException"/>

  <exception key="error.order.not.enough.money"

    path="/NewOrder.jsp"

    scope="request"

    type="com.

          meagle.

          exception.

          OrderMinimumAmountException"/>

  <forward name="success" path="/ViewOrder.jsp"/>

  <forward name="failure" path="/NewOrder.jsp"/>

</action>

The SaveNewOrder Action is used to persist an order that the user submitted from the UI layer. This is a typical Struts Action; however, notice the exception configuration for this action. These exceptions are also configured in the Spring configuration file, applicationContext-hibernate.xml, for our business service objects in the transactionAttributes property. When these exceptions get thrown back from the business layer we can handle them appropriately in our UI. The first exception, OrderException, will be used by this action when there is a failure saving the order object in the persistence layer. This will cause the transaction to rollback and propagate the exception back through the business object to the Struts layer. The OrderMinimumAmountException will also be handled in a transaction within the business object logic that fails when the order placed does not meet the minimum order amount. Again, the transaction will rollback and this exception can be handled properly by the UI layer.

SaveNewOrder Action被用来持久化一个用户从用户界面层提交的订单。这是一个典型的Struts Action;然而,注意这个action的异常配置。这些异常为在transactionAttributes属性里的我们的业务服务对象也被配置在Spring配置文件里,applicationContext-hibernate.xml。当这些异常被从业务层掷回我们能在我们的用户界面里恰当的处理它们。第一个异常,OrderException,当在持久层里有一个保存订单对象失败时将被这个action使用。这当引起事务回滚和通过业务对象传递异常回Struts层。OrderMinimumAmountException在业务对象逻辑里的一个事务因为提交的订单达不到最小订单数量而失败也将被处理。然后,事务将回滚和这个异常能被用户界面层恰当的处理。

[注:由admin翻译上述部分2005年12月31日22:59分;由***在***修改了上述部分;由***在***修改了上述部分...请自行填写,以便联系]

The last wiring step is to allow our presentation layer to interact with our business layer. This is done by using the service locator that was previously discussed. The service layer acts as an interface to our business logic and persistence layer. Here is how the SaveNewOrder Action in Struts might use a service locator to invoke a business method:

最后一个连接步骤是允许我们的表现层和我们的业务层交互。这可以通过使用前面讨论的服务定位器来完成。服务层扮演一个到我们的业务逻辑层和持久层的接口。这儿是 在Struts中的SaveNewOrder Action怎样可能使用一个服务定位器调用一个业务方法:

public ActionForward execute(

  ActionMapping mapping,

  ActionForm form,

  javax.servlet.http.HttpServletRequest request,

  javax.servlet.http.HttpServletResponse response)

  throws java.lang.Exception {

  OrderForm oForm = (OrderForm) form;

  // Use the form to build an Order object that

  // can be saved in the persistence layer.

  // See the full source code in the sample app.

  // Obtain the wired business service object

  // from the service locator configuration

  // in BaseAction.

  // Delegate the save to the service layer and

  // further upstream to save the Order object.

  getOrderService().saveNewOrder(order);

  oForm.setOrder(order);

  ActionMessages messages = new ActionMessages();

  messages.add(

      ActionMessages.GLOBAL_MESSAGE,

new ActionMessage(

      "message.order.saved.successfully"));

  saveMessages(request, messages);

  return mapping.findForward("success");

}

Conclusion

This article covers a lot of ground in terms of technology and architecture. The main concept to take away is how to better separate your application, user interface, persistence logic, and any other application layer you require. Doing this will decouple your code, allow new code components to be added, and make your application more maintainable in the future. The technologies covered here address specific problems well. However, by using this type of architecture you can replace application layers with other technologies. For example, you might not want to use Hibernate for persistence. Since you are coding to interfaces in your DAO objects it should be apparent to you how you might use another technology or framework, such as iBATIS, as a substitute. Or you might want to replace your UI layer with a different framework than Struts. Switching UI layer implementations should not directly affect your business logic or your persistence layer. Replacing your persistence layer should not affect your UI logic or business service layer. Wiring a web application is not a trivial task but it can be made easier to deal with by decoupling your application layers and wiring it together with suitable frameworks.

结论

这篇文章按照技术和架构覆盖了许多话题。从中取出的主要思想是怎样更好的分离你所需要的应用层、用户界面层、持久逻辑层、和其它任何应用层。这样做将解耦你的代码,允许新的代码组件被加入,使你的应用在将来更加可维护。这里覆盖的技术较好的解决特定的问题。然而,使用这种架构你能用其它的技术代替应用层。例如,你也许不想使用Hibernate持久化。因为你在你的DAO对象中编码到接口,你可能怎样使用其它的技术或框架,比如 iBATIS,作为一个替代是显而易见的。或者你可能用不同于Struts的框架替代你的UI层。改变UI层的实现不会直接影响你的业务逻辑层或者你的持久层。替换你的持久层应该不会影响你的UI逻辑或业务服务层。连接一个web应用不是一个小的任务,但是,靠解耦你的各应用层和用适当的框架组成它,它能变得更容易处理。

Mark Eagle is a Senior Software Engineer at MATRIX Resources, Inc. in Atlanta, GA. 

Mark Eagle 是一位在MATRIX智囊团的高级软件工程师, Inc. in Atlanta, GA。

[注:由admin翻译完全文第一遍于2006年1月1日9:59分;由***在***修改了上述部分;由***在***修改了上述部分...请自行填写,以便联系

全文:

(转帖)Wiring Your Web Application with Open Source Java(1) (1篇) http://www.learndiary.com/disDiaryContentAction.do?goalID=1408

(转帖)Wiring Your Web Application with Open Source Java(2) (1篇)http://www.learndiary.com/disDiaryContentAction.do?goalID=1409

(转帖)Wiring Your Web Application with Open Source Java(3) (1篇)http://www.learndiary.com/disDiaryContentAction.do?goalID=1410]

(转帖)Wiring Your Web Application with Open Source Java(2)

(由admin转自:http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=2)

[译者注:欢迎大家直接在这篇译文中修改和完善,并留下你的联系方式。]

 

Wiring Together a Simple Example

Now that we understand the components from a high level, let's put this into practice. Again, for this example, we will combine the Struts, Spring, and Hibernate frameworks. Each one of these frameworks has too much detail to cover in one article. Instead of going into many details about each framework, this article will show how to wire them together with simple example code. The sample application will demonstrate how a request is serviced across each layer. A user of this sample application can save a new order to the database and view an existing order in the database. Further enhancements might allow the user to update or delete an existing order.

结合一个简单的例子

  现在,我们从一个高的层次理解了组件,让我们把这些用于实践。在这个例子中,我们将合并Struts、Spring、Hibernate框架。每一个这些框架在一篇文章中都有太多的细节覆盖到。这篇文章将用一个简单的例子代码展示怎样把它们结合在一起,而不是进入每个框架的许多细节。示例应用将示范一个请求怎样跨越每一层被服务。这个示例应用的一个用户能保存一个订单到数据库中和查看一个在数据库中存在的订单。进一步的提高也许允许用户更新或删除一个存在的订单。  

 

You can download the source code of the application.

你可以下载这个应用的源码。

First, we will create our domain objects since they will interoperate with each layer. These objects will allow us to define what should be persisted, what business logic should be provided, and what type of presentation interface should be designed. Next, we will configure the persistence layer and define object-to-relational mappings with Hibernate for our domain objects. Then we will define and configure our business objects. After we have these components we can discuss wiring these layers using Spring. Finally, we will provide a presentation layer that knows how to communicate with the business service layer and knows how to handle exceptions that arise from other layers.

  首先,我们将创建我们的领域对象因为它们将和每一层交互。这些对象将允许我们定义什么应该被持久化,什么业务逻辑应该被提供,和哪种表现界面应该被设计。然后,我们将配置持久层和为我们的领域对象用Hibernate定义“对象-关系”映射。然后,我们将定义和配置我们的业务对象。在有了这些组件后,我们能讨论和Spring把这些层连在一起。最后,我们将提供一个表现层,它知道怎样和业务服务层交流和知道怎样处理从其它层产生的异常。

Domain Object Layer

Since these objects will interoperate across all layers this might be a good place to start coding. This simple domain model will contain an object that represents an order and an object that represents a line item for an order. The order object will have a one-to-many relationship to a collection of line item objects. The example code has two simple objects in the domain layer:

com.meagle.bo.Order.java: contains the header-level information for an order.

com.meagle.bo.OrderLineItem.java: contains the detail-level information for an order.

Consider choosing package names for your objects that reflect how your application is layered. For example, the domain objects in the sample application can be located in the com.meagle.bo package. More specialized domain objects would be located in subpackages under the com.meagle.bo package. The business logic begins in the com.meagle.service package and DAO objects are located in the com.meagle.service.dao.hibernate package. The presentation classes for forms and actions reside in com.meagle.action and com.meagle.forms, respectively. Accurate package naming provides a clear separation for the functionality that your classes provide, allows for easier maintenance when troubleshooting, and provides consistency when adding new classes or packages to the application.

领域对象层

因为这些对象将和所有层交互,这也许是一个开始编码的好地方。这个简单的领域模型将包括一个代表一份订单的对象和一个代表一个订单项的对象。订单对象将和一组订单项对象有一对多的关系。例子代码在领域层有两个简单的对象:

com.meagle.bo.Order.java: 包括一份订单的概括信息;

com.meagle.bo.OrderLineItem.java: 包括一份订单的详细信息;

考虑为你的对象选择包名,它将反映你的应用是怎样分层的。例如:简单应用的领域对象可以放进com.meagle.bo包[译者注:bo-business object?]。更多专门的领域对象将放入在com.meagle.bo下面的子包里。业务逻辑在com.meagle.service包里开始,DAO对象被放进com.meagle.service.dao.hibernate包。对于forms和actions的表现类分别驻入com.meagle.action 和 com.meagle.forms包。准确的包命名为你的类提供的功能提供一个清楚的区分,考虑到当故障维护时更易于维护,当增加新的类或包给应用时提供一致性。

Persistence Layer Configuration

There are several steps involved in setting up the persistence layer with Hibernate. The first step is to configure our domain business objects to be persisted. Since Hibernate works with POJOs we will use our domain objects for persistence. Therefore the Order and OrderLineItem objects will need to provide getter and setter methods for all fields that they contain. The Order object would contain setter and getter methods such as ID, UserName, Total, and OrderLineItems in a standard JavaBean format. The OrderLineItem would similarly follow the JavaBean format for its fields.

Hibernate maps domain objects-to-relational databases in XML files. For our Order and OrderLineItem objects there will be two mapping files to express this. There are tools such as XDoclet to assist with this mapping. Hibernate will map the domain objects to these files:

Order.hbm.xml

OrderLineItem.hbm.xml

You will find these generated files in the WebContent/WEB-INF/classes/com/meagle/bo directory. The Hibernate SessionFactory is configured to know which database it is communicating with, the DataSource or connection pool to use, and what persistent objects are available for persistence. Session objects provided by the SessionFactory are the interface used to translate between Java objects and persistence functions such as selecting, saving, updating, and deleting objects. We will discuss configuring the SessionFactory that Hibernate requires to handle Session objects in a later section.

持久层配置

用Hibernate设置持久层涉及到几个步骤。第一步是配置我们的被持久化的领域对象。因为Hibernate和POJOs[译者注:Persistence Objects Java Objects?]一起工作,我们将使用我们的领域对象持久化。因此,订单和订单项对象将需要提供它们包括的所有的字段的getter和setter方法。订单对象将包括像ID、用户名、合计、和订单项这样一些字段的以一种标准的JavaBean的格式的setter和getter方法。订单项对象将同样的用JavaBean的格式为它的字段设置setter和getter方法。

  Hibernate在XML文件里映射领域对象到关系数据库。为我们的订单和订单项对象将有两个映射文件来表达这种映射。有像XDoclet这样的工具来帮助这种映射。Hibernate将映射领域对象到这些文件:

Order.hbm.xml

OrderLineItem.hbm.xml

你可以在WebContent/WEB-INF/classes/com/meagle/bo目录里找到这些生成的文件。Hibernate SessionFactory被配置来知道它正和哪种数据库交流、使用哪种数据源或连接池、什么持久的对象被持久化是有效的。被SessionFactory提供的Session对象是用于在Java对象和像选取、保存、更新、删除对象这样的一些持久化功能间的翻译的接口。我们将在后面的小节讨论配置Hibernate处理Session对象需要的SessionFactory。

Business Layer Configuration

Now that we have our domain objects we need to have business service objects that perform application logic, make calls to the persistence layer, take requests from the UI layer, deal with transactions, and handle exceptions. To wire all of this together and make this easy to manage we will use the bean management aspect of the Spring framework. Spring uses inversion of control (IoC), or setter dependency injection, to wire up objects that are referenced in an external XML file. Inversion of control is a simple concept that allows objects to accept other objects that are created at a higher level. This way your object is free from having to create objects and reduces object coupling.

Here is an example of an object creating its dependencies without IoC, which leads to tight object coupling:

Figure 2. Objects arranged without IoC. Object A creates objects B and C.

And here is an example with IoC that allows objects to be created at higher levels and passed into objects so that they can use the implementations directly:

Figure 3. Objects arranged with IoC. Object A contains setter methods that accept interfaces to objects B and C. This could have also been achieved with constructors in object A that accepts objects B and C.

业务层配置

  现在,我们有了我们的领域对象,我们需要有业务服务对象来执行应用逻辑、执行向持久层的调用、获得从用户界面层的请求、处理事务、处理异常。为了把所有这些连在一起使它易于管理,我们将使用Spring框架的bean管理方面的功能。Spring使用“控制反转”(IoC),或者“setter依赖注入”来把这些对象连好,这些对象在一个外部的XML文件中被引用。“控制反转”是一个简单的概念,它允许对象接受其它在一个高一些的层次创建的对象。使用这种方法,你的对象从必须创建其它对象中解放出来和减少对象耦合。

  这儿是个不使用IoC的对象创建它的从属对象的例子,这导致紧的对象耦合:

  图2:没有使用IoC的对象组织。对象A创建对象B和C。

  这儿是一个使用IoC的例子,它允许对象在一个高一些层次被创建和传进对象,所以它们能直接使用现存的对象:

  图3:对象使用IoC组织。对象A包含setter方法,它们接受到对象B和C的接口。这也可以用对象A里的接受对象B和C的构建器完成。

Building Our Business Service Objects

The setters we will use in our business objects accept interfaces that allow loosely defined implementations of the objects that will be set, or injected. In our case we will allow our business service object to accept a DAO to handle the persistence of our domain objects. While the examples in this article use Hibernate, we can easily switch implementations to a different persistence framework and inform Spring of the new implementation DAO object to use. You can see how programming to interfaces and using the dependency injection pattern loosely couples your business logic from your persistence mechanism.

Here is the interface for the business service object that is stubbed for a DAO object dependency:

建造我们的业务服务对象

  我们将在我们的业务对象中使用的setter方法接受接口,这些接口允许将被设置或者注入的对象的宽松实现。在我们这个例子里我们将允许我们的业务服务对象接受一个DAO去控制我们的领域对象的持久化。虽然在这篇文章的例子中使用Hibernate,我们可以容易的转换到一个不同的持久框架的实现,通知Spring使用新的实现的DAO对象。你将看见怎样编程到接口和使用“依赖注入”模式宽松耦合你的业务逻辑和你的持久化机制。

  这儿是业务服务对象的接口,它有一个DAO对象依赖的桩。[译者注:是setOrderDAO方法吗?]

public interface IOrderService {

  public abstract Order saveNewOrder(Order order)

    throws OrderException,

           OrderMinimumAmountException;

  public abstract List findOrderByUser(

                                     String user)

                           throws OrderException;

  public abstract Order findOrderById(int id)

                           throws OrderException;

  public abstract void setOrderDAO(

                             IOrderDAO orderDAO);

}

Notice that the code above has a setter for a DAO object. There is not a getOrderDAO method because it is not necessary since there is often no need to access the wired OrderDAO object from the outside. The DAO object will be used to communicate with our persistence layer. We will wire the business service object and the DAO object together with Spring. Because we are coding to interfaces, we do not tightly couple the implementation.

  注意上面的代码有一个为DAO对象准备的setter方法。这儿不是一个getOrderDAO方法因为它不是必要的,因为不太有从外面访问连着的OrderDAO对象的需要。DAO对象将被用来和我们的持久层沟通。我们将用Spring把业务服务对象和DAO对象连在一起。因为我们编码到接口,我们不会紧耦合实现。

The next step is to code our DAO implementation object. Since Spring has built-in support for Hibernate this example DAO will extend the HibernateDaoSupport class, which allows us to easily get a reference to a HibernateTemplate, which is a helper class that simplifies coding with a Hibernate Session and handles HibernateExceptions. Here is the interface for the DAO:

下一步是写我们的DAO实现对象。因为Spring有Hibernate内建的支持,这个例子DAO将继承HibernateDaoSupport类,它[译者注:英语语法问题:它是指“例子DAO”还是指“HibernateDaoSupport类”?]允许我们容易取得一个到HibernateTemplate的引用,HibernateTemplate是一个帮助类,它能简化Hibernate Session的编码和处理HibernateExceptions。这儿是DAO的接口:

public interface IOrderDAO {

  public abstract Order findOrderById(

                                    final int id);

  public abstract List findOrdersPlaceByUser(

                           final String placedBy);

  public abstract Order saveOrder(

                               final Order order);

}

We still have a couple more objects to wire together for our business layer. This includes the HibernateSessionFactory and a TransactionManager object. This is done directly in the Spring configuration file. Spring provides a HibernateTransactionManager, which will bind a Hibernate Session from the factory to a thread to support transactions (see ThreadLocal for more information). Here is the Spring configuration of the HibernateSessionFactory and the HibernateTransactionManager:

  我们还有两个对象要和我们的业务层连在一起。这包括HibernateSessionFactory和一个TransactionManager对象。这在Spring配置文件里直接完成。Spring提供一个HibernateTransactionManager,它将从工厂绑定一个Hibernate Session到一个线程来支持事务(见ThreadLocal获取更多的信息)。这儿是HibernateSessionFactory和HibernateTransactionManager的Spring配置。

<bean id="mySessionFactory"

       class="org.springframework.orm.hibernate.

              LocalSessionFactoryBean">

  <property name="mappingResources">

    <list>

      <value>

        com/meagle/bo/Order.hbm.xml

      </value>

      <value>

        com/meagle/bo/OrderLineItem.hbm.xml

      </value>

    </list>

  </property>

  <property name="hibernateProperties">

    <props>

      <prop key="hibernate.dialect">

        net.sf.hibernate.dialect.MySQLDialect

      </prop>

      <prop key="hibernate.show_sql">

        false

      </prop>

      <prop key="hibernate.proxool.xml">

        C:/MyWebApps/.../WEB-INF/proxool.xml

      </prop>

      <prop key="hibernate.proxool.pool_alias">

          spring

      </prop>

    </props>

  </property>

</bean>

<!-- Transaction manager for a single Hibernate

SessionFactory (alternative to JTA) -->

<bean id="myTransactionManager"

         class="org.

                springframework.

                orm.

                hibernate.

                HibernateTransactionManager">

  <property name="sessionFactory">

    <ref local="mySessionFactory"/>

  </property>

  </bean>

Each object can be referenced in the Spring configuration within a <bean> tag. In this case the bean mySessionFactory represents a HibernateSessionFactory and the bean myTransactionManager represents a Hibernate transaction manager. Notice that the transactionManger bean has a property element called sessionFactory. The HibernateTransactionManager class has a setter and getter for sessionFactory, which is used for dependency injection when the Spring container starts. The sessionFactory property references the mySessionFactory bean. These two objects will now be wired together when the Spring container initializes. This wiring relieves you from creating singleton objects and factories for referencing and creating these objects, which reduces code maintenance in your application. The mySessionFactory bean has two property elements, which translate to setters for mappingResources and hibernatePropertes. Normally, this configuration would be stored in the hibernate.cfg.xml file if you were using Hibernate outside of Spring. However, Spring provides an easy way to incorporate the Hibernate configuration within the Spring configuration file. For more information see the Spring API.

 

  每一个对象能被Spring配置里的一个<bean>标记引用。在这个例子里,bean “mySessionFactory”代表一个HibernateSessionFactory,bean “myTransactionManager”代表一个Hibernate transaction manager。注意transactionManger bean有一个叫作sessionFactory的属性元素。HibernateTransactionManager有一个为sessionFactory准备的setter和getter方法,它们是用来当Spring容器启动时的依赖注入。sessionFactory属性指的是mySessionFactory bean。这两个对象现在当Spring容器初始化时将被连在一起。这种连接把你从为引用和创建这些对象而创建singleton对象和工厂中解放出来,这减少了你的应用中的代码维护。mySessionFactory bean有两个属性元素,它们转换到为mappingResources 和 hibernatePropertes的setter方法。通常,如果你在Spring外面使用Hibernate,这个配置将被保存在hibernate.cfg.xml文件中。然而,Spring提供一个容易的方法在Spring配置文件内合并Hibernate配置。获得更多的信息看Spring API.

[注:由admin翻译上述部分2005年12月31日17:45分;由***在***修改了上述部分;由***在***修改了上述部分...请自行填写,以便联系] 

(转帖)Wiring Your Web Application with Open Source Java(1)

(由admin转自:http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html)

[译者注:欢迎大家直接在这篇译文中修改和完善,并留下你的联系方式。]

[注:这个翻译任务是从matrix的文档wiki那里看到的,我的英文水平只能勉强看懂,但是翻译它是一举三得:学技术、学英语、为网络学习作贡献,听说这篇文章在csdn上有人翻译了,可我就是没有找到,有人找到了在这里告诉一下,以免大家重复劳动。我采用从粗到精的翻译方法,先忽略细节,按我的理解粗翻一遍,然后再请大家指正,精确化细节问题。-admin ]

Tags: java spring struts hibernate programming

Bookmark with del.icio.us

 

Wiring Your Web Application with Open Source Java

by Mark Eagle

04/07/2004

用Java开源技术构建你的web应用

Building non-trivial web applications with Java is no trivial task. There are many things to consider when structuring an architecture to house an application. From a high-level, developers are faced with decisions about how they are going to construct user interfaces, where the business logic will reside, and how to persist application data. Each of these three layers has their own questions to be answered. What technologies should be implemented across each layer? How can the application be designed so that it is loosely coupled and flexible to change? Does the architecture allow layers to be replaced without affecting other layers? How will the application handle container level services such as transactions?

   创建一个不平凡的java的web应用不是一个平凡的任务,当为构建一个应用而建造一个构架时有许多问题需要考虑。从高层来说,开发者需要面对怎样构建用户界面-那里有业务逻辑在其中、和怎样持久化应用数据。这三层每一层都有它们各自的问题需要回答。跨越每一个层次什么技术应该被使用?怎样才能把程序设计得松耦合和比较容易修改?构建中一些层的替换不会影响到其它层?应用怎样处理容器级的服务,比如事务控制?

There are definitely a number of questions that need to be addressed when creating an architecture for your web application. Fortunately, there have been developers that have run into these reoccurring problems and built frameworks to address these issues. A good framework relieves developers from attempting to reinvent the wheel for complex problems; it is extensible for internal customization; and it has a strong user community to support it. Frameworks generally address one problem well. However, your application will have several layers that might require their own framework. Just solving your UI problem does not mean that you should couple your business logic and persistence logic into a UI component. For example, you should not have business logic with JDBC code inside of a controller. This is not the functionality that a controller was intended to provide. A UI controller should be a lightweight component that delegates calls to other application layers for services outside the UI scope. Good frameworks naturally form guidelines where code should be placed. More importantly, frameworks alleviate developers from building code such as persistence from scratch and allow them to concentrate on the application logic that is important to a client.

  当为你的WEB应用创建一个构架时,有相当多的问题需要考虑。幸运的是,有开发者已经冲锋陷阵到一些重复性的东西、建立框架解决这些问题。一个好的框架可以使程序员从为一个复杂应用重复发明轮子中解放出来;它应该是内核定义为可扩展的,有一个强大的用户群支持。框架通常能够很好的解决一方面的问题。然而,你的应用有许多层都需要它们各自的框架。就如解决你的用户界面并不意味着你应该把事务逻辑和持久化逻辑掺杂进你的用户界面组件。例如,你的控制器里面就不应该有包含jdbc代码的业务逻辑在里面,这不是控制器的功能。它应该是轻量级的,代理所有来自用户界面外的请求、调用其它服务这些请求的应用层。好的框架自然形成代码应该放在哪里的线索,更重要的是,框架减轻开发者写像持久层这样的代码的伤害,使他们专注于对客户来说很重要的应用逻辑。

This article will discuss how to combine several well-known frameworks to achieve loose coupling, how to structure your architecture, and how to enforce a consistent design across all application layers. The challenge is combining frameworks so that each layer is exposed to each other in a loosely coupled manner, regardless of the underlying technologies. This article will discuss one strategy for combining frameworks using three popular open source frameworks. For the presentation layer we will use Struts; for our business layer we will use Spring; and for our persistence layer we will use Hibernate. You should be able to substitute any one of these frameworks in your application and get the same effect. Figure 1 shows what this looks like from a high level when the frameworks are combined.

  这篇文章将怎样合并几个著名的框架去达成松耦合,怎样构建你的构架,怎样实施一个跨所有应用层的保持一致性的设计。挑战是合并这些框架使得每一层都以一种松耦合的方式暴露给彼此,而与底层的技术无关。这篇文章将讨论合并框架的策略使用3种流行的开源框架。表现层我们将使用Struts;业务层我们将使用Springt;持久层使用Hibrenate.你将能够在你的应用中替换这些框架中的任何一种而得到同样的效果。图1展示了当这些框架被合并时从高层看是什么样子。

Figure 1. Overview of framework architecture with Struts, Spring, and Hibernate.

图1用Struts, Spring, 和 Hibernate框架构建的概览

Application Layering

Most non-trivial web applications can be divided into at least four layers of responsibility. These layers are the presentation, persistence, business, and domain model layers. Each layer has a distinct responsibility in the application and should not mix functionality with other layers. Each application layer should be isolated from other layers but allow an interface for communication between them. Let's start by inspecting each of these layers and discuss what these layers should provide and what they should not provide.

应用的分层

大多数不平凡的web就用能被分成至少4个各负其责的层次。这些层次是:表现层、持久层、业务层、领域模型层。每层在就用中有分别的责任,不会和其它层混淆功能。每一应用层应该彼此独立但是在它们之间允许一个接口互相交流。让我们开始深入每一层和讨论这些层应该提供什么和不应该提供什么。

The Presentation Layer

表现层

[下面是卖书的广告]

Related Reading

 

Hibernate: A Developer's Notebook

By James Elliott

Table of Contents

Index

Sample Chapter

Read Online--Safari Search this book on Safari:

    

 Only This Book All of Safari

Code Fragments only

[/广告结束]

 

At one end of a typical web application is the presentation layer. Many Java developers understand what Struts provides. However, too often, coupled code such as business logic is placed into an org.apache.struts.Action. So, let's agree on what a framework like Struts should provide. Here is what Struts is responsible for:

  在一个典型的web应用的一端是表现层。许多java程序员懂得Struts提供什么。然而,太多的人把像业务逻辑之类的耦合的代码放进了一个org.apache.struts.Action。所以,让我们在像Struts这样一个框架应该提供什么上取得一致意见。这儿是Struts负责的:

Managing requests and responses for a user.

Providing a controller to delegate calls to business logic and other upstream processes.

Handling exceptions from other tiers that throw exceptions to a Struts Action.

Assembling a model that can be presented in a view.

Performing UI validation.

为用户管理请求和回应;

提供一个控制器代理业务逻辑调用和其它上游的处理;

处理从其它层掷出给一个Struts Action的异常;

装配一个能被呈现进一个视图的模型;

执行用户界面验证。

Here are some items that are often coded using Struts but should not be associated with the presentation layer:

Direct communication with the database, such as JDBC calls.

Business logic and validation related to your application.

Transaction management.

Introducing this type of code in the presentation layer leads to type coupling and cumbersome maintenance.

这儿是一些经常被使用Struts编写的而不应该和表现层相伴的项目:

直接和数据库沟通,比如JDBC调用;

业务逻辑和与你的应用相关的验证;

传输管理;在表现层中引入这种代码将导致类型耦合和讨厌的维护。

The Persistence Layer

At the other end of a typical web application is the persistence layer. This is usually where things get out of control fast. Developers underestimate the challenges in building their own persistence frameworks. A custom, in-house persistence layer not only requires a great amount of development time, but also often lacks functionality and becomes unmanageable. There are several open source object-to-relational mapping (ORM) frameworks that solve much of this problem. In particular, the Hibernate framework allows object-to-relational persistence and query service for Java. Hibernate has a medium learning curve for Java developers who are already familiar with SQL and the JDBC API. Hibernate persistent objects are based on plain-old Java objects and Java collections. Furthermore, using Hibernate does not interfere with your IDE. The following list contains the type of code that you would write inside a persistence framework:

持久层

在典型web应用的另一端是持久层。这通常是使事情很容易失控的地方。开发者低估了建造他们自己的持久层框架的挑战性。机构内部自己写的持久层不仅需要大量的开发时间,而且缺少功能和变得难以控制。有几个开源的“对象-关系映射”(ORM)框架非常解决问题。尤其是,Hibernate框架允许“对象-关系持久化”和Java查询服务。Hibernate对那些已经熟悉了SQL和JDBC API的Java开发者有一个适中的学习曲线。Hibernate持久对象是基于简单的老的Java对象和Java集合。此外,使用Hibernate不会被你的IDE干扰。下面的列表包含了将写在一个持久层框架里的代码类型:

[注:由admin翻译上述部分2005年12月28日22:40分;由***在***修改了上述部分;由***在***修改了上述部分...请自行填写,以便联系]

Querying relational information into objects. Hibernate does this through an OO query language called HQL, or by using an expressive criteria API. HQL is very similar to SQL except you use objects instead of tables and fields instead of columns. There are some new specific HQL language elements to learn; however, they are easy to understand and well documented. HQL is a natural language to use for querying objects that require a small learning curve.

查询相关的信息成为对象。Hibernate通过一种叫作HQL的面向对象的查询语言或者使用条件表达式API来做这个事情。HQL除了使用对象代替表、使用字段代替列外和SQL非常相似。有一些新的特殊的HQL语言元素要学;但是,它们非常容易理解和良好的文档化。HQL是一种使用来查询对象的自然语言,需要很小型的学习曲线。

Saving, updating, and deleting information stored in a database.

保存、更新、删除储存在数据库中的信息。

Advanced object-to-relational mapping frameworks like Hibernate have support for most major SQL databases, and they support parent/child relationships, transactions, inheritance, and polymorphism.

像Hibernate这样的高级“对象-关系”映射框架提供对大多数主流SQL数据库的支持,它们支持“父/子”关系、事务、继承和多态。

Here are some items that should be avoided in the persistence layer:

这儿是一些应该在持久里被避免的项目:

Business logic should be in a higher layer of your application. Only data access operations should be permitted.

业务逻辑应该在你的应用的一个高一些的层次里。持久层里仅仅允许数据存取操作。

You should not have persistence logic coupled with your presentation logic. Avoid logic in presentation components such as JSPs or servlet-based classes that communicate with data access directly. By isolating persistence logic into its own layer, the application becomes flexible to change without affecting code in other layers. For example, Hibernate could be replaced with another persistence framework or API without modification to the code in any other layer.

你不应该有持久层逻辑和你的表现层逻辑搅在一起。避免像JSPs或基于servlet的类这些在表现层里的逻辑和数据访问直接交流。靠把持久层逻辑隔离进它自己的层,应用变得易于修改而不会影响在其它层的代码。例如:Hebernate能够被其它持久层框架或者API代替而不会修改在其它任何层的代码。

The Business Layer

The middle component of a typical web application is the business or service layer. This service layer is often the most ignored layer from a coding perspective. It is not uncommon to find this type of code scattered around in the UI layer or in the persistence layer. This is not the correct place because it leads to tightly coupled applications and code that can be hard to maintain over time. Fortunately, several frameworks exist that address these issues. Two of the most popular frameworks in this space are Spring and PicoContainer. These are referred to as microcontainers that have a very small footprint and determine how you wire your objects together. Both of these frameworks work on a simple concept of dependency injection (also known as inversion of control). This article will focus on Spring's use of setter injection through bean properties for named configuration parameters. Spring also allows a sophisticated form of constructor injection as an alternative to setter injection as well. The objects are wired together by a simple XML file that contains references to objects such as the transaction management handler, object factories, service objects that contain business logic, and data access objects (DAO).

[注:糟糕,还没有接触过Spring和PicoContainer,这下面的翻译肯定是漏洞百出,还望大虾不吝赐教:)]

业务层

在一个典型的web应用的中间的组件是业务层或服务层。这个服务层从编码的角度是经常最容易被忽略的层。不难在用户界面层或者持久层里找到散布在其中的这种类型的代码。这不是正确的地方,因为这导致了紧耦合的应用和代码,有时难以维护。幸运的是,几个存在的框架征对这些问题。在这个领域两个最流行的框架是Spring和PicoContainer.这些叫作微容器,你可以不费力不费神的把你的对象连在一起。所有这些框架都工作在一个简单的叫作“依赖注入”(也通称“控制反转”)的概念上。这篇文章将着眼于Spring的为指定的配置参数通过bean属性的setter注入的使用。Spring也允许一个构建器注入的复杂形式作为setter注入的一个替代。对象们被一个简单的XML文件连在一起,这个XML文件包含到像事务管理器、对象工厂、包含业务逻辑的服务对象、和数据存取对象(DAO)这些对象的引用。

The way Spring uses these concepts will be made clearer with examples later in this article. The business layer should be responsible for the following:

Handling application business logic and business validation

Managing transactions

Allowing interfaces for interaction with other layers

Managing dependencies between business level objects

Adding flexibility between the presentation and the persistence layer so they do not directly communicate with each other

Exposing a context to the business layer from the presentation layer to obtain business services

Managing implementations from the business logic to the persistence layer

Spring使用这些概念的方法在这本书将在后面用例子说得更清楚一些。业务层应该负责下面这些事情:

处理应用业务逻辑和业务验证;

管理事务;

允许界面和其它层交互;

管理业务层对象之间的依赖;

增加在表现层和持久层之间的灵活性,使它们彼此不直接相互沟通;

从表现层暴露一个上下文给业务层获得业务服务;

管理从业务逻辑到持久层的实现。

The Domain Model Layer

Finally, since we are addressing non-trivial, web-based applications we need a set of objects that can move between the different layers. The domain object layer consists of objects that represent real-world business objects such as an Order, OrderLineItem, Product, and so on. This layer allows developers to stop building and maintaining unnecessary data transfer objects, or DTOs, to match their domain objects. For example, Hibernate allows you to read database information into an object graph of domain objects, so that you can present it to your UI layer in a disconnected manner. Those objects can be updated and sent back across to the persistence layer and updated within the database. Furthermore, you do not have to transform objects into DTOs, which can get lost in translation as they are moved between different application layers. This model allows Java developers to work with objects naturally in an OO fashion without additional coding.

领域模型层

最后,因为我们讨论不平凡的、基于web的应用,我们需要一组对象能在不同的层之间移动。领域对象层由那些代表真实世界业务对象,比如:一份订单、订单项、产品等等组成。这个层允许开发者停止建造和维护不必要的数据传输对象,或者DTOs,来匹配他们的领域对象。例如,Hibernate允许你把数据库信息读进领域对象的一个对象图,所以你能以一种分离的方式把它交给你的用户界面层。那些对象能被更新和送回到持久层在数据库里更新。进一步,你不必转换对象到DTOs,DTOs能在传输中迷路,因为他们在不同的应用层间移动。这种模式允许Java开发者自然地以一种面向对象的风格和对象一起工作,没有附加的编码。

[注:由admin翻译上述部分2005年12月30日20:57分;由***在***修改了上述部分;由***在***修改了上述部分...请自行填写,以便联系]