再译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

Author: test

供游客使用的测试帐号

One thought on “再译Wiring Your Web Application with Open Source Java”

  1. 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是用来持久化UI层里的表单提交过来Order的。这是Struts中一个很典型的Action; 注意观察这个Action中exception配置,这些Exceptions也在Spring 配置文件(applicationContext-hibernate.xml)中配置了(就在 business service object 的transactionAttributes属性里)。 当异常在业务层被被抛出时,我们可以控制他们,并适当的显示给UI层。 第一个异常,OrderException,在持久层保存order对象失败的时候被触发。这将导致事物回滚并且通过BO把异常回传到Struts这一层。 第二个异常,OrderMinimumAmountException也同第一个一样。

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

    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:

    搭配整和的最后一步 通过是让你显示层和业务层相结合。这个已经被服务定位器(service locator)实现了(前面讨论过了), 这里服务层作为一个接口提供给我们的业务逻辑和持久层。 SaveNewOrder Action 在Struts中用一个服务定位器(service locator)来调用执行业务方法的。 方法代码如下:  代码:

    最后一个连接步骤是允许我们的表现层和我们的业务层交互。这可以通过使用前面讨论的服务定位器来完成。服务层扮演一个到我们的业务逻辑层和持久层的接口。这儿是 在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层(转换久层,实现层并不应该直接影响到你的业务逻辑和业务服务层)。 用适当的框架搭建你的Web应用,其实也不是一件烦琐的工作,更主要的是它“解耦”了你程序中的各个层。

    结论

    这篇文章按照技术和架构覆盖了许多话题。从中取出的主要思想是怎样更好的分离你所需要的应用层、用户界面层、持久逻辑层、和其它任何应用层。这样做将解耦你的代码,允许新的代码组件被加入,使你的应用在将来更加可维护。这里覆盖的技术较好的解决特定的问题。然而,使用这种架构你能用其它的技术代替应用层。例如,你也许不想使用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。

Comments are closed.