使用spring mvc或者resteasy構建restful服務
看到最近一個項目裏用resteasy來構建restful接口,有點不明白,不少Spring mvc4.0以後也可以很方面的實現restful服務嗎,為啥還要在Spring MVC的項目裏還引入resteasy?估計還是開發人員根據自己技術能力自由選擇的吧,畢竟resteasy引入也很簡單。為了解惑,了解了一下resteasy。
resteasy 是 jboss的一個開源restful service實現參考。本文假設讀者熟悉spring mvc,但是不了解或者沒有使用過resteasy的用戶。
其實一直以來,筆者實際都是使用spring mvc,對於研究resteasy沒有興趣。至於最近研究resteasy,純屬因為現在公司使用dubbox作為rpc框架,而dubbox使用resteasy作為REST實現庫。
簡單地說,resteasy核心就是一個servlet前端控制器,理念都一樣。
應該來說,resteasy的優勢在於相比spring mvc而言,更加的專註,簡單。就大型應用而言,絕對是spring mvc占據優勢。
就簡潔性而言,應該來說在spring 4.0引入spring restcontroller之後,優勢就沒有那麽明顯了,應該來說3.2之前對restful還不那麽有信心。
就像我們現在發現基本上mvc上spring mvc占據了絕大部分的新項目,估計以後resteasy也會小眾化。
至於說resteasy為什麽活下來,感覺上spring社區有個比較明顯的傾向就是好像不怎麽吃螃蟹,等到趨勢比較明朗之後,要麽就整合對方,要麽就強行自己引入一套接口玩死對方。
resteasy是JAX-RS的參考實現之一,規範制定者是核心人員之一,所以概念和屬於上基本上完全各種restful service教材上能夠直接對應。spring mvc方面,就沒有那麽直接的對應了,估計是鄙視J2EE的一種商業手法。
就應用而言,如果restful作為rpc的實現機制,resteasy應該是有優勢的,畢竟集成沒有spring mvc那麽多配置(當然spring cloud除外),但作為應用,估計幹不過spring mvc。
resteasy的實現原理也與Spring MVC 的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容器中獲得對象來處理請求。
Resteasy發布Rest服務的兩種方式:
一種是通過listener (ResteasyBootstrap)方式在server啟動時通過該listener的contextInitialized()初始化Resteasy核心組件及Rest資源。
第二種是如果沒有在web.xml中配置ResteasyBootstrap監聽器,則在HttpServletDispatcher,第一次請求過來時通過servlet的init方法初始化Resteasy核心組件及Rest資源。
無論哪種方式原理都是一樣的,只是初始化的時機不同。http://blog.csdn.net/skydivingwang/article/details/77961872
使用spring mvc或者resteasy構建restful服務