zoukankan      html  css  js  c++  java
  • 物联网架构成长之路(35)-利用Netty解析物联网自定义协议

    一、前言

      前面博客大部分介绍了基于EMQ中间件,通信协议使用的是MQTT,而传输的数据为纯文本数据,采用JSON格式。这种方式,大部分一看就知道是熟悉Web开发、软件开发的人喜欢用的方式。由于我也是做web软件开发的,也是比较喜欢这种方式。阿里的物联网平台,也是推荐这种方式。但是,但是做惯硬件开发,嵌入式开发就比较喜欢用裸TCP-Socket连接。采用的是二进制协议。基于此大部分应用场合为了兼容旧设备,就需要单独开发一个TCP服务器的网关。这里使用以前学过的,也是比较流行的Netty框架。

      话不多说,下面就开始了。

     二、协议

    定义

    描述

    启动符‘@@’

    (2字节)

    数据包的第1、2字节,为固定值 64,64。

    控制单元

    业务流水号

    (2字节)

    数据包的第3、4字节。发送/确认模式下,业务流水号由发送端在发送新的数据包时按顺序加一,确认方按发送包的业务流水号返回;请求/应答模式下,业务流水号由请求端在发送新的请求命令时按顺序加一,应答方按请求包的业务流水号返回。低字节传输在前。业务流水号是一个2字节的正整数,由通信双方第一次建立网络连接时确定,初始值为0。业务流水号由业务发起方(业务发起方指发送/确认模式下的发送端或者请求/应答模式下的请求端)独立管理。业务发起方负责业务流水号的分配和回收,保证在业务存续期间业务流水号的唯一性。

    协议版本号

    (2字节)

    协议版本号包含主版本号(第5字节)和用户版本号(第6字节)。主版本号为固定值1,用户版本号由用户自行定义。

    时间标签

    (6字节)

    数据包的第7~12字节,为数据包发出的时间,具体定义表2。

    源地址

    (6字节)

    数据包的第13~18字节,为数据包的源地址(监控中心或用户信息传输装置地址)。低字节传输在前。

    目的地址

    (6字节)

    数据包的第19~24字节,为数据包的目的地址(监控中心或用户信息传输装置地址)。低字节传输在前。

    应用数据单元长度

    (2字节)

    数据包的第25、26字节,为应用数据单元的长度,长度不应大于1024;低字节传输在前。

    命令字节

    (1字节)

    数据包的第27字节,为控制单元的命令字节,具体定义见表3。

    应用数据单元

    (最大1024字节)

    应用数据单元,基本格式见表3,对于确认/否认等命令包,此单元可为空。

    校验和

    (1字节)

    控制单元中各字节数据(第3~第27字节)及应用数据单元的算术校验和,舍去8位以上的进位位后所形成的1字节二进制数。

    结束符‘##’

    (2字节)

    为固定值 35,35。

      上面这个是本次需要处理的二进制数据格式。

    三、代码部分

      3.0 Pom.xml

    复制代码
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     3     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     4     <modelVersion>4.0.0</modelVersion>
     5     <parent>
     6         <groupId>org.springframework.boot</groupId>
     7         <artifactId>spring-boot-starter-parent</artifactId>
     8         <version>2.1.1.RELEASE</version>
     9         <relativePath/> <!-- lookup parent from repository -->
    10     </parent>
    11     <groupId>com.wunaozai.iot.nettyplatform</groupId>
    12     <artifactId>NettyPlatform</artifactId>
    13     <version>0.0.1-SNAPSHOT</version>
    14     <name>IoTNettyPlatForm</name>
    15     <description>基于自定义协议,使用Netty,物联网通信平台</description>
    16 
    17     <properties>
    18         <java.version>1.8</java.version>
    19     </properties>
    20 
    21     <dependencies>
    22         <dependency>
    23             <groupId>org.springframework.boot</groupId>
    24             <artifactId>spring-boot-starter</artifactId>
    25         </dependency>
    26 
    27         <!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
    28         <dependency>
    29             <groupId>io.netty</groupId>
    30             <artifactId>netty-all</artifactId>
    31         </dependency>
    32         <dependency>
    33             <groupId>org.springframework.boot</groupId>
    34             <artifactId>spring-boot-configuration-processor</artifactId>
    35             <optional>true</optional>
    36         </dependency>
    37 
    38     <!-- web项目必要的依赖 -->
    39     <dependency>
    40         <groupId>org.springframework.boot</groupId>
    41         <artifactId>spring-boot-starter-web</artifactId>
    42     </dependency>
    43 
    44     <!-- 热启动devtools -->
    45     <dependency>
    46         <groupId>org.springframework.boot</groupId>
    47         <artifactId>spring-boot-devtools</artifactId>
    48         <optional>true</optional>
    49         <scope>true</scope>
    50     </dependency>
    51     
    52         <dependency>
    53             <groupId>org.springframework.boot</groupId>
    54             <artifactId>spring-boot-starter-test</artifactId>
    55             <scope>test</scope>
    56         </dependency>
    57     </dependencies>
    58 
    59     <build>
    60         <plugins>
    61             <plugin>
    62                 <groupId>org.springframework.boot</groupId>
    63                 <artifactId>spring-boot-maven-plugin</artifactId>
    64                 <configuration>
    65                     <fork>true</fork>
    66                 </configuration>
    67             </plugin>
    68         </plugins>
    69     </build>
    70 
    71 </project>
    复制代码

      3.1 SmartIotProtocol.java

       这个主要对通信协议模型进行简单封装

    复制代码
      1 package com.wunaozai.iot.nettyplatform.code;
      2 
      3 /**
      4  * 自定义协议
      5  * @author Administrator
      6  * @see https://www.cnblogs.com/sidesky/p/6913109.html
      7  */
      8 public class SmartIotProtocol {
      9 
     10     /**
     11      * 协议最短长度 30 字节
     12      */
     13     public static int MIN_LEN = 30;
     14     
     15     /**
     16      * 数据包启动符号 @@
     17      */
     18     public static short START = 25700;
     19     
     20     /**
     21      * 业务流水号
     22      */
     23     private short flowid;
     24     /**
     25      * 主版本
     26      */
     27     private byte version_major;
     28     /**
     29      * 次版本
     30      */
     31     private byte version_minor;
     32     /**
     33      * 秒
     34      */
     35     private byte second;
     36     /**
     37      * 分钟
     38      */
     39     private byte minute;
     40     /**
     41      * 小时
     42      */
     43     private byte hour;
     44     /**
     45      * 日
     46      */
     47     private byte day;
     48     /**
     49      * 月
     50      */
     51     private byte month;
     52     /**
     53      * 年
     54      */
     55     private byte year;
     56     /**
     57      * 数据包的源地址
     58      */
     59     private byte[] src;
     60     /**
     61      * 数据包的目的地址
     62      */
     63     private byte[] dest;
     64     /**
     65      * 应用数据单元长度 长度不应大于1024;低字节传输在前
     66      */
     67     private short data_len;
     68     /**
     69      * 命令字节 为控制单元的命令字节
     70      */
     71     private byte cmd;
     72     /**
     73      * 应用数据单元  对于确认/否认等命令包,此单元可为空
     74      */
     75     private byte[] data;
     76     /**
     77      * 校验和 控制单元中各字节数据(第3~第27字节)及应用数据单元的算术校验和,舍去8位以上的进位位后所形成的1字节二进制数
     78      */
     79     private byte checksum;
     80     /**
     81      * 协议结束符号 ##
     82      */
     83     public static short END = 13621;
     84     
     85     /**
     86      * 打印调试信息
     87      */
     88     public void printDebugInfo(){
     89         System.out.println("---------完整数据包开始------------");
     90         System.out.println("|开始标志: " + printHexShort(START));
     91         System.out.println("|业务流水: " + printHexShort(flowid) + "	FlowID:" + flowid);
     92         System.out.println("|协议版本: " + printHexByte(version_major) + printHexByte(version_minor));
     93         System.out.println("|时间标签: " + "20" + year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second);
     94         System.out.println("|源地址  : " + printHexBytes(src));
     95         System.out.println("|目的地址: " + printHexBytes(dest));
     96         System.out.println("|数据长度: " + data_len);
     97         System.out.println("|命令字节: " + printHexByte(cmd));
     98         System.out.println("|应用数据: " + printHexBytes(data));
     99         System.out.println("|校验字节: " + printHexByte(checksum));
    100         System.out.println("|结束标志: " + printHexShort(END));
    101         System.out.println("---------------------------------");
    102     }
    103     private String printHexByte(byte b){
    104         return String.format("%02X", b);
    105     }
    106     private String printHexBytes(byte[] bytes){
    107         String str = "";
    108         for(int i=0; i<bytes.length; i++){
    109             str += String.format("%02X", bytes[i]);
    110         }
    111         return str;
    112     }
    113     private String printHexShort(int s){
    114         byte[] bytes = hexShort(s);
    115         return printHexBytes(bytes);
    116     }
    117     private byte[] hexShort(int s){
    118         byte[] bytes = new byte[2];
    119         bytes[0] = (byte)((s << 24) >> 24);
    120         bytes[1] = (byte)((s << 16) >> 24);
    121         return bytes;
    122     }
    123     private byte[] hexInt(int n){
    124         byte[] bytes = new byte[4];
    125         bytes[3] = (byte) ((n      ) >> 24);
    126         bytes[2] = (byte) ((n <<  8) >> 24);
    127         bytes[1] = (byte) ((n << 16) >> 24);
    128         bytes[0] = (byte) ((n << 24) >> 24);
    129         return bytes;
    130     }
    131     
    132     public short getFlowid() {
    133         return flowid;
    134     }
    135     public void setFlowid(short flowid) {
    136         this.flowid = flowid;
    137     }
    138     public byte getVersion_major() {
    139         return version_major;
    140     }
    141     public void setVersion_major(byte version_major) {
    142         this.version_major = version_major;
    143     }
    144     public byte getVersion_minor() {
    145         return version_minor;
    146     }
    147     public void setVersion_minor(byte version_minor) {
    148         this.version_minor = version_minor;
    149     }
    150     public byte getSecond() {
    151         return second;
    152     }
    153     public void setSecond(byte second) {
    154         this.second = second;
    155     }
    156     public byte getMinute() {
    157         return minute;
    158     }
    159     public void setMinute(byte minute) {
    160         this.minute = minute;
    161     }
    162     public byte getHour() {
    163         return hour;
    164     }
    165     public void setHour(byte hour) {
    166         this.hour = hour;
    167     }
    168     public byte getDay() {
    169         return day;
    170     }
    171     public void setDay(byte day) {
    172         this.day = day;
    173     }
    174     public byte getMonth() {
    175         return month;
    176     }
    177     public void setMonth(byte month) {
    178         this.month = month;
    179     }
    180     public byte getYear() {
    181         return year;
    182     }
    183     public void setYear(byte year) {
    184         this.year = year;
    185     }
    186     public byte[] getSrc() {
    187         return src;
    188     }
    189     public void setSrc(byte[] src) {
    190         this.src = src;
    191     }
    192     public byte[] getDest() {
    193         return dest;
    194     }
    195     public void setDest(byte[] dest) {
    196         this.dest = dest;
    197     }
    198     public short getData_len() {
    199         return data_len;
    200     }
    201     public void setData_len(short data_len) {
    202         this.data_len = data_len;
    203     }
    204     public byte getCmd() {
    205         return cmd;
    206     }
    207     public void setCmd(byte cmd) {
    208         this.cmd = cmd;
    209     }
    210     public byte[] getData() {
    211         return data;
    212     }
    213     public void setData(byte[] data) {
    214         this.data = data;
    215     }
    216     public byte getChecksum() {
    217         return checksum;
    218     }
    219     public void setChecksum(byte checksum) {
    220         this.checksum = checksum;
    221     }
    222     
    223 }
    复制代码

      3.2 SmartIotDecoder.java

      解码器,这个是本次的重点,这个解码器最主要是解决TCP粘包拆包问题,如果有不清楚的,要重点理解一下。 

    复制代码
      1 package com.wunaozai.iot.nettyplatform.code;
      2 
      3 import java.util.List;
      4 
      5 import org.slf4j.Logger;
      6 import org.slf4j.LoggerFactory;
      7 
      8 import io.netty.buffer.ByteBuf;
      9 import io.netty.channel.ChannelHandlerContext;
     10 import io.netty.handler.codec.ByteToMessageDecoder;
     11 
     12 /**
     13  * 自定义协议解析
     14  * @author Administrator
     15  *
     16  */
     17 public class SmartIotDecoder extends ByteToMessageDecoder {
     18 
     19     
     20     private static final Logger log = LoggerFactory.getLogger(SmartIotDecoder.class);
     21     
     22     @Override
     23     protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception {
     24         log.debug("启动解码器...");
     25         log.debug("目前数据缓存大小: " + buffer.readableBytes());
     26         // 刻度长度必须大于基本最小长度
     27         if(buffer.readableBytes() >= SmartIotProtocol.MIN_LEN){
     28             log.debug("符合最小长度,进行解析");
     29             //防止socket字节流攻击、客户端传来的数据过大,这里需要对数据进行过滤掉
     30             if(buffer.readableBytes() >= 4096){
     31                 buffer.skipBytes(buffer.readableBytes());
     32                 return ;
     33             }
     34             
     35             //记录包头开始位置
     36             int beginReader = 0;
     37             while(true){
     38                 beginReader = buffer.readerIndex(); //记录包头开始位置
     39                 buffer.markReaderIndex(); //标记包头开始index
     40                 //读取协议开始标志
     41                 if(buffer.readShort() == SmartIotProtocol.START){
     42                     break; //如果是开始标记,那么就结束查找
     43                 }
     44                 
     45                 //如果找不到包头,这里要一个一个字节跳过
     46                 buffer.resetReaderIndex();
     47                 buffer.readByte();
     48                 
     49                 //当跳过后,如果数据包又不符合长度的,结束本次协议解析
     50                 if(buffer.readableBytes() < SmartIotProtocol.MIN_LEN){
     51                     return ;
     52                 }
     53             }
     54             
     55             short flowid = buffer.readShort();
     56             byte version_major = buffer.readByte();
     57             byte version_minor = buffer.readByte();
     58             byte second = buffer.readByte();
     59             byte minute = buffer.readByte();
     60             byte hour = buffer.readByte();
     61             byte day = buffer.readByte();
     62             byte month = buffer.readByte();
     63             byte year = buffer.readByte();
     64             byte[] src = new byte[6];
     65             src[0] = buffer.readByte();
     66             src[1] = buffer.readByte();
     67             src[2] = buffer.readByte();
     68             src[3] = buffer.readByte();
     69             src[4] = buffer.readByte();
     70             src[5] = buffer.readByte();
     71             byte[] dest = new byte[6];
     72             dest[0] = buffer.readByte();
     73             dest[1] = buffer.readByte();
     74             dest[2] = buffer.readByte();
     75             dest[3] = buffer.readByte();
     76             dest[4] = buffer.readByte();
     77             dest[5] = buffer.readByte();
     78             short data_len = buffer.readShort();
     79             if(buffer.readableBytes() < data_len + 4){
     80                 //还原读指针
     81                 buffer.readerIndex(beginReader);
     82                 return ;
     83             }
     84             byte cmd = buffer.readByte();
     85             byte[] data = null;
     86             if(data_len > 0){
     87                 //读取应用数据单元
     88                 data = new byte[data_len];
     89                 buffer.readBytes(data);
     90             }
     91             
     92             byte checksum = buffer.readByte();
     93             short end = buffer.readShort();
     94             
     95             if(end == SmartIotProtocol.END){
     96                 log.debug("完成解析,并输出.");
     97                 SmartIotProtocol iot = new SmartIotProtocol();
     98                 iot.setFlowid(flowid);
     99                 iot.setVersion_major(version_major);
    100                 iot.setVersion_minor(version_minor);
    101                 iot.setSecond(second);
    102                 iot.setMinute(minute);
    103                 iot.setHour(hour);
    104                 iot.setDay(day);
    105                 iot.setMonth(month);
    106                 iot.setYear(year);
    107                 iot.setSrc(src);
    108                 iot.setDest(dest);
    109                 iot.setData_len(data_len);
    110                 iot.setCmd(cmd);
    111                 if(data_len > 0){
    112                     iot.setData(data);    
    113                 }else{
    114                     iot.setData(null);
    115                 }
    116                 iot.setChecksum(checksum);
    117                 out.add(iot);
    118             }
    119         }
    120     }
    121 
    122 }
    复制代码

      3.3 SmartIotEncoder.java

      相对于解码,这个编码器,就相对简单了,按照协议,一个byte一本byte进行发送即可。 

    复制代码
     1 package com.wunaozai.iot.nettyplatform.code;
     2 
     3 import io.netty.buffer.ByteBuf;
     4 import io.netty.channel.ChannelHandlerContext;
     5 import io.netty.handler.codec.MessageToByteEncoder;
     6 
     7 /**
     8  * 自定义协议数据解析
     9  * @author Administrator
    10  *
    11  */
    12 public class SmartIotEncoder extends MessageToByteEncoder<SmartIotProtocol> {
    13 
    14     @Override
    15     protected void encode(ChannelHandlerContext ctx, SmartIotProtocol msg, ByteBuf out) throws Exception {
    16         //写入消息SmartIot具体内容
    17         out.writeShort(SmartIotProtocol.START);
    18         out.writeShort(msg.getFlowid());
    19         out.writeByte(msg.getVersion_major());
    20         out.writeByte(msg.getVersion_minor());
    21         out.writeByte(msg.getSecond());
    22         out.writeByte(msg.getMinute());
    23         out.writeByte(msg.getHour());
    24         out.writeByte(msg.getDay());
    25         out.writeByte(msg.getMonth());
    26         out.writeByte(msg.getYear());
    27         out.writeBytes(msg.getSrc());
    28         out.writeBytes(msg.getDest());
    29         out.writeShort(msg.getData_len());
    30         out.writeByte(msg.getCmd());
    31         out.writeBytes(msg.getData());
    32         out.writeByte(msg.getChecksum());
    33         out.writeShort(SmartIotProtocol.END);
    34     }
    35 
    36 }
    复制代码

      3.4 SmartIotHandler.java

      这个是工程里面的主要业务操作类,用户Handler处理所有业务操作,这里也可以理解为是一个入口、网关。所有命令都从这里进行分发到子模块。 

    复制代码
     1 package com.wunaozai.iot.nettyplatform.code;
     2 
     3 import java.net.InetSocketAddress;
     4 
     5 import org.slf4j.Logger;
     6 import org.slf4j.LoggerFactory;
     7 
     8 import io.netty.channel.ChannelHandlerContext;
     9 import io.netty.channel.SimpleChannelInboundHandler;
    10 
    11 /**
    12  * 服务Handler 处理
    13  * @author Administrator
    14  *
    15  */
    16 public class SmartIotHandler extends SimpleChannelInboundHandler<SmartIotProtocol> {
    17 
    18     
    19     private static final Logger log = LoggerFactory.getLogger(SmartIotHandler.class);
    20 
    21     @Override
    22     protected void channelRead0(ChannelHandlerContext ctx, SmartIotProtocol iot)
    23             throws Exception {
    24         log.info("收到设备数据包: " + iot.getFlowid());
    25         iot.printDebugInfo();
    26         ctx.write("ok");
    27     }
    28     
    29     @Override
    30     public void channelActive(ChannelHandlerContext ctx) throws Exception {
    31         InetSocketAddress socket = (InetSocketAddress) ctx.channel().remoteAddress();
    32         String ip = socket.getAddress().getHostAddress();
    33         log.info("收到客户端IP: " + ip);
    34     }
    35     
    36     @Override
    37     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    38         ctx.close();
    39     }
    40 }
    复制代码

      3.5 NettyServerInitializer.java

      这个就是初始化本次Netty框架中,使用的编解码器,还有对应的处理类。 

    复制代码
     1 package com.wunaozai.iot.nettyplatform.config;
     2 
     3 import com.wunaozai.iot.nettyplatform.code.SmartIotDecoder;
     4 import com.wunaozai.iot.nettyplatform.code.SmartIotEncoder;
     5 import com.wunaozai.iot.nettyplatform.code.SmartIotHandler;
     6 
     7 import io.netty.channel.ChannelInitializer;
     8 import io.netty.channel.ChannelPipeline;
     9 import io.netty.channel.socket.SocketChannel;
    10 
    11 /**
    12  * 服务器初始化
    13  * @author Administrator
    14  *
    15  */
    16 public class NettyServerInitializer extends ChannelInitializer<SocketChannel> {
    17 
    18     @Override
    19     protected void initChannel(SocketChannel ch) throws Exception {
    20 //        ChannelPipeline pipeline = ch.pipeline();
    21 //        //自定义切割符
    22 //        //ByteBuf delimiter = Unpooled.copiedBuffer(new byte[] {16});
    23 //        ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes());
    24 //        
    25 //        pipeline.addLast(new DelimiterBasedFrameDecoder(8192, delimiter));
    26 //        pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
    27 //        pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
    28 //        pipeline.addLast(new NettyServerHandler());
    29         
    30         ChannelPipeline pipeline = ch.pipeline();
    31         //添加自定义编解码器
    32         pipeline.addLast(new SmartIotEncoder());
    33         pipeline.addLast(new SmartIotDecoder());
    34         //处理网络IO
    35         pipeline.addLast(new SmartIotHandler());
    36     }
    37 
    38 }
    复制代码

      3.6 NettyServer.java

      Netty功能的入口类,所有Netty框架初始化步骤都在这里进行简单处理。 

    复制代码
     1 package com.wunaozai.iot.nettyplatform.config;
     2 
     3 import org.slf4j.Logger;
     4 import org.slf4j.LoggerFactory;
     5 import org.springframework.stereotype.Component;
     6 
     7 import io.netty.bootstrap.ServerBootstrap;
     8 import io.netty.channel.ChannelFuture;
     9 import io.netty.channel.ChannelOption;
    10 import io.netty.channel.EventLoopGroup;
    11 import io.netty.channel.nio.NioEventLoopGroup;
    12 import io.netty.channel.socket.nio.NioServerSocketChannel;
    13 import io.netty.handler.logging.LogLevel;
    14 import io.netty.handler.logging.LoggingHandler;
    15 
    16 /**
    17  * Netty 服务器
    18  * @author Administrator
    19  *
    20  */
    21 @Component
    22 public class NettyServer {
    23     
    24     private static final Logger log = LoggerFactory.getLogger(NettyServer.class);
    25 
    26     private int port = 7777;
    27     
    28     public void run(){
    29         EventLoopGroup bossGroup = new NioEventLoopGroup();
    30         EventLoopGroup workerGroup = new NioEventLoopGroup();
    31         try {
    32             ServerBootstrap serverBootstrap = new ServerBootstrap();
    33             serverBootstrap.group(bossGroup, workerGroup);
    34             serverBootstrap.channel(NioServerSocketChannel.class);
    35             serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024);
    36             serverBootstrap.handler(new LoggingHandler(LogLevel.INFO));
    37             serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true);
    38             serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
    39             serverBootstrap.childHandler(new NettyServerInitializer());
    40             // 绑定端口,开始接收进来的连接
    41             ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
    42             log.info("netty服务启动: [port:" + port + "]");
    43             // 等待服务器socket关闭
    44             channelFuture.channel().closeFuture().sync();
    45         } catch (Exception e) {
    46             log.error("Netty 服务启动失败: " + e.getMessage());
    47         }finally {
    48             bossGroup.shutdownGracefully();
    49             workerGroup.shutdownGracefully();
    50         }
    51     }
    52 }
    复制代码

      3.7 IotNettyPlatFormApplication.java

       这个是Spring Boot项目的入口函数。在这里调用Netty的入口函数。

    复制代码
     1 package com.wunaozai.iot.nettyplatform;
     2 
     3 import org.slf4j.Logger;
     4 import org.slf4j.LoggerFactory;
     5 import org.springframework.boot.SpringApplication;
     6 import org.springframework.boot.autoconfigure.SpringBootApplication;
     7 import org.springframework.context.annotation.ComponentScan;
     8 import org.springframework.web.servlet.config.annotation.EnableWebMvc;
     9 
    10 import com.wunaozai.iot.nettyplatform.config.NettyServer;
    11 
    12 @SpringBootApplication
    13 public class IoTNettyPlatFormApplication {
    14 
    15     private static final Logger log = LoggerFactory.getLogger(IoTNettyPlatFormApplication.class);
    16 
    17     
    18     public static void main(String[] args) {
    19         SpringApplication.run(IoTNettyPlatFormApplication.class, args);
    20         run();
    21     }
    22 
    23     private static NettyServer nettyServer = new NettyServer();
    24     
    25     private static void run(){
    26         Thread thread = new Thread(new Runnable() {
    27             @Override
    28             public void run() {
    29                 nettyServer.run();                
    30             }
    31         });
    32         thread.start();
    33     }
    34     
    35 }
    复制代码

      我这里通过在@SpringBootApplication 这里调用NettyServer。同时还有其他方式:

      1) 通过实现ApplicationListener

    复制代码
     1 import org.slf4j.Logger;
     2 import org.slf4j.LoggerFactory;
     3 import org.springframework.context.ApplicationListener;
     4 import org.springframework.context.event.ContextRefreshedEvent;
     5 import org.springframework.stereotype.Component;
     6 
     7 /**
     8  * 项目初始化
     9  * @author wunaozai
    10  * @date 2018-05-24
    11  */
    12 @Component
    13 public class OnStartListener implements ApplicationListener<ContextRefreshedEvent> {
    14 
    15     private static final Logger log = LoggerFactory.getLogger(OnStartListener.class);
    16 
    17     @Override
    18     public void onApplicationEvent(ContextRefreshedEvent arg0) {
    19         log.info("Run on Start Listener.");
    20     }
    21 
    22 }
    复制代码

      2) 通过实现CommandLineRunner

    复制代码
     1 import org.slf4j.Logger;
     2 import org.slf4j.LoggerFactory;
     3 import org.springframework.boot.CommandLineRunner;
     4 import org.springframework.core.annotation.Order;
     5 import org.springframework.stereotype.Component;
     6 
     7 /**
     8  * 项目启动时初始化资源<br>
     9  * 如 一些初始化操作,提前加载加密证书,初始化线程池等
    10  * @author wunaozai
    11  * @date 2018-05-24
    12  */
    13 @Component
    14 @Order(value = 1) //执行顺序
    15 public class Runner implements CommandLineRunner {
    16 
    17     private static final Logger log = LoggerFactory.getLogger(Runner.class);
    18 
    19     @Override
    20     public void run(String... args) throws Exception {
    21         log.info("The Runner start to Initialize.");
    22     }
    23 
    24 }
    复制代码
  • 相关阅读:
    Promise关键知识
    CSS实现简易的轮播图
    绝对定位和相对定位的一些特性
    行内元素及其浮动
    webpack实践总结
    less语法详解
    js模拟事件
    jquery各种事件绑定的区别
    前端路由实现的关键知识点
    js鼠标事件相关知识
  • 原文地址:https://www.cnblogs.com/1124li/p/12308079.html
Copyright © 2011-2022 走看看