如何通过GSON根据WebSocket JSON消息类型映射不同类并分发至对应处理器
刚好我之前做过类似的WebSocket消息解析和分发需求,用GSON+自定义适配器+处理器分发的方案可以完美解决。下面给你具体的实现步骤和代码示例:
1. 定义消息类结构
首先我们需要一个包含type字段的基类,所有具体消息类都继承它,这样能统一处理类型标识:
// 消息基类 public abstract class BaseMessage { protected String type; public String getType() { return type; } } // 快照消息类 public class Snapshot extends BaseMessage { // 快照消息特有的字段,比如 private long timestamp; private List<OrderBookEntry> bids; private List<OrderBookEntry> asks; // getter、setter或构造方法按需实现 } // L2更新消息类 public class L2Update extends BaseMessage { private long timestamp; private List<PriceLevelUpdate> updates; // getter、setter或构造方法按需实现 } // 错误消息类 public class ErrorMessage extends BaseMessage { private int code; private String message; // getter、setter或构造方法按需实现 }
2. 实现GSON自定义类型适配器
核心是用TypeAdapterFactory来根据type字段动态选择对应的解析类。这个工厂类会在GSON解析时先读取type值,再决定用哪个类来解析整个JSON:
import com.google.gson.Gson; import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapterFactory; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import java.io.IOException; import java.util.HashMap; import java.util.Map; public class MessageTypeAdapterFactory implements TypeAdapterFactory { // 维护type到具体消息类的映射 private static final Map<String, Class<? extends BaseMessage>> TYPE_MAP = new HashMap<>(); static { TYPE_MAP.put("snapshot", Snapshot.class); TYPE_MAP.put("l2update", L2Update.class); TYPE_MAP.put("error", ErrorMessage.class); // 后续新增消息类型直接在这里添加即可 } @SuppressWarnings("unchecked") @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { // 只处理BaseMessage的子类 if (!BaseMessage.class.isAssignableFrom(typeToken.getRawType())) { return null; } TypeAdapter<BaseMessage> delegateAdapter = (TypeAdapter<BaseMessage>) gson.getAdapter(typeToken); return (TypeAdapter<T>) new TypeAdapter<BaseMessage>() { @Override public void write(JsonWriter out, BaseMessage value) throws IOException { delegateAdapter.write(out, value); } @Override public BaseMessage read(JsonReader in) throws IOException { // 先把整个JSON读成临时结构,以便获取type字段 in.beginObject(); String type = null; Map<String, Object> tempFieldMap = new HashMap<>(); while (in.hasNext()) { String fieldName = in.nextName(); if ("type".equals(fieldName)) { type = in.nextString(); } else { // 暂存其他字段,后续再解析 tempFieldMap.put(fieldName, gson.fromJson(in, Object.class)); } } in.endObject(); // 根据type获取对应的目标类 Class<? extends BaseMessage> targetClass = TYPE_MAP.get(type); if (targetClass == null) { throw new IOException("Unknown message type: " + type); } // 把临时结构转成目标类实例 BaseMessage message = gson.fromJson(gson.toJson(tempFieldMap), targetClass); message.type = type; // 手动注入type字段(如果GSON未自动映射) return message; } }; } }
3. 配置GSON实例
把自定义的适配器工厂加入GSON配置,这样GSON就能自动识别type字段并解析到对应类:
Gson gson = new GsonBuilder() .registerTypeAdapterFactory(new MessageTypeAdapterFactory()) .create();
4. 设计消息处理器体系
先定义一个通用的处理器接口,所有具体处理器都实现这个接口:
public interface MessageHandler<T extends BaseMessage> { void handle(T message); } // 快照消息处理器 public class SnapshotMessageHandler implements MessageHandler<Snapshot> { @Override public void handle(Snapshot message) { // 处理快照消息的业务逻辑,比如更新本地订单簿 System.out.println("Received snapshot, updating order book at: " + message.getTimestamp()); } } // 错误消息处理器 public class ErrorMessageHandler implements MessageHandler<ErrorMessage> { @Override public void handle(ErrorMessage message) { // 处理错误消息,比如记录日志、触发告警 System.err.println("WebSocket error: [" + message.getCode() + "] " + message.getMessage()); } } // L2更新消息处理器 public class L2UpdateMessageHandler implements MessageHandler<L2Update> { @Override public void handle(L2Update message) { // 处理L2更新消息,比如增量更新订单簿 System.out.println("Received L2 update, applying " + message.getUpdates().size() + " changes"); } }
5. 实现消息分发器
创建一个分发器类,负责把解析后的消息路由到对应的处理器:
import java.util.HashMap; import java.util.Map; public class MessageDispatcher { private final Map<Class<? extends BaseMessage>, MessageHandler<? extends BaseMessage>> handlerMap = new HashMap<>(); // 注册处理器 public <T extends BaseMessage> void registerHandler(Class<T> messageClass, MessageHandler<T> handler) { handlerMap.put(messageClass, handler); } // 分发消息 @SuppressWarnings("unchecked") public <T extends BaseMessage> void dispatch(T message) { MessageHandler<T> handler = (MessageHandler<T>) handlerMap.get(message.getClass()); if (handler != null) { handler.handle(message); } else { // 处理无对应处理器的情况 System.err.println("No handler registered for message type: " + message.getClass().getSimpleName()); } } }
6. 在WebSocket处理器中整合
最后在你的WebSocket消息接收方法里,把这些组件串起来:
// 初始化核心组件 Gson gson = new GsonBuilder() .registerTypeAdapterFactory(new MessageTypeAdapterFactory()) .create(); MessageDispatcher dispatcher = new MessageDispatcher(); // 注册所有处理器 dispatcher.registerHandler(Snapshot.class, new SnapshotMessageHandler()); dispatcher.registerHandler(L2Update.class, new L2UpdateMessageHandler()); dispatcher.registerHandler(ErrorMessage.class, new ErrorMessageHandler()); // WebSocket消息接收示例(以Java WebSocket API为例) @Override public void onMessage(String message) { try { // 解析JSON到对应的消息实例 BaseMessage parsedMessage = gson.fromJson(message, BaseMessage.class); // 分发给对应处理器处理 dispatcher.dispatch(parsedMessage); } catch (Exception e) { // 处理解析失败的异常 System.err.println("Failed to parse WebSocket message: " + message); e.printStackTrace(); } }
一些注意事项
- 确保
TYPE_MAP中的type值和WebSocket收到的JSON里的type字段完全匹配(包括大小写),否则会触发未知类型异常。 - 如果消息包含复杂嵌套结构,可以在GSON配置中添加对应适配器,或者用
@SerializedName注解映射字段名。 - 对于未知消息类型,可以在适配器中返回自定义的
UnknownMessage类,或者在分发器中统一做日志记录,避免程序崩溃。
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

