轉載本文需注明出處:EAII企業架構創新研究院,違者必究。如需加入微信群參與微課堂、架構設計與討論直播請直接回復公眾號:“EAII企業架構創新研究院”。(微信號:eaworld)
1,背景知識;
1.1)了解Rest是什么?
1.2)了解JAX-RS是什么?
1.3)RestEasy簡介
2,手把手教你使用Resteasy;
3,揭秘Resteasy的實現原理;
4,總結;
一、Rest簡介及Resteasy產生背景
1.1)了解Rest是什么:
REST是英文RepresentationalState Transfer 的縮寫,有中文翻譯為“具象狀態傳輸”。REST 這個術語是由 RoyFielding 在他的博士論文《Architectural Styles and the Design ofNetwork-based Software Architectures 》中提出的。REST并非標準,而是一種開發 Web 應用的架構風格,可以將其理解為一種設計模式。REST 基于 HTTP,URI,以及 XML 這些現有的廣泛流行的協議和標準,伴隨著 REST,HTTP 協議得到了更加正確的使用。
相較于基于 SOAP 和 WSDL 的 Web 服務,REST 模式提供了更為簡潔的實現方案。目前,越來越多的 Web 服務開始采用 REST 風格設計和實現,真實世界中比較著名的 REST 服務包括:Google AJAX 搜索 API、Amazon Simple Storage Service (AmazonS3) 等。
基于 REST 的 Web 服務遵循一些基本的設計原則:
1)系統中的每一個對象或是資源都可以通過一個唯一的 URI 來進行尋址,URI 的結構應該簡單、可預測且易于理解,比如定義目錄結構式的 URI。
2)以遵循RFC-2616 所定義的協議的方式顯式地使用 HTTP 方法,建立創建、檢索、更新和刪除(CRUD:Create, Retrieve, Update and Delete)操作與 HTTP 方法之間的一對一映射:
若要創建資源,應該使用 POST方法, URI : xxx/book(在服務器端新建圖書信息,需提供該圖書所有信息)
若要檢索某個資源,應該使用 GET 方法, URI:xxx/book/{ID} (從服務器端獲得某圖書信息)
若要更改資源狀態或對其進行更新,應該使用 PUT 方法,URI:xxx/book/{ID}(在服務器端更新某已存在的圖書信息,需提供更新的內容)
若要刪除某個資源,應該使用 DELETE 方法, URI :xxx/book/{ID} (從服務器端刪除某圖書信息)
URI 所訪問的每個資源都可以使用不同的形式加以表示(比如 XML 或者 JSON),具體的表現形式取決于訪問資源的客戶端,客戶端與服務提供者使用一種內容協商的機制(請求頭與 MIME 類型)來選擇合適的數據格式,最小化彼此之間的數據耦合。
1.2) 了解JAX-RS是什么?
Java EE 6 引入了對 JSR-311 的支持。JSR-311(JAX-RS:JavaAPI for RESTful Web Services)旨在定義一個統一的規范,使得 Java 程序員可以使用一套固定的接口來開發 REST 應用,避免了依賴于第三方框架。同時,JAX-RS 使用 POJO 編程模型和基于標注的配置,并集成了JAXB,從而可以有效縮短 REST 應用的開發周期。
JAX-RS是一套用java實現REST服務的規范,提供了一些標注將一個資源類,一個POJOJava類,封裝為Web資源. 這些標注包括以下:
@Path:標注資源類或方法的相對路徑。
@GET,@PUT,@POST,@DELETE:標注方法是用的HTTP請求的類型。
@Produces:標注返回的MIME媒體類型。
@Consumes:標注可接受請求的MIME媒體類型。
@PathParam,@QueryParam,@HeaderParam,@CookieParam,@MatrixParam,@FormParam:分別標注方法的參數來自于HTTP請求的不同位置,例如@PathParam來自于URL的路徑,@QueryParam來自于URL的查詢參數,@HeaderParam來自于HTTP請求的頭信息,@CookieParam來自于HTTP請求的Cookie。
更通俗些說如果你用java寫了一套框架,當開發者自己寫的JAVA類使用了JAX-RS定義的這些注解標注過,然后通過你寫的這套框架就可以將有這些JAX-RS標注的類發布成web資源,供其他客戶端程序去調用。那么你寫的這套框架就是一套RestFul Web Service框架,就是JAX-RS規范的實現者之一,是JAX-RS標準定義的這些標注的解釋執行者。
目前比較流行的JAX-RS實現有以下幾種:
Apache CXF,開源的Web服務框架開源組織Apache的實現。Jersey,由Sun提供的JAX-RS的參考實現。RestEasy,JBoss的JAX-RS的實現。
與其他幾個框架相比較而言,RestEasy以其高性能,輕量級,簡單易上手,高可靠性和穩定性以及易于與其他容器集成等特點,越來越受到開發人員的歡迎。
1.3)Resteasy簡介:
RESTEasy是JBoss的一個開源項目,提供一套完整的框架幫助開發人員構建RESTful Web Service和RESTful Java應用程序。它是JAX-RS 2.0規范的一個完整實現并通過JCP認證,通過Http協議對外提供基于Java API的 RestFul Web Service。
RestEasy可以運行在任何Servlet容器中,作為JBoss的官方實現它可以更好的和Jboss服務器緊密融合從而提供更好的用戶體驗。
作為JAX-RS的標準實現,RestEasy還具有以下亮點特性:
1)不需要配置文件,只要把JARs文件放到類路徑里面,添加 @Path等標注就可以了
2)完全的把 RESTEeasy 配置作為Seam 組件來看待
3)HTTP 請求由Seam來提供,不需要一個額外的Servlet
4)Resources 和providers可以作為Seam components (JavaBean or EJB),具有全面的Seaminjection,lifecycle, interception, 等功能支持
5)支持在客戶端與服務器端自動實現GZIP解壓縮
6)支持異步請求處理
7)支持多種數據傳輸格式: XML, JSON, YAML, Fastinfoset, Multipart, XOP, Atom
……
二、手把手教你使用Resteasy
Resteasy的配置方法有很多種,本節內容是為了給下節講解RestEasy原理做個鋪墊,便于大家理解其實現原理,所以使用了RestEasy最基礎的配置方式,其他配置方法大家可以去官網找到相關資料。
RestEasy的配置使用非常的簡單,現在我們通過一個 Demo來看一下如何使用RestEasy。
新建一個JAVA Web工程: 我使用了Maven來創建webapp項目:
引入依賴包:pom.xml 配置如下:
新建Java 資源類,并添加相應的注解;(要發布成rest服務的類)
配置web.xml,添加使用Resteasy將資源類發布成rest服務的能力,配置如下:
驗證,啟動服務器打開瀏覽器訪問:
http://localhost:8080/resteasydemo/path1/subpath/123
出現以上結果說明通過Resteasy發布 Rest服務成功.怎么樣 SoEasy吧。
三、揭秘Resteasy的實現原理
通過上面的Demo相信大家都已經學會如何使用Resteasy把一個JavaBean發布成Rest服務了,接下來我們結合Demo一起來看一下Resteasy的實現原理。
我本人研究Resteasy實現原理的方法是:通過上面這個Demo來調試閱讀Resteasy的源碼進而理解其實現原理。
首先要發布restful的service要解決以下幾個問題:
1) 誰來接受來自客戶端的請求,并進行分發交給對應的對象的方法去處理。
2) 負責處理客戶端請求的對象由誰來負責產生(上面Demo中的TestRest對象)。
3) 如何解析Java類上面的JAX-RS注解,使客戶端過來的請求可以找到對應的對象的方法去執行。
帶著上面的三個問題我們來看一下Resteasy是如何設計實現來解決上面的問題的。
在上面的Demo中要把TestRest發布成Rest服務首先在web.xml文件中做了以下配置:
其中ResteasyBootstrap作為監聽器是拉起Resteasy服務的入口,在服務啟動時主要做了以下動作:
1)通過ListenerBootstrap組件讀取在web.xml文件中的一些系統配置信息,創建ResteasyDeployment對象,并將這些配置信息初始化到該對象中,其中就包括將”resteasy.resources”中配置的資源類的路徑初始化到其成員變量resourceClasses中;
2)通過調用ResteasyDeployment的start()方法,并根據相關配置信息初始化Resteasy的核心組件ResteasyProviderFactory ,Dispatcher,Registry.
3)最關鍵的部分是調用registration(),在該方法中會遍歷之前在web.xml中配置的資源并將其注冊到Registry中, 以Demo中的例子來看會遍歷resourceClasses中配置好的TestRest資源路徑,并加載該類然后通過調用registry.addPerRequestResource(clazz)注冊到Registry中; 詳見以下代碼片段:
在addPerRequestResource()中做了兩個主要的事情:其中一個是會使用相應的ResourceFactory來包裝資源類TestRest,見以下代碼片段:
通過閱讀POJOResourceFactory的源碼可以了解到其作用就是包含了資源類的所有元信息,因此它可以利用ResteasyProviderFactory提供的注入器在需要時通過createResource()來創建資源類TestRest的對象;
第二個主要的事情是Registry可以通過資源類中的元信息來解析上面的JAX-RS注解,并將該注解的路徑和對應的方法生成的invoker對象注冊到Registry中,在Demo中就是把”/path1/subpath/{id}”和 test()方法的invoker對象注冊到Registry中。
(Resteasy在服務啟動時初始化過程圖)
在web.xml文件中另一個配置是配置了HttpServletDispatcher,該類是HttpServlet的實現是所有請求的入口,通過其service()方法最終將請求交給之前啟動服務時已經初始化好的Dispatcher對象來處理. 以Demo為例,當請求”http://localhost:8080/resteasydemo/path1/subpath/123”過來時,Dispatcher對象會調用其成員變量Registry對象來解析該請求中的路徑”/path1/subpath/123”, 然后匹配到相應的invoker來執行客戶端請求(詳見以下代碼段),并將結果返回,頁面會顯示”Hello 123”;
(Resteasy 客戶端請求處理流程圖)
四、總結
通過對Resteasy源碼的解讀分析我們就可以解答剛開始的三個問題:
1)誰來接受來自客戶端的請求,并進行分發交給對應的對象的方法去處理。
----->HttpServletDispatcher,(接受并分發客戶端http請求)
2)負責處理客戶端請求的對象由誰來負責產生。
----->ResourceFactory (在服務器啟動時通過web.xml讀取class的配置信息然后通過反射機制產生)
3)如何解析Java類上面的注解,使客戶端過來的請求可以找到對應的方法去執行。
------>Registry(服務器啟動時加載用戶自定義Rest資源時,會解析上面的注解,并將注解相對路徑和該類中執行的方法建立對應關系注冊到Registry中,當客戶端請求過來時會根據請求中的相對路徑去Registry中查找對應的invoker對象,然后執行并將處理結果返回)
Resteasy就是通過以上幾個核心組件的相互配合,最終將一個JavaBean發布成Rest服務,這種基于服務注冊的實現方式,使得Resteasy具有較好的可擴展性,例如它能很好的和Spring進行整合將SpringBean發布成Rest服務,它是如何做到的呢?首先擴展了Resteasy的ResourceFactory實現了一個SpringResourceFactory(用來從Spring容器中獲得對象),然后在服務啟動時當Spring容器初始化好以后,通過擴展Spring的BeanFactoryPostProcessor,將Spring容器中初始化好的SpringBean以及對應的SpringResourceFactory注冊到Resteasy的Registry中.這樣客戶端請求過來后,當請求路徑在Registry中匹配到相應的SpringBean時就可以調用該SpringBean的ResourceFactory的createResource方法,該方法可以從Spring容器中獲得對象來處理請求。
Tips:
Resteasy發布Rest服務的兩種方式:
一種是通過listener (ResteasyBootstrap)方式在server啟動時通過該listener的contextInitialized()初始化Resteasy核心組件及Rest資源。
第二種是如果沒有在web.xml中配置ResteasyBootstrap監聽器,則在HttpServletDispatcher,第一次請求過來時通過servlet的init方法初始化Resteasy核心組件及Rest資源。
無論哪種方式原理都是一樣的,只是初始化的時機不同。
關于作者:
王磊
現任普元SOA產品部高級軟件工程師,曾供職于Newegg,The ActiveNetWork等知名外企,在Newegg工作期間曾擔任項目經理帶領團隊完成美蛋網O2O平臺LocalPros的開發上線,在J2EE企業級應用方面有豐富的實戰經驗。
關于EAII
EAII(Enterprise Architecture Innovation Institute)企業架構創新研究院,致力于軟件架構創新與實踐,加速企業數字化轉
文章列表