我们在开发报文处理服务时,会考虑对报文处理的简洁易配置,通常会想到通过配置文件,关联交易代码及相应的处理类,但新增的报文,需要修改该配置文件,会显得不够灵活,如果通过annotation避免配置文件的方式,易于扩展,简单易用,大概思路如下:

1、构建annontion接口,用于标识业务处理类

package com.variflight.data.analysis.core.msgengine.handler;import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @author sunli* * @date 2015年11月24日 下午3:52:03*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MessageHandlerMarker {String version() default "";String code();boolean checkSign() default true;
}

2、报文处理基类

package com.variflight.data.analysis.core.msgengine.handler;import java.util.Date;
import java.util.Iterator;
import java.util.Set;import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;import com.alibaba.fastjson.JSON;
import com.variflight.data.analysis.core.msgengine.exception.ApplicationException;
import com.variflight.data.analysis.core.msgengine.exception.BizCheckException;
import com.variflight.data.analysis.core.msgengine.model.MessageObject;
import com.variflight.data.analysis.core.msgengine.model.MetaInfo;/*** @author sunli* * @date 2015年11月24日 下午3:52:03*/
public abstract class AbstractMessageHandler<REQ, RSP> implements IMessageHandler<REQ> {private static Log logger = LogFactory.getLog(AbstractMessageHandler.class);private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator();@Overridepublic MessageObject onEvent(MetaInfo meta, REQ request, String sign) throws BizCheckException {if (logger.isDebugEnabled()) {logger.debug("request message meta is :" + meta + ",data is : " + request);}RSP rspData = null;Set<ConstraintViolation<REQ>> constraintViolations = validator.validate(request);if (constraintViolations.size() > 0) {String errCode = meta.getMsgCode() + "00";StringBuffer errSB = new StringBuffer();Iterator<ConstraintViolation<REQ>> it = constraintViolations.iterator();while (it.hasNext()) {errSB.append(it.next().getMessage());if (it.hasNext()) {errSB.append(",");}}String error = String.format("参数校验失败:%s", errSB.toString());logger.info("请求参数: " + request + ", " + error);rspData = onApplicationException(meta, request, new ApplicationException(errCode, error));}if (rspData == null) {rspData = validateRequest(request);}if (rspData == null) {rspData = onHandler(meta, request, sign);}String rspSerno = genRspSerno(meta, request);MessageObject rsp = buildResponseMessage(meta, rspSerno, rspData);if (logger.isDebugEnabled()) {logger.debug("response message meta is :" + JSON.toJSONString(rsp.getMeta()) + ",data is : "+ JSON.toJSONString(rsp.getData()));}return rsp;}protected abstract String genRspSerno(MetaInfo meta, REQ request);// 校验报文有效性public abstract RSP validateRequest(REQ request);private String storeRequestMessage(REQ request) {return "123";}private RSP onHandler(MetaInfo meta, REQ request, String sign) {String msgId = storeRequestMessage(request);if (msgId == null) {throw new BizCheckException();}try {return onMessage(meta, request);} catch (ApplicationException appEx) {// 服务端非正常结束,如:抛出异常,使事务回滚return onApplicationException(meta, request, appEx);}}protected abstract RSP onMessage(MetaInfo meta, REQ request);protected abstract RSP onApplicationException(MetaInfo meta, REQ request, ApplicationException appEx);private MessageObject buildResponseMessage(MetaInfo meta, String rspSerno, RSP rspData) {// 应答报文MessageObject rspMessage = new MessageObject();rspMessage.setMeta(rspMeta);rspMessage.setData(rspData);return rspMessage;}@Overridepublic String toString() {return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);}}

3、系统启动时发现并注册消息处理类

系统接收到报文后,通过getTxProcessor方法txCode,version参数找到对应的处理类

package com.variflight.data.analysis.core.msgengine.handler;import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;import com.variflight.data.analysis.core.msgengine.model.MessageObject;/*** @author sunli* * @date 2015年11月25日 下午13:02:22*/
@Component
@SuppressWarnings({ "rawtypes", "unchecked" })
public class HandlersRegistry implements ApplicationContextAware {private final static Log logger = LogFactory.getLog(HandlersRegistry.class);private Map<String, METAINF> cache = new Hashtable<String, METAINF>();private ApplicationContext appCtx = null;private boolean isLoaded = false;public void setApplicationContext(ApplicationContext appCtx) throws BeansException {this.appCtx = appCtx;}/*** Called by spring*/public void dispose() {cache.clear();cache = null;}public METAINF getTxProcessor(String version, String txCode) {if (logger.isDebugEnabled()) {logger.debug("try to load bean " + version + "::" + txCode);}if (cache.isEmpty()) {checkingHandler();}return cache.get(version + "::" + txCode);}private synchronized void checkingHandler() {if (!isLoaded) {isLoaded = true;Map<String, IMessageHandler> txProviders = BeanFactoryUtils.beansOfTypeIncludingAncestors(appCtx,IMessageHandler.class);if (logger.isDebugEnabled()) {logger.debug("Find result:" + txProviders);}for (Iterator<IMessageHandler> it = txProviders.values().iterator(); it.hasNext();) {IMessageHandler tx = it.next();// 被代理的类if (tx instanceof Advised) {Advised advised = (Advised) tx;try {tx = (IMessageHandler) advised.getTargetSource().getTarget();} catch (Exception ex) {logger.error("This should never happend", ex);throw new RuntimeException(ex);}}Class<? extends IMessageHandler> rc = tx.getClass();if (logger.isDebugEnabled()) {for (Annotation a : rc.getAnnotations()) {logger.debug(a);}}MessageHandlerMarker txMarker = rc.getAnnotation(MessageHandlerMarker.class);if (txMarker != null) {if (logger.isDebugEnabled()) {logger.debug("Find Processor ==>" + tx);}// 如果是直接实现接口Type ts[] = rc.getGenericInterfaces();if (ts.length > 0) {if (logger.isDebugEnabled()) {logger.debug("Processor implements IMessageHandler , checking it now");}for (Type t : ts) {if (t instanceof ParameterizedType) {Type[] p = ((ParameterizedType) t).getActualTypeArguments();METAINF metainf = new METAINF((Class<? extends MessageObject>) p[0], tx,txMarker.version(), txMarker.code(), txMarker.checkSign());cache.put(txMarker.version() + "::" + txMarker.code(), metainf);if (logger.isDebugEnabled()) {logger.debug("Added.");}break;}}}{// 检查是否实现类if (logger.isDebugEnabled()) {logger.debug("Processor extends some class that implements IMessageHandler , checking it now");}Type sc = rc.getGenericSuperclass();if (sc instanceof ParameterizedType) {Type[] p = ((ParameterizedType) sc).getActualTypeArguments();METAINF metainf = new METAINF((Class<?>) p[0], tx, txMarker.version(), txMarker.code(),txMarker.checkSign());cache.put(txMarker.version() + "::" + txMarker.code(), metainf);if (logger.isDebugEnabled()) {logger.debug("Added.");}}if (logger.isDebugEnabled()) {logger.debug("Added.");}}}}}}/*------------- Inner Classes ------------------*/public static class METAINF {Class<?> requestClass;IMessageHandler<?> processor;String version;String msgType;boolean isCaSupport = true;public METAINF(Class<?> requestClass, IMessageHandler<? extends MessageObject> processor) {super();this.requestClass = requestClass;this.processor = processor;}public METAINF(Class<?> requestClass, IMessageHandler<?> processor, String version, String msgType,boolean isCaSupport) {super();this.requestClass = requestClass;this.processor = processor;this.version = version;this.msgType = msgType;this.isCaSupport = isCaSupport;}public Class<?> getRequestClass() {return requestClass;}public IMessageHandler<?> getProcessor() {return processor;}public boolean isCaSupport() {return this.isCaSupport;}@Overridepublic String toString() {return "METAINF [version=" + version + ", msgType=" + msgType + ", processor=" + processor+ ", isCaSupport=" + isCaSupport + ",requestClass=" + requestClass + "]";}};}

4、报文处理类(例子)

package com.variflight.data.analysis.entity.fs.msg.handler;import java.text.ParseException;
import java.util.Arrays;
import java.util.Date;import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import com.variflight.data.analysis.common.model.EnumParamUtils;
import com.variflight.data.analysis.core.client.entity.service.AirportCapacityService;
import com.variflight.data.analysis.core.client.entity.service.AirportCapacityService.AirportCapacityQueryFilter;
import com.variflight.data.analysis.core.client.entity.service.AirportCapacityService.ResultCapacityForm;
import com.variflight.data.analysis.core.client.entity.service.CapacityService.ACT_QUERY_TYPE;
import com.variflight.data.analysis.core.client.entity.service.CapacityService.DATE_QUERY_TYPE;
import com.variflight.data.analysis.core.client.model.ServiceResult;
import com.variflight.data.analysis.core.msgengine.exception.ApplicationException;
import com.variflight.data.analysis.core.msgengine.handler.AbstractMessageHandler;
import com.variflight.data.analysis.core.msgengine.handler.MessageHandlerMarker;
import com.variflight.data.analysis.core.msgengine.model.MetaInfo;
import com.variflight.data.analysis.entity.fs.msg.form.AirportCapacityReqForm;
import com.variflight.data.analysis.entity.fs.msg.form.AirportCapacityRspForm;
import com.variflight.data.analysis.entity.fs.msg.form.base.FormBuilder;/*** 机场运力分析* * @author sunli* * @date 2015年11月27日 上午午08:12:29*/
@Component
@MessageHandlerMarker(code = "0201", version = "1.0", checkSign = false)
public class AirportCapacityMsgHandler extends AbstractMessageHandler<AirportCapacityReqForm, AirportCapacityRspForm> {private static Log logger = LogFactory.getLog(AirportCapacityMsgHandler.class);// 日期范围格式错误public static final String ER_DATE_FORMAT = "020101";@Autowiredprivate AirportCapacityService airportCapacityService;@Overrideprotected String genRspSerno(MetaInfo meta, AirportCapacityReqForm request) {return "";}@Overridepublic AirportCapacityRspForm validateRequest(AirportCapacityReqForm request) {return null;}@Overrideprotected AirportCapacityRspForm onMessage(MetaInfo meta, AirportCapacityReqForm request) {String airportcode = request.getAirport();Date begin = null;try {begin = DateFormatUtils.ISO_DATE_FORMAT.parse(request.getBeginDate());} catch (ParseException e) {}Date end = null;try {end = DateFormatUtils.ISO_DATE_FORMAT.parse(request.getEndDate());} catch (ParseException e) {}if (begin.compareTo(end) > 0) {return FormBuilder.buildRsp(AirportCapacityRspForm.class).setRtnCode(ER_DATE_FORMAT).setRtnInfo("开始日期必须小于结束日期");}AirportCapacityQueryFilter filter = new AirportCapacityQueryFilter();if (StringUtils.isNotBlank(request.getAircodes())) {String[] codes = request.getAircodes().split(",");for (String code : codes) {if (StringUtils.isNotBlank(code)) {filter.getAircodes().add(code.toUpperCase());}}}if (StringUtils.isNotBlank(request.getDateTypes())) {DATE_QUERY_TYPE[] dtypes = EnumParamUtils.valueOfIgnoreCase(DATE_QUERY_TYPE.class, request.getDateTypes(),",");filter.getDateQueryTypes().addAll(Arrays.asList(dtypes));}if (StringUtils.isNotBlank(request.getActTypes())) {ACT_QUERY_TYPE[] dtypes = EnumParamUtils.valueOfIgnoreCase(ACT_QUERY_TYPE.class, request.getActTypes(),",");filter.getActQueryTypes().addAll(Arrays.asList(dtypes));}ServiceResult<ResultCapacityForm> result = airportCapacityService.airportCapacity(airportcode, begin, end,filter);return FormBuilder.buildRsp(AirportCapacityRspForm.class, result).setAirportCapacity(result.getResultObject());}@Overrideprotected AirportCapacityRspForm onApplicationException(MetaInfo meta, AirportCapacityReqForm request,ApplicationException appEx) {return FormBuilder.buildRsp(AirportCapacityRspForm.class).setRtnCode(appEx.getResultCode()).setRtnInfo(appEx.getResultMsg());}}

基于annotation方式的通用报文处理框架相关推荐

