Hessian 是一種通訊協議,使用 Hessian 能夠實現跨平臺的方法調用,有點相似 SOAP。您可使用下面任意一種語言經過 Hessian 協議進行互相調用,Hessian 自己使用的是二進制傳輸格式。 java
好了廢話很少說,這篇文章是源於和 OSC 上的朋友進行討論最後得出的,如今拿出來和你們分享一下。 git
首先咱們假想這樣一段代碼用來發布 Hessian 服務: github
@HessianService("/testBean") public class HessianBean { public String sayHello() { System.out.println("aaa"); return "aaa"; } }
而後使用下面這樣的代碼調用這個服務。 web
@HessianClient("http://127.0.0.1:8082/testBean") public interface IHessianBean { public String sayHello(); } public static void main(String[] args) throws MalformedURLException { IHessianBean bean = (IHessianBean) HessianPlugin.getPropxy(IHessianBean.class); System.out.println(bean.sayHello()); }
-------------------------------------------------------- api
HessianServlet hessianServlet = new HessianServlet(); hessianServlet.setAPIClass(HessianBean.class); hessianServlet.setHome(hessianBean);
在沒有容器支持的狀況下使用 Hessian 發佈服務須要寫一個 Servlet 類繼承自 HessianServle類而後設置 APIClass 和 Home 屬性。其中 APIClass 表示發佈的服務類型,Home 表示發佈的服務對象。 app
當寫完擴展類以後將其配置到 web.xml 下,若是是 Servlet3.0 容器加上 @WebServlet 註解就能夠了。 maven
下面看一看如何讓 Hasor 支持 Hessian,首先 Hasor 發佈 Servlet 是經過 WebApiBinder 接口。獲得這個接口有兩種方式。 測試
第一種:經過 Hasor 的 WebPlugin 擴展機制,在loadPlugin 時候獲得它。
第二種:經過 Hasor 的 WebModule 擴展機制,當 init 階段能夠獲得它。 網站
如今不管你是選用了那種方式咱們假設您已經獲得了 WebApiBinder 接口。接下來就是經過上面這段代碼建立一個 Hessian Servlet 並註冊到 Hasor 中即可以了。代碼看上去應該是這個樣子的: ui
@Plugin public class TestHessian extends AbstractWebHasorPlugin { public void loadPlugin(WebApiBinder apiBinder) { HessianBean hessianBean = new HessianBean(); // HessianServlet hessianServlet = new HessianServlet(); hessianServlet.setAPIClass(HessianBean.class); hessianServlet.setHome(hessianBean); // apiBinder.serve("/hessian/test").with(hessianServlet); } public static void main(String[] args) throws MalformedURLException { String url = "http://127.0.0.1:8082/hessian/test"; HessianProxyFactory factory = new HessianProxyFactory(); // IHello爲調用的服務接口,url爲hessian服務url IHessianBean bean = (IHessianBean) factory.create(IHessianBean.class, url); System.out.println(bean.sayHello()); } }
其中 Main 方法是用於測試 這個服務發佈是否成功。
HessianBean 和 IHessianBean 之間一個是用於發佈服務的服務對象,另外一個是服務抽象接口。根據 Java Hessian Api 特性二者能夠沒有繼承關係。下面是它們的代碼:
public class HessianBean { public String sayHello() { System.out.println("aaa"); return "aaa"; } } public interface IHessianBean { public String sayHello(); }
啓動 web 程序,並運行 main 方法能夠看到控制檯上打印出 aaa,客戶端也打印出一份 aaa。
--------------------------------------------------------
或許各位同窗以爲,這樣寫太死了不能知足咱們那麼靈活的要求。假若我須要發佈其它 Services 豈不要重複寫不少代碼,這樣寫也不是很優雅!
要想實現上面這樣的目標咱們須要本身解析 @HessianService 註解,而後發佈 HessianServlet 服務。接下來咱們開發一個 HessianPlugin 類用於建立 Hessian客戶端對象。
咱們知道經過 Java 反射機制能夠輕鬆獲取標記到 Class 上的註解信息,而後運用這些信息去作發佈服務和調用服務。值得慶幸的是服務發佈和調用代碼在上面已經先給出了。那麼接下來就是反射形式取得註解信息而後發佈服務了。
首先定義一個 @HessianService 註解,全部標記了這個註解的類都被列入 Hessian Bean。
@Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE }) public @interface HessianService { public String value(); }
其次建立一個 Hasor Web Plugin 插件。
@Plugin public class HessianPlugin extends AbstractWebHasorPlugin { public void loadPlugin(WebApiBinder apiBinder) { } }
接下來咱們須要知道都有哪些類標記了 HessianServices 註解,這個工做能夠經過 Hasor 提供的方法取得。
Set<Class<?>> servicesSet = apiBinder.getClassSet(HessianService.class);
getClassSet 方法是由 Environment 接口直接提供,Hasor 在加載插件以前這個接口對象會被建立。該方法會自動掃描 classpath 路徑中全部類,並匹配被掃描的類。掃描匹配規則以下:
1.被掃描的類是否爲被測試類的(子類)。
2.被掃描的類中是否實現了被測試類型表示的接口(接口實現)。
3.若是被測試的類型是註解,則判斷被掃描的類中是否標記了該註解(註解)。
經過上面這個方法就能夠獲得咱們須要的那些類,接下來取得註解的信息註冊 Hessian 服務。
@Plugin public class HessianPlugin extends AbstractWebHasorPlugin { public void loadPlugin(WebApiBinder apiBinder) { Set<Class<?>> servicesSet = apiBinder.getClassSet(HessianService.class); for (Class<?> hessian : servicesSet) { // HessianService hessAnno = hessian.getAnnotation(HessianService.class); if (hessAnno == null || StringUtils.isBlank(hessAnno.value())) continue; String pushPath = hessAnno.value(); pushPath = (pushPath.charAt(0) != '/') ? ("/" + pushPath) : pushPath; // HessianServlet hessianServlet = new HessianServlet(); hessianServlet.setAPIClass(hessian); hessianServlet.setHome(hessian.newInstance()); apiBinder.serve(pushPath).with(hessianServlet); // } } }
OK,到此爲止發佈服務的工做就算完成了。或許「hessian.newInstance()」這麼草草的經過反射建立 Services 會讓服務類丟失 Guice IoC/Aop 強大功能的支持,可是咱們的確完成了發佈工做。
若是想要發佈的服務類對象是經過 Guice 建立而來的天然就更加完美了,這樣 Hessian 服務類也能夠享受到 IoC/Aop 的待遇。
@Plugin public class HessianPlugin extends AbstractWebHasorPlugin { public void loadPlugin(WebApiBinder apiBinder) { Set<Class<?>> servicesSet = apiBinder.getClassSet(HessianService.class); // 1.註冊 Map<Class<?>, HessianServlet> serviceMap = new HashMap<Class<?>, HessianServlet>(); for (Class<?> serviceType : servicesSet) { // HessianService hessAnno = serviceType.getAnnotation(HessianService.class); if (hessAnno == null || StringUtils.isBlank(hessAnno.value())) continue; String pushPath = hessAnno.value(); pushPath = (pushPath.charAt(0) != '/') ? ("/" + pushPath) : pushPath; // HessianServlet serviceServlet = new HessianServlet(); //serviceServlet.setAPIClass(hessian); //serviceServlet.setHome(hessian.newInstance()); serviceMap.put(serviceType, serviceServlet); apiBinder.serve(pushPath).with(serviceServlet); // } // 2.初始化 } }
新的插件類改成如上樣子,咱們經過 serviceMap 保存 Hessian 服務和具體 HessianServlet 之間的映射關係。
經過 AppContextAware 接口取得 AppContext 對象而後再設置 HessianServlet的 APIClass 和 Home 屬性便可 。
PS:Hasor 會在 Start 的第一時間通知 AppContextAware 接口並將 AppContext 輸送進來,此時 AppContext 已經準備好能夠經過它建立或者獲取 Bean,其它模塊還還沒有 Start。
下面是咱們發佈服務的最終完整插件代碼,它只有一個類:
@Plugin public class HessianPlugin extends AbstractWebHasorPlugin { public void loadPlugin(WebApiBinder apiBinder) { Set<Class<?>> servicesSet = apiBinder.getClassSet(HessianService.class); // 1.註冊 final Map<Class<?>, HessianServlet> serviceMap = new HashMap<Class<?>, HessianServlet>(); for (Class<?> serviceType : servicesSet) { // HessianService hessAnno = serviceType.getAnnotation(HessianService.class); if (hessAnno == null || StringUtils.isBlank(hessAnno.value())) continue; String pushPath = hessAnno.value(); pushPath = (pushPath.charAt(0) != '/') ? ("/" + pushPath) : pushPath; // HessianServlet serviceServlet = new HessianServlet(); serviceMap.put(serviceType, serviceServlet); apiBinder.serve(pushPath).with(serviceServlet); } // 2.初始化 apiBinder.registerAware(new AppContextAware() { public void setAppContext(AppContext appContext) { for (Entry<Class<?>, HessianServlet> ent : serviceMap.entrySet()) { Class<?> serviceType = ent.getKey(); HessianServlet serviceServlet = ent.getValue(); serviceServlet.setAPIClass(serviceType); // 經過 AppContext 建立 serviceServlet.setHome(appContext.getInstance(serviceType)); } } }); } }
下面代碼就是測試程序:
//發佈服務 @HessianService("/testBean") public class HessianBean { @Inject private AppContext appContext; // public long sayHello() { long t = appContext.getStartTime(); System.out.println(t); return t; } } //定義客戶端接口 public interface IHessianBean { public long sayHello(); } //客戶端調用 public static void main(String[] args) throws MalformedURLException { String url = "http://127.0.0.1:8082/testBean"; HessianProxyFactory factory = new HessianProxyFactory(); // IHello爲調用的服務接口,url爲hessian服務url IHessianBean bean = (IHessianBean) factory.create(IHessianBean.class, url); System.out.println(bean.sayHello()); }
--------------------------------------------------
還記得前面說的
public static void main(String[] args) throws MalformedURLException { IHessianBean bean = (IHessianBean) HessianPlugin.getPropxy(IHessianBean.class); System.out.println(bean.sayHello()); }
這種形式調用客戶端麼?下面是 getPropxy 的方法代碼,將這個代碼放入 HessianPlugin 類中便可:
// 建立 Hessian 客戶端調用 public static <T> T getPropxy(Class<T> propxyFaces) throws MalformedURLException { HessianClient hessAnno = propxyFaces.getAnnotation(HessianClient.class); if (hessAnno == null || StringUtils.isBlank(hessAnno.value())) return null; return getPropxy(propxyFaces, hessAnno.value()); } // 建立 Hessian 客戶端調用 public static <T> T getPropxy(Class<T> propxyFaces, String url) throws MalformedURLException { if (propxyFaces.isInterface() == false) throw new ClassCastException("propxyFaces is not Interface."); HessianProxyFactory factory = new HessianProxyFactory(); return (T) factory.create(propxyFaces, url); }
--------------------------------------------------
整合 Hessian 就這麼多,若是您有更好的想法能夠在此基礎上擴展,經過 Hasor 整合 Hessian 就是這麼簡單。2個註解一個插件就能夠搞定!
代碼位於:
這裏是 @黃勇 寫的一篇基於 @WebServlet 註解下集成 Hessian 與你們分享一下。
http://my.oschina.net/huangyong/blog/187561
--------------------------------------------------
目前的開發代碼存放於(包括Demo程序):
Github: https://github.com/zycgit/hasor
git@OSC: http://git.oschina.net/zycgit/hasor
很是感謝您百忙之中抽出時間來看這一系博文。能夠經過Maven 中央倉庫網站 http://search.maven.org/ 搜索 Hasor 下載 hasor 的相關代碼。