日期:2014-05-19  浏览次数:20717 次

设计一个简单的service-oriented(面向服务)的J2EE应用
    这篇文档翻译自 http://www.javaworld.com/javaworld/jw-10-2004/jw-1004-soa_p.html?page=1 ,这个文档的时间是 04年的,所以从今天的角度来看,原文的观点未必全部正确,但是作者用一个如此简单的例子来阐述了SOA,我想对SOA的理解还是有一定帮助的。

yananay@126.com
2007年6月




现在大家都有一个共识,就是开源的项目会对大家的项目有所帮助:Structs,Spring,Hibernate,Tiles,Avalon,WebWorks,Tapestry,Oracle ADF,等等还有很多很多。但是许多人也发现这些东西并非解决问题的万灵药,因为“开放源代码”并非就意味着它们很容易被修改和改进。
当你面对一个某一个专业领域时,那么最好的办法是,基于某些framework来创建自己的framework。不过,如果要作一个像structs那样的framework,实在是不容易的事,但是如果要在structs或者其他framework上进行封装,那就容易得多了。
在这个文档里,我将演示如何创建一个framework,我给它起个名字叫x18p(xiangnong 18 palm,降龙十八掌)。这是一个简单的framework,通过这个framework,我们来看一看目前被许多j2ee framework 所忽视的2个方面:紧耦合与肿胀的DAO代码。
正如你所看到的,x18p这个framework会基于structs,spring,Axis,Hibernate等等其他开源framework。我们当然更希望您能通过这个文档,来提高自己搭建framework的能力,并且在更多的项目中来逐渐完善它。

我开发的过程遵循了RUP(IBM Rational Unified Process)。步骤如下:

1、 确定一个简单的目标
2、 分析现存的j2ee架构,并且找出问题的所在
3、 比较众多的framework,然后选择其中一个比较合适的而且简单的
4、 编写代码,并且持续重构
5、 多和使用framework的开发人员交流,并且获得反馈
6、 测试,测试,还是测试


确定一个简单的目标

我们要有一个伟大的目标,我们要设计一个framework来解决一切可能出现的问题。如果你有足够的资源,那这个目标可真是一个好想法。
不过,通常老板们认为,在你的项目开始之前去设计一个framework,这可是一个看不见商业价值的消耗。为了降低不可预见的风险,愉快地工作,降低学习曲线,保证项目的利益,根据我多年的j2ee的经验,这个我们可以分成2个部分来完成。
1、 降低j2ee Action 部分的偶合性
2、 降低j2ee中DAO层的重复代码

总的来说,我想提供优秀质量的代码,并且降低项目的成本和维护成本。所以,我会用对这个2个部分分别用上面提到的6个步骤来实现。


降低代码的耦合度
1. 分析以往的j2ee架构

如果我们手头有一个j2ee framework,我们首先必须知道如何才能改进它。光说是没用的,我们还是先来看看一个典型的j2ee架构 structs 吧!



Action 调用 xxxManager, xxxManager 又调用 xxxDAOs。可以看出,在一个典型的structs架构中,我们会涉及到如下的元素:

? HttpServlet 或者 Action,用来传递HttpRequest 或者 HttpResponse
? Business logic层
? 数据访问层(DAO)
? 领域层(Domain)

上面的架构有什么问题?问题就是:紧耦合。如果Action中的逻辑很简单,那么没有任何问题。那么如果你要访问一些EJB呢?如果你要通过不同的资源调用web服务呢?如果你需要访问JMX呢?
通过 structs-config.xml,Structs 有这样的能力去帮助你实现这些功能吗?答案是:不能。Structs 仅仅是一个web端的framework,不过如果你在action 里编写调用一些其他服务的代码也不是不可以,但那样做的话,就导致在Action的execute()方法里混合了2种类型的代码。哪2种代码呢?

第一种就是web段的,如 HttpRequest/ HttpResponse。对于一次调用来说,你可以从HttpRequest或者Actionform里获得提交的数据,你也可以把数据放到HttpResquest里或者Session里,然后在jsp里显示它。

第二种代码就是业务逻辑的。在Action,你也可以调用后台的代码,如EJB,JMX,甚至去操作JDBC的数据源。你也可以使用“定位服务”的模式去加载一些业务逻辑类,当然也可以生成一个POJO如xxxManager。虽然有很多方式,但是都有一个缺点,就是Action必须考虑后台对象的类型。

但这就是Action的工作方式,难道不是吗?Action其实就是servlet,它负责从request/response里得到数据,同时也负责把数据放到 request/response或者session里,用于在jsp里显示。它同时也是和业务逻辑层交互的一个桥梁 — 从业务逻辑层里得到数据或者更新数据。不过,Action并不考虑以什么方式或者协议来和业务逻辑层联系。

或许你可以想象,你可以结束Action和业务逻辑层这种紧耦合的现状。
这就是我们要解决的问题。在众多的开源framework中,spring 进入了我的视野。


2. 比较、选择framework

Spring 的核心被称作 BeanFactory。它不同于以往的服务定位模式,它有一个新名词,叫 IOC(Inversion-of-Control 控制反转),这个特性之前被称作“Injection Denpendency”(依赖注入)。其思想就是通过调用 ApplicationContext的getBean方法来得到一个对象,这个方法从Spring的配置文件里寻找对象的定义,然后创建这个对象,然后以 java.lang.Object 的类型返回这个对象。用“getBean”方法是一个查找对象的好办法。这意味着在 Action中,我们只需要引用一个ApplicationContext 就可以了。不过这并不是重点,因为我们还必须把得到的对象转换成正确的类型,如EJB,或者JMX。这么一来,Action仍然需要考虑后台对象的类型 — 这仍然是紧耦合。

如果我们要避免这一点,那么该如何做?很自然的,service(服务),这个词出现在我的脑海里。Service 是一个广泛的概念,任何东西都可以被称作service,而不仅仅是那个名字就叫作 web-service的service。Action 也可以把一个EJB当作service,也可以把一个JMX当作service。我想我们设计一个service才是正确的途径。

随着战略的清晰,我们通过分析进一步降低了风险,我们将要发挥我们的创造力,去创建一个service 层来演示这个“面向服务”的内容!

3. 代码和重构

为了把“面向服务”这个概念变成可以运行的代码,我们必须考虑以下这些事情:

? service层将会存在于web层和业务逻辑层之间。
? web层仅仅调用 service层的控制类,service层的控制类会根据x18p-config.xml 来调用不同的“服务提供者”。
? “服务提供者”可以去调用相应的服务,这里的服务可以是任何类型的,EJB,JMX,LDAP,等等。X18p-config.xml 必须提供足够的数据来让“服务器提供者”完成每次调用。
? 使用Spring来实现对象的查找和引用。
? 持续增加“服务提供者”。正如你所看到的,“服务提供者”类型越多,我们的x18p framework就越有威力!
? 使用现有的structs的知识,但是不要漏掉新出现的知识。

现在,我们比较一下在使用了x18p framework前后的Action代码:
public ActionForward execute(ActionMapping mapping, ActionFo