蘿卜青菜的BLOG

          路漫漫其修遠(yuǎn)兮,吾將上下而求索!~
          隨筆 - 21, 文章 - 10, 評(píng)論 - 6, 引用 - 0
          數(shù)據(jù)加載中……

          Ruby on Rails 和 J2EE:兩者能否共存?

          Ruby on Rails 是一個(gè)相對(duì)較新的 Web 應(yīng)用程序框架,構(gòu)建在 Ruby 語(yǔ)言之上。它被宣傳為現(xiàn)有企業(yè)框架的一個(gè)替代,而它的目標(biāo),簡(jiǎn)而言之,就是讓生活,至少是 Web 開(kāi)發(fā)方面的生活,變得更輕松。在本文中,Aaron Rustad 將對(duì) Rails 和傳統(tǒng)的 J2EE 框架在架構(gòu)上的一些關(guān)鍵特性進(jìn)行比較。

          Ruby on Rails 是一個(gè) Web 應(yīng)用程序框架,它的目標(biāo)是為應(yīng)用程序開(kāi)發(fā)提供一條易行道。實(shí)際上,框架的支持者們聲稱 Ruby on Rails 開(kāi)發(fā)人員的生產(chǎn)率最多是使用傳統(tǒng) J2EE 框架的 10 倍。(請(qǐng)閱讀“Rolling with Ruby on Rails”一文,以獲得關(guān)于這一聲明的更多內(nèi)容;請(qǐng)參閱 參考資料 )。雖然這句話造成了 Rails 和 J2EE 社區(qū)相當(dāng)大的爭(zhēng)議,但爭(zhēng)論中卻很少談及如何比較 Rails 和 J2EE 架構(gòu)。本文將使用企業(yè)應(yīng)用程序中常見(jiàn)的開(kāi)源工具,對(duì) Rails 框架和典型的 J2EE 實(shí)現(xiàn)進(jìn)行比較。

          什么是 Ruby on Rails?

          要想找到用一句話描述 Rails 的簡(jiǎn)單說(shuō)明,只需查看項(xiàng)目的 主頁(yè) 即可:

          Rails 是一個(gè)用 Ruby 編寫的全棧的(full-stack)、開(kāi)源的 Web 框架,可以使用它來(lái)輕松編寫實(shí)際的應(yīng)用程序,所需的代碼也要比大多數(shù)框架花在處理 XML 上的代碼少。

          雖然我不能保證框架確實(shí)會(huì)提供它所承諾的輕松快樂(lè),但是上面這句話確實(shí)很好地總結(jié)了 Rails 的品質(zhì)。全棧包括:Web 服務(wù)器、處理 HTTP 請(qǐng)求和響應(yīng)的框架,以及方便地把數(shù)據(jù)持久存儲(chǔ)到關(guān)系數(shù)據(jù)庫(kù)的框架。Rails 通過(guò)消除復(fù)雜的 XML 配置文件,使用 Ruby 語(yǔ)言的動(dòng)態(tài)性質(zhì),幫助把靜態(tài)類型語(yǔ)言中常見(jiàn)的許多重復(fù)代碼減少到最少,努力使開(kāi)發(fā)工作變得更容易。

          Rails 和典型的 J2EE Web 堆棧

          圖 1 比較了 Rails 堆棧和典型的 J2EE Web 堆棧(包括 Tomcat servlet 容器、Struts Web 應(yīng)用程序框架和 Hibernate 持久性框架)。



          圖 1. Rails 和 J2EE 堆棧的比較?
          Rails 和 J2EE 堆棧的比較?

          可以看到,Rails 堆棧和構(gòu)成普通的基于 J2EE 的 Web 應(yīng)用程序的組件之間的基本區(qū)別很小。兩者都有用來(lái)執(zhí)行應(yīng)用程序代碼的容器;都有幫助分離應(yīng)用程序的模型、視圖和控件的 MVC 框架;以及持久存儲(chǔ)數(shù)據(jù)的機(jī)制。

          MVC 框架

          模型-視圖-控制器(MVC)是應(yīng)用時(shí)間相當(dāng)長(zhǎng)、應(yīng)用面相當(dāng)廣的一個(gè)設(shè)計(jì)模式。它源自 Smalltalk;如今,幾乎所有的 GUI 框架,包括 Web 和胖客戶端,都以該框架為基礎(chǔ)。MVC 有三個(gè)部分:模型,負(fù)責(zé)業(yè)務(wù)邏輯,包括應(yīng)用程序狀態(tài)和將在這個(gè)狀態(tài)上執(zhí)行的動(dòng)作;視圖,用來(lái)渲染和向用戶呈現(xiàn)模型(在 Web 應(yīng)用程序中,視圖一般渲染為 HTML);控制器,定義應(yīng)用程序的行為。有關(guān) MVC 模式的詳細(xì)解釋,請(qǐng)參閱 參考資料

          前端控制器

          Struts 的 ActionServlet 和 Rails 的 DispatchServlet 都是前端控制器模式的例子;所以,它們提供了相同的功能。它們接受 HTTP 請(qǐng)求,解析 URL,把請(qǐng)求的處理轉(zhuǎn)發(fā)給適當(dāng)?shù)膭?dòng)作。在 Struts 中,動(dòng)作是擴(kuò)展自 Action 的類;對(duì)于 Rails,動(dòng)作是擴(kuò)展自 ActionController 的類。兩個(gè)前端控制器之間的主要區(qū)別是它們?nèi)绾螞Q定處理具體請(qǐng)求的動(dòng)作。

          使用 Struts,開(kāi)發(fā)人員需要把特定請(qǐng)求的映射外部化到 XML 配置文件中的 Action 類。當(dāng)首次裝入 ActionServlet 時(shí),它將解析這個(gè)文件,并準(zhǔn)備接受請(qǐng)求。根據(jù)約定,以 .do 結(jié)束的請(qǐng)求被重定向到 ActionServlet,由 ActionServlet 分派到適當(dāng)?shù)?Action 圖 2 的 XML 是一個(gè)典型的映射。它告訴 ActionServlet 把叫作 deleteOrder.do 的請(qǐng)求轉(zhuǎn)發(fā)到 controllers.order.DeleteOrderAction 作進(jìn)一步處理。

          Rails 采用了不同的方式。它沒(méi)有依賴配置文件把請(qǐng)求映射到某一個(gè)動(dòng)作,而是根據(jù)請(qǐng)求的 URL 發(fā)現(xiàn)適當(dāng)?shù)膭?dòng)作。從圖 2 可以看到,URL http://localhost/order/delete/4 告訴 Rails 調(diào)用 OrderController 實(shí)例上的 delete 方法,并將 4 作為可用的實(shí)例變量。Rails 足夠聰明,知道 /order 將映射到文件 order_controller.rb 中定義的一個(gè)控制器類。如果在控制器中定義了 find 方法,那么只要用 find 替代 URL 中的 delete,就可以調(diào)用這個(gè)方法。



          圖 2. Rails 和 Struts 中的 URL 映射?
          Rails 和 Struts 中的 URL 映射?

          動(dòng)作和模型

          在 Rails 和 Struts 中,動(dòng)作用來(lái)充當(dāng)前端控制器和模型之間的橋梁。開(kāi)發(fā)人員提供動(dòng)作的現(xiàn)實(shí),從而提供特定于應(yīng)用程序的請(qǐng)求處理。前端控制器負(fù)責(zé)接受請(qǐng)求,并把請(qǐng)求傳遞到特定動(dòng)作。圖 3 演示了 Rails 和 Struts 基本的動(dòng)作層次結(jié)構(gòu)。



          圖 3. Rails 和 Struts 的動(dòng)作層次結(jié)構(gòu)
          ?Rails 和 Struts 的動(dòng)作層次結(jié)構(gòu)
          動(dòng)作是模型還是控制器?

          Action ActionController 從技術(shù)上講是 MVC 模式的控制器的一部分,因?yàn)樗鼈儗?duì)客戶發(fā)起的事件進(jìn)行響應(yīng)。但是,在小型應(yīng)用程序中,開(kāi)發(fā)人員通常在這些類中對(duì)域或業(yè)務(wù)邏輯進(jìn)行編碼,所以在這些情況下,也可以把它們看作是模型的一部分。最佳實(shí)踐建議:應(yīng)當(dāng)把域邏輯從控制器中抽象出來(lái),放置在它自己的特定于域的類中。

          Struts 要求開(kāi)發(fā)人員擴(kuò)展 Action 并覆蓋 execute(),以處理請(qǐng)求。通常,每個(gè) Action 類都提供了非常具體的工作單元。 圖 3 演示了三個(gè)特定動(dòng)作:SaveOrderActionDeleteOrderActionListOrdersAction。前端控制器將調(diào)用 execute() 方法,傳遞給它許多有用的對(duì)象,其中包括 HTTP 請(qǐng)求和響應(yīng)對(duì)象。ActionForm 是一個(gè)類,它可以方便地向視圖來(lái)回傳輸并驗(yàn)證與表單有關(guān)的輸入,ActionMapping 包含映射的配置信息,就像 圖 2 的 XML 所描述的那樣。

          execute() 方法返回 ActionForward 對(duì)象,Struts 用這個(gè)對(duì)象來(lái)確定對(duì)請(qǐng)求繼續(xù)進(jìn)行處理的組件。一般來(lái)說(shuō),這個(gè)組件是一個(gè) JSP 頁(yè)面,但是 ActionForward 也能指向其他動(dòng)作。開(kāi)發(fā)人員必須清楚,Struts 創(chuàng)建的是 Action 的單一實(shí)例,并允許多個(gè)線程調(diào)用它的 execute()。這使請(qǐng)求處理變得更快,因?yàn)榭蚣芴幚砻總€(gè)請(qǐng)求時(shí)不用頻繁地創(chuàng)建新的 Action 實(shí)例。但是因?yàn)榭梢栽诙鄠€(gè)線程之間共享單一對(duì)象,所以必須遵守適當(dāng)?shù)木€程注意事項(xiàng),因?yàn)槠渌€程可能會(huì)破壞在這個(gè)動(dòng)作中保持狀態(tài)的實(shí)例變量。

          在 Rails 中,必須擴(kuò)展 ActionController::Base,讓模型參與到請(qǐng)求處理中。Rails 沒(méi)有將 ActionController 的實(shí)例池化;相反,它為每個(gè)請(qǐng)求創(chuàng)建新的實(shí)例。雖然這對(duì)性能可能有負(fù)面影響,但是它可以讓開(kāi)發(fā)變得更容易。開(kāi)發(fā)人員不需要關(guān)注 Struts 中存在的線程問(wèn)題,因此,會(huì)話、請(qǐng)求、標(biāo)題和參數(shù)都可以作為 ActionController 的實(shí)例成員來(lái)進(jìn)行訪問(wèn)。ActionController 還是一個(gè)將特定域邏輯的所有處理組合在一起的合理場(chǎng)所。Struts 的 Action 類是細(xì)粒度的,它提供了非常具體的工作單元,而 Rails ActionController 則是粗粒度的,它將具體的工作單元模擬為一些方法。

          清單 1 清單 2 分別演示了典型的 Struts 動(dòng)作和典型的 Rails 動(dòng)作

          表 1 提供了對(duì)兩種方法的邏輯流程的比較,并演示了清單 1 和清單 2 的特定行中發(fā)生的事情。研究 DeleteOrderActionexecute() 方法和 OrderControllerdelete 方法,可以看出它們基本上是相同的。



          表 1. execute() 和 delete 方法比較
          步驟 Struts Rails
          框架調(diào)用動(dòng)作 行 03: execute() 行 07: delete
          從請(qǐng)求中檢索到的 ID 行 06-07:從請(qǐng)求對(duì)象中取出 行 08:從所有參數(shù)的實(shí)例哈希中取出
          從數(shù)據(jù)庫(kù)刪除訂單記錄 行 09、14-24:調(diào)用 delete() 方法,用 Hibernate 刪除記錄 行 09:用 ActiveRecord 刪除記錄
          重定向到列出剩余訂單 行 11:ActionMapping 對(duì)象查找將要轉(zhuǎn)發(fā)處理的下一個(gè)組件。 圖 2 中的 XML 映射顯示,success 將映射到 /listOrders,這是另一個(gè) Action,負(fù)責(zé)查找剩余訂單,并以 JSP 的形式呈現(xiàn)它們 行 10:用將調(diào)用的下一動(dòng)作的哈希來(lái)調(diào)用 redirect_to 方法;在這種情況下,它只是調(diào)用同一控制器的 list 方法




          回頁(yè)首


          持久性框架

          持久性框架 用來(lái)在應(yīng)用程序?qū)雍蛿?shù)據(jù)庫(kù)之間來(lái)回移動(dòng)數(shù)據(jù)。Hibernate 和 Rails 的持久性框架可以歸類為對(duì)象/關(guān)系映射(ORM)工具,這意味著它們接受數(shù)據(jù)的對(duì)象視圖,并將該視圖映射到關(guān)系數(shù)據(jù)庫(kù)內(nèi)的表中。使用兩種框架的目的都是為了減少與關(guān)系數(shù)據(jù)庫(kù)有關(guān)的開(kāi)發(fā)時(shí)間。但是, 圖 4 演示了兩者在設(shè)計(jì)和配置上的一些根本區(qū)別。



          圖 4. Active Record 和 Hibernate 持久性框架的比較?
           Active Record 和 Hibernate 持久性框架的比較?

          Hibernate

          Hibernate 基于 Data Mapper 模式,在這種模式中,特定的映射器類 Session 負(fù)責(zé)在數(shù)據(jù)庫(kù)中持久存儲(chǔ)和檢索數(shù)據(jù)。Hibernate 可以持久存儲(chǔ)任何 Java 對(duì)象,只要這個(gè)對(duì)象符合 JavaBean 規(guī)范。XML 映射文件描述了如何將類映射到數(shù)據(jù)庫(kù)中具體的表,并描述了類與其他類的關(guān)系。

          清單 3 顯示了 Hibernate 映射文件的一個(gè)實(shí)例。class 標(biāo)簽把 Order 對(duì)象映射到 ORDERS 表,還有許多子標(biāo)簽用于描述其屬性、ID 訂單名稱,以及同 models.Item 的一對(duì)多關(guān)系。 清單 4 顯示了 Order 類本身。



          清單 3. Order.hbm.xml
          												...
          01 <hibernate-mapping>
          02    <class name="models.Order" table="ORDERS"
          03        dynamic-update="true" dynamic-insert="false"
          04        discriminator-value="null">
          05
          06 	<id name="id" column="id" type="java.lang.Long" 
          07             unsaved-value="null">
          08             <generator class="identity"/>
          09         </id>
          10 
          11         <set name="items" lazy="false" inverse="false"
          12            cascade="none" sort="unsorted">
          13             <key column="id"/>
          14             <one-to-many class="models.Item"/>
          15         </set>
          16 
          17         <property name="name" type="java.lang.String"
          18             update="true" insert="true"
          19             access="property" column="name"/>
          20     </class>
          21 </hibernate-mapping>
          
          										



          清單 4. Order.java
          												01 public class Order {
          02    private Set items;
          03     private String name;
          04     private Long id;
          05 
          06     public Long getId() { return id;}
          07 
          08     public void setId(Long id) { this.id = id;}
          09 	
          10     public Set getItems() { return items;}
          11 	
          12     public void setItems(Set items) { this.items = items; }
          13 	
          14     public String getName() { return name; }
          15 
          16     public void setName(String name) { this.name = name; }
          17 }
          
          										

          Active Record

          反射和元編程

          Wikipedia 中(請(qǐng)參閱 參考資料 )簡(jiǎn)要地把 反射 定義為“程序在運(yùn)行的時(shí)候檢查和修改其高級(jí)結(jié)構(gòu)的能力”。在那里,還將 元編程 定義為“編寫那些能夠編寫和操作其他其他程序(或它們自己),將其他程序作為自己的數(shù)據(jù)的程序,或者編寫那些完成其他程序在運(yùn)行時(shí)所做的部分工作的程序。”

          以下代碼將實(shí)現(xiàn)反射:

          																												01 obj = "some_string"
          02 if obj.respond_to?('length'):
          03   puts "obj length = #{obj.length}" 
          03 end
          >> obj length = 5
          
          																										

          這個(gè)代碼將實(shí)現(xiàn)元編程:

          																												01 class SomeClass
          02 end
          03 newMethod = %q{def msg() puts "A message!" end}
          04 SomeClass.class_eval(newMethod)
          05 aClass = SomeClass.new
          06 aClass.msg
          >> A message!
          
          																										

          Rails 的 ORM 框架叫作 Active Record,它基于同名的設(shè)計(jì)模式。Martin Fowler 將 Active Record 描述為“包裝數(shù)據(jù)庫(kù)表或視圖中數(shù)據(jù)行的對(duì)象,封裝數(shù)據(jù)庫(kù)訪問(wèn),在數(shù)據(jù)上添加域邏輯”。在 Rails 中,每個(gè)域?qū)ο蠖紝U(kuò)展提供 CRUD 操作的 ActiveRecord::Base

          與 Hibernate 一樣,Active Record 不需要映射文件;實(shí)際上,使用 Active Record 的開(kāi)發(fā)人員不需要對(duì) getter 或 setter、甚至類的屬性進(jìn)行編碼。通過(guò)一些漂亮的詞匯分析,Active Record 能夠判斷出,Order 類將映射到數(shù)據(jù)庫(kù)中的 ORDERS 表。使用 Ruby 反射和元編程的組合,表的列可以變成對(duì)象的屬性。訪問(wèn)器和調(diào)整器也添加了進(jìn)來(lái)。

          清單 5 顯示了 Order 類的完成后的代碼。在 Order 類體中有一行代碼定義了它與 Item 對(duì)象的關(guān)系。has_many 是一個(gè)靜態(tài)方法調(diào)用,符號(hào) :items 是它的參數(shù)。ActiveRecord 用 :items 發(fā)現(xiàn) Item 域?qū)ο螅缓髮⑦@個(gè) Item 對(duì)象映射回?cái)?shù)據(jù)庫(kù)中的 ITEMS 表。



          清單 5. order.rb
          												01 class Order < ActiveRecord::Base
          02	has_many :items
          03 end
          
          										

          清單 5 那樣編碼的 Order 類在運(yùn)行時(shí)提供了一些類和實(shí)例方法。表 2 提供了可在 Order 上使用的操作和屬性的部分列表:



          表 2. 在 Order 上可用的屬性和操作
          類方法 實(shí)例方法 屬性
          • find(*args)
          • find_by_sql(sql)
          • exists?(id)
          • create(attributes)
          • update(id, attributes)
          • update_all(updates, conditions
          • delete(id)
          • delete_all(conditions)
          • ...
          • add_items
          • build_to_items
          • create_in_items
          • find_all_in_items
          • find_in_items
          • has_items?
          • items
          • items=
          • items_count
          • remove_items
          • id
          • name




          回頁(yè)首


          結(jié)束語(yǔ)

          雖然 Ruby on Rails 是一個(gè)非常新、令人興奮的框架,并且在 Web 社區(qū)中已經(jīng)引起了人們相當(dāng)?shù)呐d趣,但是它的核心架構(gòu)仍然遵循在 J2EE 中發(fā)現(xiàn)的基本模式。開(kāi)發(fā)把兩個(gè)框架分開(kāi)的 Web 應(yīng)用程序是一種合理的方法。Rails 更喜歡清楚的代碼而不是配置文件,而 Ruby 語(yǔ)言的動(dòng)態(tài)性質(zhì)在運(yùn)行時(shí)生成了大部分管道 代碼。大多數(shù) Rails 框架都是作為獨(dú)立項(xiàng)目創(chuàng)建的,而且應(yīng)用程序開(kāi)發(fā)能夠從一組同類組件受益。相比之下,典型的 J2EE 堆棧傾向于構(gòu)建在通常獨(dú)立開(kāi)發(fā)的最好的組件之上,常常用 XML 進(jìn)行配置并將組件組合在一起。

          那么,是否應(yīng)該考慮對(duì)下一個(gè) Web 應(yīng)用程序使用 Rails 呢?嗯,為什么不呢?它是編寫得很好的組件堆棧,它們彼此之間工作得很好,并且基于行業(yè)接受的企業(yè)模式。Ruby 語(yǔ)言支持快速開(kāi)發(fā),并通過(guò)生產(chǎn)大多數(shù)應(yīng)用程序管道來(lái)添加到框架。熟悉 Java 世界中的 MVC 和 ORM 框架的人們?cè)谟?Rails 表達(dá)自己的思想時(shí)沒(méi)有任何困難。

          與 J2EE 一起分發(fā)會(huì)不會(huì)有利于 Rails?絕對(duì)不要。J2EE 是一個(gè)已經(jīng)設(shè)置好的標(biāo)準(zhǔn),有許多固定的實(shí)現(xiàn),而且,最重要的是,它是一個(gè)經(jīng)過(guò)驗(yàn)證的技術(shù)。我建議您下載一份 Rails 的副本,并開(kāi)始自己鉆研它。許多可用的教程都是介紹性的,這些教程可以讓您立即開(kāi)始使用 Rails。再次聲明,我并不能保證您會(huì)通過(guò)使用 Rails 得到快樂(lè),但是我敢打賭您會(huì)感到滿意。

          posted on 2006-11-27 17:10 蘿卜青菜 閱讀(146) 評(píng)論(0)  編輯  收藏 所屬分類: 技術(shù)類

          主站蜘蛛池模板: 蒙城县| 大田县| 富阳市| 桃园县| 巴南区| 叙永县| 哈巴河县| 西峡县| 通化市| 富源县| 牙克石市| 舞钢市| 白朗县| 临夏县| 江达县| 且末县| 额济纳旗| 平乐县| 闵行区| 新泰市| 鄂州市| 惠来县| 石阡县| 平乐县| 大同县| 准格尔旗| 尚义县| 福建省| 左云县| 溆浦县| 东明县| 安顺市| 密山市| 开阳县| 南汇区| 综艺| 奈曼旗| 巴林左旗| 五指山市| 余姚市| 开封县|