1、Jdon為什么會讓我們抓狂?
平安夜的狂歡過后,Jdon已經三歲了,已經到了5.1版本,作為中國的第一個java開源框架,相比很多胎死腹中的畸形胎兒(比如G-Roller等),可以算是非常健康長壽了,值得所有熱愛并從事著開源的人們學習、反思。
不知道為了什么?直到現在仍然還有人對他以及他的創始人抱有深深的偏見或者嫉恨。一個能讓這么多人抓狂的框架,如果你對他不了解,那真是一個遺憾。畢竟不是任何東西都能讓人抓狂的,而且是讓很多“牛”人們集體抓狂,更是不容易。是因為他確實太濫或者又他太優秀?是因為他侵犯了大家的利益還是他在給我們宣揚錯誤的思想及理念?或者都是,又或者又都不是,也許只有身在其中的人們才知道。
通過兩天對Jdon框架的應用體驗及源碼分析,今天從第三方的角度來審視Jdon,根據我所了解的Jdon的框架,談談我的認識及感受,希望能讓你對Jdon有一個全新的認識,又或者能為Jdon的發展做出一些小小的貢獻。
2、Jdon是什么
Jdon是什么?回答這個問題可以直接借助他的創始人板橋寫在其官方網站上的介紹:Jdon Framework(簡稱JF)是一套適合開發中小型J2EE/JavaEE應用系統的輕量Web框架(Lightweight Java Web Framework)。JF誕生于2004年底,是國人獨立開發的中國人自己的框架產品,2005年入選全球SUN公司網站java.net正式企業應用目錄。經過多年發展和眾多用戶的使用及其完善,JF已經發展成為一套成熟的、面向對象的、基于構件(基于組件)的輕量快速開發框架。Jdon是嚴格堅持分層架構(表現層、業務層和持久層)下的快速開發。JF是快速性和靈活性綜合平衡的產物,它帶來了多快好省的簡單的解決之道(simplify the best):對于小項目,使用Jdon框架可以開發出高質量可擴展的好的系統;對于大項目,使用Jdon框架可以更快地開發出系統。
也許現在看來這些特性都沒什么,但如果在當時,確是非常具有革命性的,用板橋的話:“顛覆對象使用之前必須創建的基本定律,正象無需關心對象銷毀一樣,您可以無需關心對象創建。”,“面向對象編程之父Grady Booch 說:對象最偉大處在于其可被替代。而Jdon框架偉大之處是幫助你替代這些對象,甚至包括Jdon框本身。”
板橋一下強調:“Jdon框架不是面向數據庫的;而是面向模型分析設計(OOA/OOD)。”
當然,孩子永遠是自家的好,我們不能只聽板橋說他如何我們就認為他怎樣?究竟這個框架是好還是差,耳聽為虛,眼見為實。既然都是開源項目,我們只需要下載他的源代碼看看,并跟同類的開源比較一下就知道。如果你跟我一樣,通過看他的文檔,閱讀他的代碼,你才會真正了解Jdon究竟是什么。
一個IOC框架
Jdon是一個IOC容器(板橋也算是最早把IOC的概念引入國內的少數牛人之一,并且能通過集成到jdon中向大家展示IoC的使用),這個IOC容器能實現自動按構造子注入組件所依賴的對象。這個Ioc需要配置的東西不多,比如:你只需要在一個類似jdonframework.xml的xml文件中寫類似下面的配置信息:
<services>
<pojoService name="testService" class="com.jdon.framework.test.service.TestServicePOJOImp"/>
</services>
你就能在你的Action中使用下面的代碼訪問這個testService
TestService testService = (TestService) WebAppUtil.getService("testService ", request);
testService.createUser(em);
當然,你必須要搞清楚的是,Jdon的Ioc實現并不是從頭開始實現了一個IoC,他是通過在picocontainer基礎上進行封裝實現的。
簡單的AOP及攔截器實現
基于面向切面的編程,可以把面向對象的方法不能很好解決的問題很輕松的解決掉。Jdon在aopalliance定義的API基礎上,實現了一個非常簡單的AOP,其實就是幾個類,使用代理實現了對方法的環繞攔截。雖然沒有AspejctJ及Spring的AOP強大,但對于應用80%的AOP需求,已經足夠。
Jdon立足中大型應用需求,充分發揮Java在企業應用開發中的優勢,考慮到性能等很多因素,Jdon框架還通過成功應用攔截器,實現了對象Cache、對象池等功能。你可以在一個像aspect.xml這樣的文件中配置你的攔截器,實現對一組一組的對象進行攔截:
<interceptor name="cacheInterceptor"
class="com.jdon.aop.interceptor.CacheInterceptor"
pointcut="services" />
JdonAOP攔截器目標對象組有三種:全部目標服務;EJB服務;POJO服務(EJB服務和POJO服務是在JdonFramework.xml中定義的ejbService和pojoService)
針對訪問EJB業務組件的封裝
Jdon充分考慮到在大型的分布式應用中,一些功能仍然必須依靠EJB這種重量級的業務組件來完成的現狀。相對于其它一些同類框架,從框架底層到最終應用都考慮到對EJB支持及簡化。比如針對EJB2的一個業務組件,可以直接配置成下面的形式:
<ejbService name="testService" >
<jndi name="TestEJB" />
<ejbHomeObject class="com.jdon.framework.test.ejb.TestEJBHome"/>
<ejbRemoteObject class="com.jdon.framework.test.ejb.TestEJBRemote"/>
<interface class="com.jdon.framework.test.service.TestService" />
</ejbService>
而在Action中使用的時候,還是像使用普通的pojoService一樣,WebAppUtil.getService方法即可獲得。
持久層數據訪問封裝
企業級應用80%都會涉及到數據庫的持久化。因此,Jdon提供了對持久層數據訪問的簡單封裝,提供了一個JdbcTemp類來執行數據庫操作,另外還提供了數據訪問層的DaoCRUD接口,以及一個Hibernate的實現,訪問我們使用Hibernate來進行對象持久化。
如下面的代碼使用Jdon中提供的jdbc模板類來操作數據庫:
//適合查詢返回結果是單個字段,如:
// select name from user where id=?
public Object querySingleObject(Collection queryParams, String sqlquery) throws Exception {
return jdbcTemp.querySingleObject(queryParams, sqlquery);
}
Struts1.x工具集合
Jdon在我看來有一點感覺是為使用Struts1.x開的人用的,因為他誕生的時候,struts1.x正處于鼎盛時期。因此,框架內部集成了很多開發struts1.x應用的實用工具,全部放在strutsutil及下面的包中,包含基于Struts1.x的通用業務處理如ModelDispAction、ModelListActionAction等,文件上傳封裝,基于Struts1.x的樹形組件以及自定義的分頁標簽等。如下圖所示:
一個圍繞Struts1.x+POJO(EJB) Service+Hibernate的快速開發框架
說到快速開發框架,我想大家都不陌生,JavaEE領由于涉及到的技術及選擇性太多,導致現在的快速開發框架可以說是五化八門,國際上比較知名的有appfuse,國內比較有名的有springside及easyjf等。而jdon在做那么多基礎性功能的情況下,也實現了一個快速開發框架。也許他的核心及目標也就是這個快速開發框架,他是最終能讓這個框架立竿見影的重要部分。
使用Jdon的快速開發框架,可以使用對象驅動的方式開發j2ee應用。Jdon框架中花了大量的精力及資源來解決模型CRUD的問題,整個框架中差不多一半的代碼都是為實現這個靈活、快速、基于對象驅動的快速框架而寫的。為了一個添刪改查,你只需要一個模型、一個業務組件、一個Form、兩個配置文件,就能實現一個非常簡單的添刪改查找應用。比如針對留言Message進行添刪改查,需要下面的內容:
域模型
public class Message extends Model {
private String messageId;
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
業務邏輯層
public interface MessageService {
public void createMessage(EventModel em);
public void updateMessage(EventModel em);
public void deleteMessage(EventModel em);
public Message getMessage(String messageId);
}
實現及DAO層的代碼這里省略。
一個Form(Struts1.x的產物):
public class MessageForm extends ModelForm {
private String messageId;
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
業務層配置文件jdonframework.xml
<models>
<!-- 配置模型的類是Message,其主鍵是messageId -->
<model key="messageId" class ="sample.model.Message">
<!-- 下行是配置界面模型MessageForm -->
<actionForm name="messageForm"/>
<handler>
<!-- 以下配置MessageService -->
<service ref="messageService">
<getMethod name="getMessage" />
<createMethod name="createMessage" />
<updateMethod name="updateMessage" />
<deleteMethod name="deleteMessage" />
</service>
</handler>
</model>
</models>
<services>
<!-- 以下配置MessageService -->
<pojoService name="messageService" class="sample.service.MessageServiceImp"/>
</services>
Struts-config.xml配置文件
<struts-config>
<form-beans>
<form-bean name="messageForm" type="sample.web.MessageForm" />
……
</form-beans>
…..
<plug-in className="com.jdon.strutsutil.InitPlugIn">
<set-property property="modelmapping-config" value="jdonframework.xml" />
</plug-in>
<action name="messageForm" path="/messageAction" type="com.jdon.strutsutil.ModelViewAction"
scope="request" validate="false">
<forward name="create" path="/message.jsp" />
<forward name="edit" path="/message.jsp" />
</action>
<action name="messageForm" path="/messageSaveAction" type="com.jdon.strutsutil.ModelSaveAction"
scope="request" validate="true" input="/message.jsp">
<forward name="success" path="/result.jsp" />
<forward name="failure" path="/result.jsp" />
</action>
</struts-config>
3、Jdon給了我們什么
看了上面的功能介紹,也許確實沒給你帶來更多的驚喜。但是想想如果你是三年前的今天看到這么多的介紹會是怎樣?也許那時候你才開始學hibernate,或者剛使用struts沒多久,又或者還在為什么是model2的web應用而困惑,更別說什么是IoC或AOP了。如果那時你知道國人有這么一個框架,使用了這么多先進的理念、引入了很多先進的技術、并且可以讓我們開發Struts應用基本上不用寫太多的java代碼,你會是什么樣的感受?
其實,也許就算你現在不用Jdon框架來做項目,作為一個開源愛好者,我仍然強烈推薦你去了解這個框架。因為他曾經帶給我們的是很多革命性的東西。而且,就算三年后的今天,也許你已經從一個java菜鳥變成了java小牛,但回頭了解Jdon框架中的很多東西,你會發現很多與你的代碼有著似曾相識的感覺。
Jdon框架中大量應用了設計模式,這是面向對象編程人員必須掌握的一門內功。通過ServiceFactory、ServiceFacade、ContainerDirector、ComponentVisitor、HttpSessionProxyVisitor、CommonsPoolAdapter、CommonsPoolFactory、WebServiceDecorator這些名字,一個一個的去了解、挖掘,一定會非常受益。
4、Jdon的代碼質量分析
Jdon的代碼質量總的來說是非常高的,不管是命名規范、代碼注釋或者是代碼結構等。整個框架根據要實現的功能模塊分成aop、businessproxy、controller、container、model、strutsutil、persistence、security等大包,框架的核心部件如容器ContainerWrapper、ContainerBuilder、組件描述TargetMetaDef、動作事件 Event、模型ModelIF等都是針對接口編程,具有一定的可擴展性。另外整個設計中使用到大量的設計模式,可讀性也非常強,想進一步提高OO水平的java開發人員值得進一步學習研究。
代碼的注釋有的是英文,有的是中文,這種中英文混合的方式有好處有壞處。好處是國人或老外都能看懂一點,壞處是不管對國人還是老外,都沒法讓他們徹底地搞懂。比如下面是ModelIF的代碼及注釋:
/**
* Base domain model it can be DTO or nested Model. it is the important message
* between business layer and view layer. in view layer, it is created by form
* object(such as ActionForm object);in business layer, it is created by
* business components(such as session bean).
*
* thi class can be cached, and setModified is important, this method can be
* used to refresh the cache.
*
* because setModified function ,so the class is designed for a class, but not a
* interface.
* the difference with setModified and setCacheable;
* setCacheable to false, the model will never exist in the cache.
* setModified to true, if the model exists in the cache, the client will not
* get it from cache, it is same as being deleted from cache .
* deleting the model from cache must have a condition that the deleting operator
* can access the cache of the container, if it cann't access the container,
* it cann't delete the model from cache. such it is EJB.
* @author banq
*/
public interface ModelIF extends Cacheable, Cloneable, Serializable {
/**
* in the past version, this method name is isCacheble,
* now change it after 1.3 !
*/
public boolean isCacheable();
/**
* in the past version, this method name is setCacheble,
* now change it after 1.3 !
*/
public void setCacheable(boolean cacheable);
public boolean isModified();
/**
* set the property has been modified such as : setName(String name){
* this.name = name; setModified(true); }
*
*/
public void setModified(boolean modified) ;
}
當然,既然是中國人,那么跟所有其它的中國人一樣,一個人寫這么多的代碼,難免也會出現一些小小的Bug及錯誤,特別是一些錯別字。比如說:ModelManager接口中的borrowtHandlerObject方法,又或者isCacheable寫成isCacheble,或者Jdbc操作模板類名稱叫JdbcTemp而不叫JdbcTemplate等;另外還有把test代碼沒有跟框架代碼分離,而是跟著框架核心代碼放在一起,比如ContainerDirectorTest等;還有很多核心的接口缺少注釋,比如ServiceAccessor等。
如果不是為了雞蛋里面挑骨頭,但我想這些不是應該成為這個框架不好的原因,畢竟這些問題我想Jdon并不是無法改進。
Jdon的代碼存放在sourceforge上面,使用cvs管理,任何人都可以從這個cvs上check out他的源代碼進行學習及改進。
5、Jdon還缺哪些?
前面已經說了很多Jdon的優點,但同樣是應用程序框架,Jdon為什么沒有能像Spring那樣火呢?為什么市場上關于Jdon的書基本上為零呢?為什么Jdon沒有得到企業的認可,并大量應用呢?
因此,Jdon應該是缺少一些東西,或者說是關鍵的東西。為什么同樣是開源,spring能得到那么多用戶的反饋、并不斷改進,而針對jdon的bug建議、用戶反饋卻寥寥無幾呢?是技術不行還是市場推廣不行?Jdon雖然發布到了5.0,但除了前面的一兩個版本,后續的版本都沒有帶來什么變革性的東西,難道是后勁不足?其實這些問題都值得我們每一個開源愛好者思考。本文只談談我對技術上覺得現在Jdon的存在的不足,以供大家參考。
設計上的問題
技術的進步是永無止盡的。Jdon框架的設計仍然還存在著很多的問題。比如,要求用戶領域模型繼承Jdon的Model類或實現ModelIF接口,添刪改查的業務實現類中要包含類似createXxx(EventModel em)這樣的方法,導致整個框架對業務層的東西侵入性太嚴重,不符合實際應用。另外,過多與Struts1.x緊密綁定的設計也不可取。
容器的改進
picocontainer有很多局限性,最要命的是不支持setter方法注入,這個通過實踐證明是用得最多的。picocontainer的自動注入應該是按類型注入的,在實際應用中也存在很多限制。比如下面的EmailDefine這樣的構造子可閱讀性是非常差的,如果存在多個這樣的構造子,稍不注意就會搞錯:
<component name="emailDefine"
class="com.jdon.jivejdon.service.imp.account.EmailDefine">
<constructor value="J道:用戶名和密碼"/>
<constructor value="您好:您索要的jdon.com網站登陸用戶和密碼如下:"/>
<constructor value="Jdon.com --- 解惑授道 專業的解決之道"/>
<constructor value="Jdon.com"/>
<constructor value="admin@jdon.com"/>
</component>
public class EmailDefine{
public EmailDefine(String s1, String s2, String s3, String s4, String s5){
}
}
因此,Jdon的IoC部份,需要增加針對setter方法注入的支持才行。
統一業務組件
Jdon中的業務組件包括“普通類服務pojoService”、“普通類component”、“EJB服務ejbService”等,不同的業務組件配置的方法還不一致,有的使用<pojoService>、有的使用<component>、有的使用<ejbService>,其實既然是松耦合,就應該是一致的。在一個應用中,又如何能完全區分出誰該扮演component、誰該叫service呢?另外攔截器還要在單獨的配置文件中進行配置,這樣會增加了配置及處理的復雜程度。下面是當前jdon中的一些配置片斷:
<pojoService name="testService" class="com.jdon.framework.test.service.TestServicePOJOImp"/>
<component name="jdbcDAO" class="com.jdon.framework.test.dao.JdbcDAO">
<constructor value="java:/TestDS"/>
</ component >
<context-param>
<param-name>containerConfigure</param-name>
<param-value>WEB-INF/mycontainer.xml</param-value>
</context-param>
……
<context-param>
<param-name>aspectConfigure</param-name>
<param-value>WEB-INF/myaspect.xml</param-value>
</context-param>
EJB服務
<ejbService name="testService" >
<jndi name="TestEJB" />
<ejbLocalObject class="com.jdon.framework.test.ejb.TestEJBLocal"/>
</ejbService>
<ejbService name="calculator" >
<jndi name="CalculatorEJB3" />
<interface class="com.jdon.framework.test.service.Calculator" />
</ejbService>
Annonation支持
EJB3、JPA以及整個JavaEE5都已經大量引入的java5的annonation來描述源數據,spring、struts2、hibernate以及國內的operamasks、easyjweb等框架也都大量引入了對annonation的支持,實踐證明annonation也是一個非常好的東西。而到上前為止,在這一方面jdon框架中還沒有看到有對annonation的支持。最好能把ejbService、pojoService及component等配置可以通過簡單的注解來實現,甚至cache、攔截器等也應該引入annonation的支持。
其它Web框架支持
雖然Struts1.x的市場仍然還是很大,但我們應該清醒地看到,今天已經有很多正在逐漸取代Struts1.x的Web框架出現,比如webwork(或struts2)、easyjweb、operamasks(jsf)、grails等。Jdon作為一個應用框架,要能獲得更多的應用支持,必須支持與這些框架進行集成,提供更多的支持,讓開發者有更多的選擇權。
持久層JPA支持
JPA不用質疑肯定是一個趨勢,spring、grails、appfuse、struts2、jsf等當前主流的框架都提供了對jpa全面的支持,并且把jpa作為java持久層的首選解決方法。另外, springside、easyjf等國內的開源組織,都已經在他們的框架中大量的使用到了jpa持久層技術。因此,Jdon也應該提供更多的對Jpa的支持。jdon現在所提供的對持久層的封裝顯得較單薄,很多時候無法滿足項目中需求。
過分EJB不一定是好事
EJB是一個好東西,但EJB3以后EJB從技術上來說應該就不算是什么東西了。三年前的Jdon考慮到當時對EJB的支持情況,過分考慮EJB的需求是對的。但都EJB都已經從重量變化輕量了,jdon框架中的很多為支持EJB而提供接口、方法等應該根據實現的情況作相應的調整、改進,不用再“過分EJB”。比如,下圖是Jdon中的TargetMetaDef組件定義核心接口的類結構圖:
6、寫在最后
也許真像就像我在
《中國java開源界最可愛的人們》中說過的一樣,Jdon現在給人有點高處不勝寒的感覺。然而我更希望的是Jdon不要停止前進的步伐,同時也希望更多人一起來為Jdon以后的發展、為國人的開源做出力所能及的貢獻。擁抱開源肯定是不會錯的,能投身到開源的事業中當然就會讓我們的職業生涯更加有意義的。
泡一杯清茶,細品Jdon中的代碼,他可以帶給你很多東西。程序是一種藝術,藝術不一定都實用,他能帶給我們藝術享受就已經足夠。
也許我們永遠都用不到這框架,也許幾年以后,你會發現編程的技術又有翻天覆地的變化,如果你發現你為這種變化做出了一些貢獻,你會感到非常欣慰。從這一點來說,我認為板橋無論如何肯定都是應該是快樂的。
版權聲明:本文版權由Blogjava的小雨開源所有,受法律保護。歡迎轉載,轉載請保留作者版權聲明及連接。
附:
其它相關背景資料:
- 2005年Jdon框架入選SUN公司的Java.net企業應用目錄(與AppFuse同列)。
- Jdon框架在全世界最大開源網站Sourceforge的項目網址
- 世界頂級Java網站TheServerSide有關Jdon框架 2004年新聞1 新聞2
- 2004年底Jdon框架剛推出時國內各種評論
- 時值2006年8月道友lhsail對Jdon框架的看法。
- 一位Jdon框架用戶的感言
- 對話Jdon
一個開源人的孤獨告白.
- 更多關于JdonFramework討論系列1 以及 討論系列2