从零开始搭建属于自己的物联网平台(四)实现基于协议包的动态协议解析

实现动态的协议解析

  • 源码
  • 往期链接
  • 业务需求
  • 实现方式
    • 源码实现
      • 协议对象接口
    • 协议对象的实现类
    • 解析协议包

源码

源码仓库

往期链接

从零开始搭建属于自己的物联网平台(一)需求分析以及架构设计

从零开始搭建属于自己的物联网平台(二)实现基于订阅发布的消息总线

从零开始搭建属于自己的物联网平台(三)基于netty实现mqtt server网关

业务需求

在物联网平台场景下,接入设备是多种多样的,这时候就不能以硬编码的形式在源码中实现,所以要实现动态的可以自由添加修改的协议解析方式

实现方式

针对这一场景,以加载jar包的形式来实现,指定标准的接口,只要在jar包中实现对应的接口,做标准的协议解析方法就可以了(这里要注意,要支持设备上下行消息解析)。

源码实现

协议对象接口

/**
 * 消息协议支持接口,通过实现此接口来自定义消息协议
 *
 * @author liuhualin
 * @since 1.0.0
 */
public interface ProtocolSupport extends Serializable {
    /**
     * @return 协议ID
     */
    String getId();

    /**
     * @return 协议名称
     */
    String getName();

    /**
     * @return 说明
     */
    String getDescription();

    /**
     * @return 获取支持的协议类型
     */
    List<Transport> getSupportedTransport();

    /**
     * 根据指定协议取得
     *
     * @return 获取支持的协议类型
     */
    DeviceMessageCodec getMessageCodecSupport(String transport);
}

协议对象的实现类

定义协议解析包对象应具有的功能

  • 上行协议解析
  • 下行协议解析

DeviceMessageCodec这里继承了两个接口,分别用来实现上行解析以及下行解析,并且DeviceMessageCodec定义了这个解析器对应的协议类型,最终结构是下面这个样子的:
一个协议包可能有多个DeviceMessageCodec(根据协议包解析的网络协议来的,比如需要解析TCP、MQTT两种那就添加两个DeviceMessageCodec),每个DeviceMessageCodec都实现了上行消息解析、下行消息解析两个功能。

/**
 * 实现自定义消息解析需要实现该类
 */
public interface ProtocolSupportProvider {

    ProtocolSupport create();
}

/**
 * 多传输协议支持的解析包
 */
@Data
public class CompositeProtocolSupport implements ProtocolSupport {

    /**
     * 协议ID
     */
    private String id;

    /**
     * 协议名称
     */
    private String name;

    /**
     * 协议描述
     */
    private String description;

    /**
     * 支持的协议类型
     */
    private Map<String, DeviceMessageCodec> messageCodecSupports = new ConcurrentHashMap<>();


    @Override
    public String getId() {
        return this.id;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public String getDescription() {
        return this.description;
    }

    @Override
    public List<Transport> getSupportedTransport() {
        return messageCodecSupports.entrySet().stream().map(Map.Entry::getValue).map(DeviceMessageCodec::getSupportTransport).collect(Collectors.toList());
    }

    @Override
    public DeviceMessageCodec getMessageCodecSupport(String transport) {
        return messageCodecSupports.get(transport);
    }

    public void addMessageCodecSupport(Transport transport, DeviceMessageCodec codec) {
        messageCodecSupports.put(transport.getId(), codec);
    }

    public void addMessageCodecSupport(DeviceMessageCodec codec) {
        addMessageCodecSupport(codec.getSupportTransport(), codec);
    }
}

解析协议包

以classloader的形式解析jar包,反射调用ProtocolSupportProvider的create

**
 * 自定义协议支持包注册器(内存)
 */
@Component
@Slf4j
public class MemoryProtocolSupportRegistry {

    /**
     * 协议支持包
     * 

* K: 协议ID * V: 协议实体 */ private Map<String, ProtocolSupport> protocolSupportMap = new ConcurrentHashMap<>(16); /** * 取得解析器 * * @param protocolId 协议ID */ public ProtocolSupport getProtocolSupport(String protocolId) { return protocolSupportMap.get(protocolId); } /** * 发布协议 */ public void publishProtocol(String jarFilePath, String mainClass, String protocolId) throws MalformedURLException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { decodeProtocolJar(jarFilePath, mainClass, protocolId); } /** * 发布协议 */ public void publishProtocol(ProtocolSupport protocolSupport) { protocolSupportMap.put(protocolSupport.getId(), protocolSupport); } /** * 解析协议jar包 * * @param jarFilePath * @throws IllegalAccessException */ private void decodeProtocolJar(String jarFilePath, String mainClass, String protocolId) { File jarFile = new File(jarFilePath); URL url; try { url = jarFile.toURI().toURL(); } catch (Exception e) { throw new ServiceException("URL错误,加载不到jar"); } if (null != url) { try { URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url}, this.getClass().getClassLoader()); Class<?> codec = urlClassLoader.loadClass(mainClass); Object instance = codec.getClass().forName(mainClass, true, urlClassLoader).newInstance(); Method method = codec.getMethod("create"); // 加载协议包,创建实体对象 ProtocolSupport protocolSupport = (ProtocolSupport) method.invoke(instance); if (!StringUtils.equals(protocolSupport.getId(), protocolId)) { throw new ServiceException("jar包内定义的ID与协议ID不匹配"); } protocolSupportMap.put(protocolSupport.getId(), protocolSupport); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { throw new ServiceException("jar包解析异常"); } } } }

你可能感兴趣的:(从零开始搭建物联网平台,物联网)