J2EE(Java 2 Enterprise Edition)平台自从问世以来,就是众人瞩目的焦点。这一方面要归功于升阳以及其他协力厂商对于J2EE平台不遗余力的支援和行销,但另一方面来说,J2EE平台的技术规格在当时也是颇令人惊艳。它是一个标准化、跨平台的新技术,而且整合以下功能:
- ● 分散式交易(JTA/JTS)(注1)
- ● 分散式元件(EJB)
- ● 资料存取(JDBC)
- ● Message Queue(JMS)
- ● 权限控管(JAAS)
- ● 电子邮件(JavaMail)
- ● 网页技术(JSP/Servlet)
- ● Web Service
- ● EAI介面(JCA)
这些强大的技术规格如(图一)所示,在过去的几年独领风骚;然而,人的欲望是无止境的。功能面的强大已经无法抵消人们对于复杂度的忍受度,而J2EE平台的确是相当复杂而难以掌握的。
J2EE是为了企业级应用程式的需求而设计的,因此功能面讲求强大、稳定;付出的代价就是应用程式开发的复杂度。然而,现阶段的企业级应用程式除了要求强大与稳定之外,还特别讲求时效。以银行业为例,每当某家银行要针对某个信用卡客户群进行优惠专案,随之而来的结果可能就是要建置一个新的软体系统来搭配;像这样的软体系统,其开发的生命周期一定不长,否则就无法配合银行的行销造势活动。很明显地,我们需要一个能够保留J2EE强大稳定的优势,又能够让软体开发过程更顺畅的解决方案。
在接下来的篇幅里,我将为大家介绍一个叫做「Spring Framework」的J2EE应用程式框架;这个应用程式框架是由几位业界资深的J2EE专家为了简化J2EE应用程式开发而量身打造的;而个人在工作上的使用经验也验证了Spring Framework的确能够大幅简化J2EE应用程式开发的复杂度,相对的增加了产能,也让我们能够拥有更多的精力和时间来做更好的系统规划和设计。
Spring Framework
一位名为Rod Johnson的J2EE专家在2002年10月份出版了一本标题为「Expert One-on-One J2EE Design and Development」的书。这本书主要的内容是对于整个J2EE平台进行的一个「水能载舟,亦能覆舟」式的反省:我们使用J2EE的方式是否正确? Spring Framework的一些设计雏形就这样的形成了。经过了一年多的开发,Spring Framework 1.0的正式版终于在2004年的春天问世。Spring Framework的软体授权采用LGPL(注2),也就是我们一般常听到的开放原始码授权模式;在这样的开放模式之下,集结了众人心血结晶的Spring Framework到底有何过人之处呢?
核心哲学:POJO
POJO是Plain Old Java Object的缩写,说穿了就是一般的Java Class,而一个Class是一个物件导向软体系统当中最小的程式单位。 Spring Framework的核心哲学,就是希望程式设计师能够直接利用最单纯的方式撰写一般的Java Class程式。
这么做到底有什么好处?
如果您有开发过EJB,应该就很容易了解。一个EJB元件最基本的要求就是必须实做某些特殊的程式介面,如在Java当中描述物件规格的一种程式单位,才会被J2EE平台的实作J2EE Container,通常也称为Application Server辨识为一个合格的EJB元件。而这些介面却和EJB元件所应该提供的功能一点关系都没有,纯粹只是方便J2EE Container管理和取用的用途;除此之外,EJB元件无法在没有J2EE Container的状态下运作,更别说是要除错了。事实上,EJB元件的除错一直都是J2EE程式设计师的一个痛:哪怕是功能再简单的EJB,为了除错某个小功能,你必须不断启动像是IBM出产的Websphere或是BEA出产的Weblogic这样庞大的怪物,眼睁睁地看着它们耗尽你的系统资源。如果您是一位Java程式设计师,这样的场景描述是否有触动了你的心扉,拨动了你深沉的记忆呢?
在这里,Spring Framework所提供的价值就是,让你以最单纯的Java Class来进行程式开发,却仍然保留了EJB所提供的宣告式交易(Declarative Transaction)(注3)、宣告式权限控管( Declarative Authentication/Authorization),甚至,分散式交易(Distributed Transaction)的能力。于是,在程式的开发过程当中,你面对的是单纯的、可进行单元测试(注4)的POJO;在系统建置的最后阶段,再视需要来设定宣告式交易以及宣告式权限控管的功能即可。这样的作法一样可以提供能够和EJB相提并论的功能,但是却多了很多弹性。
让我们以生活中简单实际的例子做个比较吧!在现代的社会中,什么场合穿什么衣服是最起码的常识。我们假设有两个人,一个人的名字叫做EJB,另外一个人的名字叫做POJO,我们以一个简单的对照表来比较这两个人行为上的差异,请参考(表一)。
时间 行为 EJB POJO
23:00-07:00 睡觉 穿着西装打领带。因为怕 穿睡衣睡觉
把衣服弄皱而不敢乱动
07:00-18:00 上班 穿着西打领带 穿西装打领带
18:00-20:00 瑜珈 穿西装打领带。裤子因此 穿着短裤以及T-Shirt,行动自如
破裂
20:00-20:30 淋浴 穿西装打领带。衣服顺便 洗澡当然要脱光才能洗干净啊
一起洗了
我们可以看到,EJB不管是面对哪一种场合,都是用一套万年的西装来应对,而POJO却可以自由的针对不同的状况来选择不同的衣服,做出最舒适且合时宜的选择。
软体系统的开发,有时候就很像穿衣服:不同的场合和场景,有不同的需求和不同的适用性。 EJB有其适用的场合,但也有其不适用的场合;而Spring Framework所提供的POJO能针对任何场合选择其适用的「服装」的能力,相较之下就多了许多弹性。这弹性到底怎么来的?又是用什么技术来做到的呢?接下来,就让我为大家介绍让Spring Framework能够提供如此强大弹性的技术:AOP。
Spring Framework的核心技术:AOP
AOP是Aspect Oriented Programming的简称。在目前,所谓的OOP(Object Oriented Programming,物件导向)是软体开发界的显学,包括OOA(物件导向系统分析)、OOD(物件导向系统设计)以及OOP(物件导向程式设计)等;但是就像我们所熟知的历史一样,这世界上永远都会有改革进步的力量,而这股力量的名字就是AOP。但是值得注意的一点是:AOP并不是为了推翻我们所熟知的物件导向开发模式而产生的。相反的,AOP是为了要「补强」一些物件导向开发模式所可能带来的结构性缺陷而诞生的,如(图二)。
在一个典型的物件导向开发的软体专案当中,我们常常可以看到一个系统按照着物件导向的原则不断的被细分拆解成模组、元件以及类别。我们可能就此以为,以类别为基础的系统设计应该就已经是模组化的极致了─其实不然。随着时间我们会发现,系统中各类别常常会共同拥有某些特征,例如说交易控管、权限控管以及定时执行排程等所谓的Crosscutting Concern(横切关键点,暂译)会不断的重复出现在各类别的程式码当中。我们会赫然发现,其实可模组化的还有一种系统的Aspect(面向,也是AOP名称的由来);将这些Aspect从我们的物件导向程式码当中抽出,会让我们的程式码更简洁,更具有可设定性(Configurable),能够达到更进一步的模组化。
就拿刚刚所提到的交易控管作为例子吧!其实交易控管相关的程式码在各种企业应用系统当中应该是非常普遍的。一段程式码的逻辑如果有去更动到资料库的资料,为求资料的完整性,通常都会有交易控管的动作:
- STEP 1:宣告交易开始
- STEP2:进行一系列的资料处理动作
- STEP 3:如果发生错误则进行Rollback,资料回朔到进行交易之前的状态
- STEP 4:结束交易行为
如果我们可以将实作1、3、4步骤的程式码从原来的物件中抽离,这么一来我们的交易控管机制就可以交由一个专门的程式─称之为Aspect─来处理了!我们的程式码可以简洁许多,系统中做重功的程式码也变少。至于Aspect所使用的交易控管机制为何?这就让Aspect来自己来决定了。以此为前提,同一个物件有办法在不同的情况下,藉由套用不同的Aspect实作来享有各种层次的交易控管能力。例如,在一个简单的系统中,如果一个物件只处理来自单一的资料来源的资料,我们就可以让它使用实作JDBC API中预设提供的交易控管机制的Aspect;如果一样的物件被用在一个复杂的多资料来源环境当中,我们则可以让它使用实作JTS的Aspec。
图三当中的交易控管行为隐藏在一个很典型的方法呼叫method Invocation当中,每当UserApplication Instance呼叫aBusinessObject实体中的methodInvocation()方法时,Spring AOP所隐藏的交易控管机制就会启动。要让这个交易控管机制能运作,我们首先得决定要使用的交易管理实作。从(图三)的例子当中,我们可依不同的情况选用四种选择:
- Choice1:如果我们的系统当中只有单一的JDBC资料源,则可以使用DatasourceTransactionManager
- Choice2:如果我们利用Hibernate(注5)OR-Mapping(注6)的工具来实作系统物件的Persistence,则我们可以使用HibernateTransactionManager
- Choice3:如果我们使用了JDO来实作物件Persistence,则可以使用JdoTransactionManagerChoice4:如果我们的软体系统是要建置在一个多资料源的复杂环境下,则必须使用JtaTransactionManager
值得一提的是,Spring Framework使用了XML描述定义档(注7)来描述物件以及其使用的Aspect之间的关系(Pointcut)(注8),因此以上四种交易管理机制实作的切换完全不需要重新编译程式码;需要修改的就只有XML定义档而已。关于上述的范例设定档,有兴趣者请参考我在JavaTwo研讨会演讲的Powerpoint Slides,网址http://www.timerwell.com.tw/event/images/java2.ppt。
另举一个简单的例子:定时排程(Cronjob)。有些时候我们会想让某些程式区段定时的执行;有了Spring AOP的帮助后,撰写一个定时排程执行的程式变得相当容易,如下:
public class HelloworldJob {
public void sayHello() {
System.out.println( "Hello!" );}
}
我们在上述的程式码当中用了超级典型的入门级程式:Hello World。但是,要让Spring Framework能够和这段程式互动,还需要一些设定:
<beans>
(註10)'(注10)
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject"><ref bean="hello"/></property>
sayHello</value></property>'<property name="targetMethod"><valuesayHello</value></property>
</bean>
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">(注12)
'
</property>
<property name="cronExpression">
<value>0 6 * * 1</value>
</property>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">(注13)
<property name="triggers">
<list>
<ref local="cronTrigger"/>
</list>
</property>
</bean>
>"</beans>
上述的设定会在每天早上六点执行sayHello()这个方法。是不是很简单呢?
结论
进步的本质,理论上就是要让过去是很复杂的事情变得很简单。 Spring Framework就是拥有将复杂的J2EE简化的这种本质;或者,至少它为J2EE该往哪个方向发展开发出一条路。事实上,根据目前的蛛丝马迹来看,下一个改版的J2EE将会和目前Spring Framework所提供以POJO为开发重心的开发模式相当类似。所以我们可藉由使用Spring Framework的方式整合J2EE来品尝未来;至于J2EE未来的发展,就让我们拭目以待吧!
注1:「分散式交易」存在的目的是希望能够提供多重资料源的交易控管机制
注2:LGPL:是一种任何人都可以自由下载、使用并且更改该软体的程式码的授权模式;商业化的产品可自由的采用LGPL授权的软体,但是如果有牵涉到修改原始程式码的部份,则必须贡献回软体版权所有人。
注3:「宣告式交易」是一种将交易控管的能力从程式码中抽出,在程式码之外另外定义交易控管范围与机制的一种技术。
注4:单元测试是针对一个类别(Class)所进行的测试。这测试的目的是想确保该类别有满足设计规格的规范。
注5:Hibernate是非常强大的OR-Mapping工具,声势和使用者甚至超越了Java标准的OR-Mapping工具:JDO和EJB CMP Entity Bean。关于Hibernate的资讯,请参考http://hibernate.sf.net/
注6:OR-Mapping是一种让主流的关联式资料库能够呈现物件导向特性的一种技术。使用这种技术后,在程式设计师眼中,塞进资料库的不再是一笔一笔的资料,而是一个一个的物件
注7:Spring Framework以XML语法来描述物件之间的相依性,以及物件和Aspect之间的Pointcut定义。
注8:Pointcut是将Aspect和物件结合为一体的机制。 Pointcut描述了一个Aspect必须根据哪些规则内嵌到所对应的物件方法中。举例来说,一个合理的Pointcut描述可能是要求交易控管的Aspect必须内嵌到所有方法名称(method signiture)以do为开头的方法,例如doSomething()
注9:EJB和Spring所提供的「POJO导向应用程式开发」之间最大的差异,也就是适用性的差异。
注10:将HelloworldJob以hello的名称向Spring注册
注11:这个Spring所提供的工具类别会藉由AOP method interception的方式来乎叫我们HelloworldJob类别中的sayHello()方法
注12:cronTrigger中我们指定了cron job要排程执行的时间Pattern。 Unix-like系统的管理员应该对这部份相当熟析。
注13:把cronTrigger加入此类别,完成工作排程注册的动作。
|
|
?J2EE的核心规范是 Enterprise
Java Beans(EJBs)。 EJB依照特性的不同,目前共分为三种,分别是Session Bean、Entity Bean,以及
Message Driven Bean 。其中 Session Bean 与Entity Bean 算是EJB的始祖,这两种EJB规格在EJB
1.x版本推出时就已经存在,而Message Driven Bean则是出现在EJB 2.0的规格之中。相关介绍请见「Enterprise
Java Beans,EJB的三种特性???」一文。 |
|
EJB元件在J2EE规范中自成一层,把应用程式的表示层和后端资讯系统捆绑。而其物件可分为会话Beans、实体Beans以及讯息驱动Beans。你可在「?????细说EJB」一文中得到进一步的介绍。 |
|
到底什么是Spring Frameworks。在「作者简伯宇在JavaTwo
2004演讲入门级的Tutorial Powerpoint Slide 」一文为你做了相关的评析。 |
|
|
|