如何做一个简单的开放接口(2)

1、要实现的功能

书接上回,本回书我们要完成开放接口平台核心引擎的多Handler支持机制。

如图1所示。

图1 开放接口服务器端架构

2、Filter还是装饰模式

装饰者模式貌似是一个实现的候选,类似Java的I/O实现。 多“装饰”一层,就获得了新的功能,原来的功能还在。

对我现在的应用场景来说,这种实现方式过于复杂了。 相对而言,Filter更简洁。

当前的应用场景对性能是有极高要求的,不适合使用哪怕稍微复杂的模式。

3、Handler接口定义

我的Handler接口定义如下。

{(HttpServletRequest request,HttpServletResponse response);(HttpServletRequest request,HttpServletResponse response);}

更有节操的童鞋会自己定义Request、Response0,甚至Context对象。以便脱离Web容器的限制,进一步实现自己的底层通信协议。

我这里先偷个懒,等有时间了慢慢来。

Handler接口中,inWay方法对应图1左侧的向下箭头,outWay对应右侧的向上箭头。

这样,在同一个Handler定义进、出的逻辑。 对于实现序列化功能的Handler,inWay中实现反序列化,outWay中实现序列化。 对于实现加密功能的Handler,inWay中实现解密,outWay中实现加密。 对于实现压缩功能的Handler,inWay中实现解压缩的逻辑,outWay中实现压缩的逻辑。

这样,当不需要某个Handler的时候,直接去掉就好了。

当然,outWay中可以do nothing。

另外,非常重要的,Handler实现类不可以有自己的属性。Handler实例不能有“状态”。 我们需要Handler是线程安全的。

3、可配置

多个Handler是可配置的,每个Handler链可以服务于一个或多个接口。

在Handler无状态、线程安全的基础上,我们可以采用在每个JVM中Handler单例的方式,避免频繁创建、回收Handler对象的损失。

配置信息可以保存在properties文件中,可以保存在xml中,可以保存在数据中,范例如下:

openapi.handler.keys=surface,encrypt,authopenapiopenapiopenapi

配置系统中可能用到的所有Handler,并在系统启动时加载。

在上面的配置中,配置了每个Handler的类名,加载的时候,可以根据类名创建类的实例。 给每个Handler起了一个短名称,便于在配置Handler链的时候引用。

对应的加载代码为:

{/*** 保存系统中的所有Handler,key为handler短名,value为Handler实例。*/private static Map<String, Handler> handlersMap = new ConcurrentHashMap<String, Handler>();static{reloadHandlers();}(){handlersMap.clear();logger.info(“Open Api Handlers load start … “);long begin = System.currentTimeMillis();Properties props = ConfigManager.getProperties(“openapi”);String handlerKeys = props.getProperty(“openapi.handler.keys”);logger.debug(“loading handlers : “+handlerKeys);Handler handler = null;if(!StringUtils.isEmpty(handlerKeys)){String[] handlerKeyArray = handlerKeys.split(“,”);if(handlerKeyArray!=null && handlerKeyArray.length>0){for (String handlerKey : handlerKeyArray) {String propertiesKey = “openapi.handler.”+handlerKey;String handlerClassName = props.getProperty(propertiesKey);if(StringUtils.isEmpty(handlerClassName)){continue;}handlerClassName = handlerClassName.trim();Class<?> clz = Class.forName(className);handler = BeanUtil.newInstance(Handler.class,clz);if(handler!=null){handlersMap.put(handlerKey,handler);logger.debug(String.format(“handler[%s] loaded : %s “, handlerKey,handler));}}}}logger.info(“Open Api Handlers load end , time costs “+(System.currentTimeMillis()-begin));}/****/public static Hanlder get(String shortName){return handlerMap.get(shortName);}}

修改了Handler的配置,需要重新加载的时候,,也无需重启服务器(在生产环境,这非常重要),再次调用HandlerManager.reloadHandlers()即可。

接下来是Handler链的配置,配置范例如下:

openapi=full,idleopenapi=surface,encrypt,auth,traffic,config,validateopenapi=idle,idle,idle,idle,idle

加载逻辑与HandlerManager中代码逻辑类似。

4、Handler执行过程

Handler的执行过程如图1所示。

public class HandlerChain {protected List<Handler> handlersList = null;protected List<Handler> handlersReversedList = null;protected Iterator<Handler> inIterator = null;protected Iterator<Handler> outIterator = null;public HandlerChain(List<Handler> handlers) {setHandlers(handlers);reset();}(List<Handler> handlers) {if (handlers == null) {return;}// 正向this.handlersList = handlers;// 反向if (handlersReversedList == null) {handlersReversedList = new ArrayList<Handler>();} else {handlersReversedList.clear();}for (int idx = handlers.size() – 1; idx > -1; –idx) {handlersReversedList.add(handlers.get(idx));}}() {if (handlersList != null) {inIterator = handlersList.iterator();}if (handlersReversedList != null) {outIterator = handlersReversedList.iterator();}}(HttpServletRequest request, HttpServletResponse response) {Handler nextHandler = null;if (inIterator != null && inIterator.hasNext()) {nextHandler = inIterator.next();}if (nextHandler != null) {nextHandler.inWay(request, response);this.inWay(request, response);//递归调用} else {logger.debug(String.format(“In End Time:%s.”,(System.currentTimeMillis() – this.time)));}}(HttpServletRequest request, HttpServletResponse response) {Handler nextHandler = null;if (outIterator != null && outIterator.hasNext()) {nextHandler = outIterator.next();}if (nextHandler != null) {nextHandler.outWay(request, response);this.outWay(request, response);} else {logger.debug(String.format(“Out End Time:%s.”,(System.currentTimeMillis() – this.time)));}}}生活中若没有朋友,就像生活中没有阳光一样

如何做一个简单的开放接口(2)

相关文章:

你感兴趣的文章:

标签云: