最近在一个互联网跨境支付项目组,所使用的技术比较老,代码是写于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)); } }