标签:.com out hash sass target map art heartbeat 配置
本文是该文章的后续(https://www.cnblogs.com/Binhua-Liu/p/5577622.html),该文章介绍了在ProtoBuf上再加一层Header从来归避ProtoBuf在Netty框架下只能有一有对象的局限。 在蘑菇街开源的TeamTalk中,也是加了一个Header,根据Header中的操作类型,做出相应的逻辑处理操作。
下面是我们的配置文件,用于实现ServerCustomDecodeHandler中的decodeBody的逻辑。ProtoBuf通过反射生成对象需要使用“包$类”的形式。
<?xml version="1.0" encoding="UTF-8"?> <decodetypes> <decodetype type="com.zywj.protobuf.out.IMBase$MessageCmdID" val="CID_MSG_DATA_VALUE" class="com.zywj.protobuf.out.IMMessage$MsgData" /> <decodetype type="com.zywj.protobuf.out.IMBase$OtherCmdID" val="CID_OTHER_HEARTBEAT_VALUE" class="com.zywj.protobuf.out.IMOther$HeartBeat" /> </decodetypes>
读取XML的工作放在Server中,声明为private static。这里是根据我自己的逻辑生成的一个Map变量。
private static Map parseXmlData(String xmlFilePath){ SAXReader reader = new SAXReader(); Document doc = null; try { doc = reader.read(new File(xmlFilePath)); } catch (DocumentException e) { e.printStackTrace(); } Element root = doc.getRootElement(); Map<String,Map> map = new HashMap<>(); for(Iterator i_action=root.elementIterator();i_action.hasNext();){ Element e_action = (Element)i_action.next(); Iterator it = e_action.attributeIterator(); Attribute key = (Attribute) it.next(); String type = key.getValue(); Map<String, String> inner = new HashMap<>(); while(it.hasNext()) { Attribute attribute = (Attribute) it.next(); inner.put(attribute.getName(), attribute.getValue()); } map.put(type, inner); } return map; }
ServerCustomDecodeHandler的decodeBody的工作是根据Map中的数据通过反射生成对象,这里需要判断当前对象的enum值是否是与commandId相等,如果找到,就生成相对应的ProtoBuf对象。
public MessageLite decodeBody(short commandId, byte[] array, int offset, int length) throws Exception { Map<String, Map> decodeMap = Server.decodeMap; for (Map.Entry<String, Map> entry : decodeMap.entrySet()) { Map<String, String> m = decodeMap.get(entry.getKey()); Class clazz = Class.forName(entry.getKey()); Field f = clazz.getField(m.get("val")); if ((int)f.get(clazz) == commandId) { Class cls = Class.forName(m.get("class")); Method method = cls.getMethod("getDefaultInstance"); Object obj = method.invoke(cls, null); method = cls.getMethod("getParserForType"); obj = method.invoke(obj, null); return ((Parser<MessageLite>) obj).parseFrom(array, offset, length); } } return null; }
到这里,还没完,因为ServerHandler里面传进来的是Object msg,所以还要用instanceof判断该Object到底是ProtoBuf的对象。所以又是一个XML,再反射。
<?xml version="1.0" encoding="UTF-8"?> <msgtypes> <msgtype type="com.zywj.protobuf.out.IMMessage$MsgData" class="com.zywj.server.LogicHandler" method="handleMsgData" /> <msgtype type="com.zywj.protobuf.out.IMOther$HeartBeat" class="com.zywj.server.LogicHandler" method="handleHeartBeat" /> </msgtypes>
ServerHanlder中的channelRead0改成
@Override public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { Map<String, Map> dispatchMap = Server.dispatchMap; for (Map.Entry<String, Map> entry : dispatchMap.entrySet()) { Class clazz = Class.forName(entry.getKey()); if (msg.getClass().isAssignableFrom(clazz)) { Map<String, String> m = dispatchMap.get(entry.getKey()); Class clazzLogic = Class.forName(m.get("class")); Method handle = clazzLogic.getDeclaredMethod(m.get("method"), ChannelHandlerContext.class, Object.class); handle.invoke(clazzLogic.newInstance(), ctx, msg); break; } } }
SeverCustomEncodeHandler也是相同方法,不再赘述。
到这里,我们利用反射,把上面文章中过多的if...else...归避了。
最后,我觉得这样实现会有过多的反射(循环反射再判断,时间复杂度O(n)),还有就是代码量其实并没有减少,只是转移到XML中去,最大的优点是降低耦合吧。
Netty + ProtoBuf使用反射实现多种类型的传输方式
标签:.com out hash sass target map art heartbeat 配置
原文地址:https://www.cnblogs.com/zywj/p/9216144.html