我们在开发报文处理服务时,会考虑对报文处理的简洁易配置,通常会想到通过配置文件,关联交易代码及相应的处理类,但新增的报文,需要修改该配置文件,会显得不够灵活,如果通过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();
@Override
public 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;
}
@Override
public 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;
}
@Override
public 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";
@Autowired
private AirportCapacityService airportCapacityService;
@Override
protected String genRspSerno(MetaInfo meta, AirportCapacityReqForm request) {
return "";
}
@Override
public AirportCapacityRspForm validateRequest(AirportCapacityReqForm request) {
return null;
}
@Override
protected 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());
}
@Override
protected AirportCapacityRspForm onApplicationException(MetaInfo meta, AirportCapacityReqForm request,
ApplicationException appEx) {
return FormBuilder.buildRsp(AirportCapacityRspForm.class).setRtnCode(appEx.getResultCode())
.setRtnInfo(appEx.getResultMsg());
}
}