最近在一個互聯網跨境支付項目組,所使用的技術比較老,代碼是寫於2006年的,整個系統採用服務的架構模式,鏈接件使用hessian進行同步調用,使用MQ進行異步調用。
跨境系統的服務分類上,主要有兩類,一類是線上的,好比交易,網關,出金,入金等,一類是線下的,好比對帳,覈算等。這個分類方法,有點像以前金融市場業務功能分紅前中後臺子系統。言歸正傳,本文主要是講一下,hessian在該項目中的使用。java
整個工程分爲兩個WEB模塊:客戶調用模塊client,服務處理模塊handler。兩個基本jar組件:服務註冊組件register,hessian工具組件hessianutil.web
register : 只有一個枚舉,用於註冊服務,一個服務一個枚舉。是否是瞬間感受低端了。
hessianutil : 提供了hessian操做的工具類套件。之因此將這兩個分開,是由於hessianutil基本不變,而註冊類就常常變更了
client : 服務調用者
handler : 服務提供者spring
public enum SerCode { SIMPLE_CALL_RETURN_STRING("000000","簡單調用"), SIMPLE_CALL_RETURN_MAP("000001","返回字典"); private String code; private String desc; SerCode(String code, String desc) { this.code = code; this.desc = desc; } public String getCode() { return code; } public String getDesc() { return desc; } }
注意在hessian的service中傳入了handler的服務調用地址,hessian會建立代理,來實現RPC調用架構
public void makeSimpleCall(){ Map<String, String> paraMap = new HashMap<String,String>(); String reqMsg = JSonUtil.toJSonString(paraMap); HessianInvokeParam param = HessianInvokeHelper.processRequest(reqMsg); String sysTraceNo = SysTraceNoService .generateSysTraceNo(SystemCodeEnum.WEBGATE.getCode()); String result = clientHessianService.invoke( SerCode.SIMPLE_CALL_RETURN_STRING.getCode(), sysTraceNo, SystemCodeEnum.WEBGATE.getCode(), SystemCodeEnum.TXNCORE.getCode(), SystemCodeEnum.TXNCORE.getVersion(), param.getDataLength(), param.getMsgCompress(), param.getDataMsg()); param.parse(result); HessianInvokeHelper.processResponse(param); result = param.getDataMsg(); System.out.println("result:"+result); }
<bean id="client-txnCoreService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean"> <property name="serviceUrl" value="http://localhost:8080/handler/service/invoke" /> <property name="serviceInterface" value="com.mvp.hessian.service.HessianInvokeService" /> </bean>
public class SimpleHandler implements EventHandler { public String handle(String dataMsg) throws HessianInvokeException { return "this is from simple handler"; } }
<!--bean配置--> <bean id="txncoreService" class="com.mvp.hessian.service.HessianService"> <property name="eventHandlerMap" ref="eventHandlerMap" /> </bean> <bean id="eventHandlerMap" class="java.util.HashMap"> <constructor-arg> <map> <entry key="000000" value-ref="simpleHandler" /> </map> </constructor-arg> </bean> <bean id="simpleHandler" class="com.mvp.hessian.handler.SimpleHandler"> </bean>
<!--servlet配置--> <bean name="/invoke" class="org.springframework.remoting.caucho.HessianServiceExporter"> <property name="serviceInterface" value="com.mvp.hessian.service.HessianInvokeService"/> <property name="service" ref="txncoreService"/> </bean>
<!--web.xml--> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath*:context/**/*.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>remoting</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value> classpath*:remote/**/*.xml </param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>remoting</servlet-name> <url-pattern>/service/*</url-pattern> </servlet-mapping>
經過如上配置,客戶端就能夠經過訪問http://localhost:8080/handler...和對應的code來訪問handler了。app
封裝了hessian的功能,便於調用。裏面的類就不一一作介紹了。主要包括枚舉類和幫助類。異步
//全部handler必須實現的接口 public interface EventHandler { String handle(String dataMsg) throws HessianInvokeException; }
//hessian調用時用的接口 public interface HessianInvokeService { /** * Hessian通信服務接口 * * @param serCode * 服務代碼 * @param sysTraceNo * 系統跟蹤號 * @param originNo * 源系統編號 * @param targetNo * 目的系統編號 * @param versionNo * 接口版本號 格式:1.0.0 * @param dataLength * 消息正文長度 * @param msgCompress * 消息正文是否壓縮 * @param dataMsg * 消息正文 * @return */ String invoke(String serCode, String sysTraceNo, String originNo, String targetNo, String versionNo, int dataLength, int msgCompress, String dataMsg); }
//調用的主要方法類 public class HessianService implements HessianInvokeService { private final Log logger = LogFactory.getLog(HessianService.class); private Map<String, EventHandler> eventHandlerMap; public void setEventHandlerMap(Map<String, EventHandler> eventHandlerMap) { this.eventHandlerMap = eventHandlerMap; } @SuppressWarnings("unchecked") @Override public String invoke(String serCode, String sysTraceNo, String originNo, String targetNo, String versionNo, int dataLength, int msgCompress, String dataMsg) { logger.info("requet auth system:" + "serCode:" + serCode + "sysTraceNo:" + sysTraceNo + "originNo:" + originNo + "targetNo:" + targetNo + "versionNo:" + versionNo); if(logger.isDebugEnabled()){ logger.info("dataMsg:" + dataMsg); } Map<String, String> result = new HashMap<String, String>(); try { // 驗證請求參數 HessianInvokeHelper.validateReqParam(serCode, sysTraceNo, originNo, targetNo, versionNo, dataLength, msgCompress, dataMsg); // 驗證請求服務代碼是否正確 EventHandler handler = eventHandlerMap.get(serCode); if (handler == null) { throw new HessianInvokeException( ResponseCodeEnum.UNDEFINED_SERVICE.getCode(), ResponseCodeEnum.UNDEFINED_SERVICE.getDesc()); } // 驗證目標系統編碼 HessianInvokeHelper.validateTargetNo(targetNo, SystemCodeEnum.TXNCORE.getCode()); // 驗證請求消息正文內容長度 HessianInvokeHelper.validateDataMsgSize(dataLength, dataMsg); String reqMsg = dataMsg; // 判斷是否須要解壓請求消息正文內容 if (msgCompress == 1) { try { reqMsg = ZipUtil.uncompress(dataMsg); } catch (IOException e) { throw new HessianInvokeException( ResponseCodeEnum.UNCOMPRESS_FAILURE.getCode(), ResponseCodeEnum.UNCOMPRESS_FAILURE.getDesc(), e); } } if(logger.isDebugEnabled()){ logger.info("reqMsg:" + reqMsg); } Map<String, Object> map = JSonUtil.toObject(reqMsg, Map.class); map.put("sysTraceNo", sysTraceNo); String rsp = handler.handle(JSonUtil.toJSonString(map)); return HessianInvokeHelper.buildResponse(serCode, sysTraceNo, SystemCodeEnum.TXNCORE.getCode(), originNo, versionNo, rsp); } catch (Exception e) { logger.error(e.getMessage(), e); logger.error(e.getMessage(), e); result.put("responseCode", ResponseCodeEnum.UNDEFINED_ERROR.getCode()); result.put("responseDesc", ResponseCodeEnum.UNDEFINED_ERROR.getDesc()); } return HessianInvokeHelper.buildResponse(serCode, sysTraceNo, SystemCodeEnum.TXNCORE.getCode(), originNo, versionNo, JSonUtil.toJSonString(result)); } }