  1. 注解@resource的作用_Bean基于Annotation(注解)的装配方式

    在Spring中,尽管使用XML配置文件可以实现Bean的装配工作,但如果应用中有很多Bean时,会导致XML配置文件过于臃肿,给后续的维护和升级工作带来一定的困难.为此,Spring提供了对Anno ...

  2. 独家 | 2019 ICCV 收录论文:基于弱监督学习的病理影像分析框架

    论文传送门 ▼ 扫描下方二维码,或点击文末"阅读原文" 基于弱监督学习的病理影像分析框架 一.研究背景 恶性肿瘤是全球第二大死因,每年导致近千万人死亡.病理报告是肿瘤临床诊断和治疗 ...

  3. CVPR 2019开源论文 | 基于“解构-重构”的图像分类学习框架

    作者丨白亚龙 单位丨京东AI研究院研究员 研究方向丨表示学习.图像识别 基于深度卷积图像识别的相关技术主要专注于高层次图像特征的理解,而对于相似物体之间的细节差异和具有判别意义的区域(discrimi ...

  4. Entity Framework 实体框架的形成之旅--基于泛型的仓储模式的实体框架(1)

    很久没有写博客了,一些读者也经常问问一些问题,不过最近我确实也很忙,除了处理日常工作外,平常主要的时间也花在了继续研究微软的实体框架(EntityFramework)方面了.这个实体框架加入了很多特性 ...

  5. 基于RxJava2+Retrofit2精心打造的Android基础框架

    代码地址如下: http://www.demodashi.com/demo/12132.html XSnow 基于RxJava2+Retrofit2精心打造的Android基础框架,包含网络.上传.下 ...

  6. 一步一步手绘Spring IOC运行时序图三(基于Annotation的IOC容器初始化)

    相关内容: 架构师系列内容:架构师学习笔记(持续更新) 一步一步手绘Spring IOC运行时序图一(Spring 核心容器 IOC初始化过程) 一步一步手绘Spring IOC运行时序图二(基于XM ...

  7. HTML一条线匀速一定区域运动,通用的匀速运动框架如何打造

    本文主要为大家带来一篇打造通用的匀速运动框架(实例讲解).小编觉得挺不错的,现在就分享给大家,也给大家做个参考.一起跟随小编过来看看吧,希望能帮助到大家. 本文,是接着上 基于匀速运动的实例讲解(侧边 ...

  8. SSM源码分析之Spring05-DI实现原理(基于Annotation 注入)

    目录导航 前言 注解的引入 AnnotationConfigApplicationContext 对注解Bean初始化 AnnotationConfigApplicationContext注册注解Be ...

  9. 基于VS Code搭建通用ARM微控制器开发平台

    基于VS Code搭建通用ARM微控制器开发平台 Data Author Version Note 2022.04.12 Dog Tao V1.0 Release as V1.0 - 使用基于STM3 ...

最新文章

  1. c语言中小数乘法怎样写程序,四年级下册lbrack;小数乘法rsqb;知识点归纳
  2. oracle密码错误延迟验证,oracle密码错误验证延迟
  3. 美国Palmbeach大学服务器整合改造案例
  4. redhat5中架设DHCP服务器与DHCP中继
  5. 【#9733;】SPF(Dijkstra)算法完美教程
  6. Windows 下 docker 部署 gitlab ci
  7. 【电力电子】【2020.02】利用导抗式三相双有源桥DC-DC变换器实现宽范围高效率的拓扑结构和调制方案
  8. 笔记学习:关于如何使用ESPwifi模块与51单片机通信
  9. C语言自己编写头文件
  10. python输入一个包含若干自然数的列表_Python练习题
  11. Android中使用AudioManager实现按键录音并保存以及点击播放功能
  12. 小红书种草模式有哪些?如何保证种草效果
  13. MQ(message queue)使用 Spring整合 MQ下载 五分钟上手使用
  14. class file has wrong version 55.0, should be 52.0
  15. 为什么要使用零知识证明来开发跨链协议
  16. 数字图像处理:实验一 MATLAB 图像处理基础
  17. 敏捷实践之Scrum
  18. SAP IDoc ALE和EDI有什么区别和联系
  19. 田野调查手记·浮山篇(八)
  20. 解决---设备“VMnet0”上的网桥没有运行。该虚拟机无法与此主机或网络上的其他主机进行通信。 无法连接虚拟设备“Ethernet0”。

热门文章

  1. 全球与中国无溶剂双组份聚氨酯粘合剂市场深度研究分析报告
  2. 界面之下:还原真实的MV*模式 -( MVC , MVP , MVVM )
  3. 操作系统---(35)缺页中断与缺页中断处理过程
  4. mac安装cnpm安装失败
  5. sql server 2008:导入excel,出现“外部表不是预期格式“错误
  6. 通过 20 个棘手的ES6面试问题来提高咱们的 JS 技能
  7. 在大连做安天技术论坛 GuessMe3
  8. 阿里云企业邮箱设置教程(新手指南)
  9. Mysql查询语句执行过程及运行原理
  10. Rancher2.0安装Kubernetes