最近由於工作原因研究了jrouter,簡單的記錄和分享下。
一,項目介紹
jrouter是一套基於配置和annotation攔截方法的框架,專注方法的映射、調用、攔截和結果處理,比較強大。項目地址http://code.google.com/p/jrouter/
二,實現思路
首先說標籤,jrouter提供了Action,Interceptor,result,namespace等標籤,通過spring文件將自定義的"標籤實現類"加載到內存中。標籤是一種對真正執行代理的映射,在感興趣的method上定義想要的標籤和name。兩層代理,一層是對標籤的代理(ActionProxy或InterceptorProxy),action和interceptor的代理,由ActionFactory產生;往下一層是具體的proxy(使用javassitproxy產生的代理對象),由ProxyFactory產生。總體來看,jrouter是標籤和代理的結合運用。
三,關鍵路徑分析
入口類DefaultActionFactoryBean(又是FactoryBean)會在屬性初始化後將“代理環境”搭建起來,其中有個屬性classScannerProperties定義了掃描類的規則,在buildActionFactory過程中將所有符合規則的類加載,jrouter就是給這些類加上一層代理,所以同時一起初始化的還有Action,interceptor等自定義實現。整個初始化過程就是對jrouter-spring的解析+設置代理的過程。
測試執行過程:
factory = new DefaultActionFactory();
//interceptor
factory.addInterceptors(SampleInterceptor.class);
//interceptor stack
factory.addInterceptorStacks(DefaultInterceptorStack.class);
//result
factory.addResultTypes(DefaultResult.class);
//aciotn
//class
factory.addActions(jrouter.URLTestAction.class);
//object
factory.addActions(new jrouter.URLTestAction2());
factory.invokeAction("");
invokeAction過程中根據參數創建調用上下文,ActionInvocation invocation = createActionInvocation(path, params);
那麼後面自然是對action和interceptor的調用了,這裏用到了recursive invoke。直接上代碼:
//recursive invoke if (interceptors != null && _index < interceptors.size()) { final InterceptorProxy interceptor = interceptors.get(_index++); LOG.debug("Invoke Interceptor [{}] at : {}", interceptor.getName(), interceptor.getMethod()); invokeResult = interceptor.isRequireAction() ? interceptor.invoke(this) : interceptor.invoke(); } else { //action invoke if (!executed) { invokeActionOnly(params); } } return invokeResult;
再往後使用Java反射或代理對象調用底層方法:
使用Java反射或代理對象調用底層方法:
return proxy == null ? method.invoke(obj, params) : proxy.invoke(method, obj, params);
**************分割線*************
看下創建Action代理類(ActiionProxy)時取得這個Action的攔截代理的實現:
Action action = method.getAnnotation(Action.class);
//action中申明的interceptors
for (String name : action.interceptors()) {
InterceptorProxy ip = interceptors.get(name);
if (ip == null) {
LOG.warn("No such Interceptor [{}] at : {}", name, ap.getMethod());
} else {
inters.add(ip);
}
}
可以是根據標籤配置的攔截器的name從內存的攔截器集合中取到的。真正執行invoke時只要像上述遍歷所有攔截器即可。
四,總結
這種基於標籤和配置的方式擴展性很強,適合於短小精幹的批量的攔截場景,同時學習成本也比較大,跟我想要的攔截模型還不太一樣,但也是有參考價值的。javaassist和reflectasm同樣操作字節碼但使用上方式有很大差別,後面有時間寫篇兩者對比的文章。
最新的文章和分享都放在個人博客:www.b2notes.com ,歡迎訪問。