<o:p></o:p>
<o:p></o:p>
摘
要
使用Spring,你能够利用许多EJB所提供的特性,例如可申明的事务管理,对象池和简单的ORM(对象角色建模)等功能。在本文中,我们将要重点讨论的是如何将Spring技术应用在使用EJB构建的系统中,同时拥有Spring和EJB的优点。
关键词
Spring Hibernate Struts EJB SLSB Java Command Framework(JCF)<o:p></o:p>
1.
引言
<o:p></o:p>
开发大规模系统时,其复杂程度将大大增加。整个开发过程涉及到各种角色,例如
UI
设计人员,前台开发人员,后台开发人员,工作流开发人员,接口开发人员等。每个角色负责自己的任务,完成后再联调,或者是在开发过程中就已经开始了联调。如果将所有的代码都放到一块代码将会变得很乱,很难管理。尤其在系统间的信息沟通或者是将其他系统的功能增加到本系统的时候就要进行代码的拷贝,另外一种办法是通过远程访问来访问其他系统的功能,如果两个都是
java
应用就可以通过
EJB
的远程访问,如果是非
java
应用可以通过
web service
来远程访问。本文描述了一个基于
Spring
和
EJB
的通用调用框架,将
Spring
和
EJB
融合到一块,取其精华,去其糟粕。用
Spring
的
IOC
和
AOP
功能,使得系统的各个
Bean
之间解耦,而且很容易将事务和安全加到系统中。由于
EJB
的
Entity Bean
饱受争议,开发效率和运行效率都不太高,所以本框架不采用
Entity Bean
,采用
Hibernate
作为系统的持久层,
Spring
对
Hibernate
可谓是
Spring
的一大亮点了,使用
Srping
之后,
Hibernate
的开发更加简便了。在
Rod Johnson
和
Juergen Hoeller
所写的书《
Expert One-on-One J2EE without EJB
》中,狠狠的将
EJB
批了一通,但是在传统
J2EE
应用程序中,
EJB
构成了应用程序架构的基础。尽管
Spring
提供了
EJB
所提供的许多服务的简化版本,例如可申明的事务管理和对象持久性,但是,在一段时间内,许多应用程序将会继续使用
EJB
来构建。而且
EJB
中的
Session Bean
和
MDB
还是有其存在的价值,尤其是无状态会话
Bean
(
StateLess Session Bean
下文简称
SLSB
),简单得来使得系统具有分布式的功能。在
Spring
外再套一个
SLSB
使得系统天生就具有了远程访问的能力,再加上一个
Command
模式,
SLSB
变为系统功能调用的入口点,相应的业务逻辑都写在
Spring
控制的
Bean
中。而
MDB
可以开发异步调用系统。在
Spring
中,支持对
EJB
的调用,你能够在基于
EJB
的解决方案中使用
Spring
,
Spring
简化
EJB
的创建,提供一个简单,友好的方法来访问
EJB
资源。本框架不关注在
Spring
中如何调用
EJB
,而是关注于在
EJB
中如何访问
Spring
的
Bean
资源,如何将客户端的请求送到相应的
Spring
管理的
POJO
(
plain old Java object
)。
<o:p></o:p>
<o:p></o:p>
2.
项目背景
本
JCF
架构参考商务领航项目原有
JCF
实现。商务领航项目分为前台,工作流,后台三大模块,前台的请求通过工作流系统的调度来调用后台的业务方法,其中后台和工作流系统都提供了带有远程接口的
session bean
供其客户端程序调用。后台提供一个业务方法在系统中命名为“
Command
”,代表一个动作,若干个
Command
组成一个“
Service
”,客户端在一个请求
Request
中设入
service
名字和参数,经过服务端的运行后返回一个“
Response
”
,Response
中带有返回的结果。作者在开发的过程中发现原有
JCF
框架的开发过程中由于引入了
EJB
给测试带来了很大的麻烦,断点跟踪很难跟到
EJB
后面的
Command
,而且配置文件比较繁琐,在三大模块联调的时候浪费了很多的人力物力。现引入
Spring
以减少测试带来的时间耗费,减少了代码量,并且引进了目前流行的
ORM
工具
Hibernate
。其体系结构图如下:
<v:shapetype id="_x0000_t75" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" filled="f" stroked="f" coordsize="21600,21600" o:spt="75"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" o:extrusionok="f" gradientshapeok="t"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype>
<v:shape id="_x0000_i1025" style="WIDTH: 459pt; HEIGHT: 295.5pt" o:ole="" type="#_x0000_t75"></v:shape>
图
1 JCF
框架体系结构图
本框架综合运用
Delegate
、
Session façade
、
Command
等设计模式,把商业逻辑放到客户端
(servlet,applet,
等等
)
有严重的负面效果,影响性能和可维护性,使用
session facade
模式可以纠正这个问题,需要把商业逻辑放到
session bean
中,
session bean
的每个方法映射到一个特定的工作单元,或者用例。这样做,客户端被从服务器端的对象模型屏蔽起来,并且在一个事务和一次网络调用的
round trip
中执行用例。
直接从客户端调用
session facade
会导致客户端和服务器之间的依赖
(
在一个大型项目和复杂的客户端代码中
)
,因为对
EJB
的紧耦合,如
Business Delegate
模式所讨论的。这些问题能被用
business delegate
解决,增加一个封装所有对
ejb
层的存取的对象层。
business delegate
能帮助让客户端代码简单,使客户端和服务器之间的依赖最小。
然而,用
session facade
和
business delegate
开发会导致长期的变化
->
发布
->
测试的
round-trip,
会成为大型项目的瓶颈。问题的关键是商业逻辑放在一个
session bean
层,几乎是重量级的开发。使用
Command
模式来封装商业逻辑到轻量级的
command bean,
使客户端从
EJB
解耦,在一个网络调用中执行,作为
EJB
层的一个
façade
。用
Spring
来管理这些
Command
,这些
Command
就作为一个
Spring Beans
被管理起来。这样做有以下好处:
1.
因为轻量级的开发/
分发过程,方便了RAD
;<o:p></o:p>
2.
把商业逻辑从表示逻辑分离;<o:p></o:p>
3.
使客户端从ejb
解耦;<o:p></o:p>
4.
命令(command)
可以本地执行或产生哑(dummy)
数据;<o:p></o:p>
5.
用上Srping
的声明式的事务和Spring Acegi
安全支持;<o:p></o:p>
6.
灵活的错误处理措施;
7.
command
是无状态的,一个
round trip
可以执行若干个
Command
,组成一个工作流程
Processor
,该
Processor
共享一个状态。
<v:imagedata o:title="" src="file:///C:\DOCUME~1\HEWENQ~1\LOCALS~1\Temp\msohtml1\01\clip_image001.emz">
<v:shapetype id="_x0000_t75" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" filled="f" stroked="f" coordsize="21600,21600" o:spt="75"> <v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" o:extrusionok="f" gradientshapeok="t"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><v:shape id="_x0000_i1025" style="WIDTH: 459pt; HEIGHT: 295.5pt" o:ole="" type="#_x0000_t75"><v:imagedata o:title="" src="file:///C:\DOCUME~1\HEWENQ~1\LOCALS~1\Temp\msohtml1\01\clip_image001.emz"></v:imagedata></v:shape></v:imagedata>