物联网架构成长之路(35)-利用Netty解析物联网自定义协议

一、前言

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

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

 

 二、协议

定义

描述

启动符‘@@

2字节)

数据包的第12字节,为固定值 6464

控制单元

 

业务流水号

2字节)

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

协议版本号

2字节)

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

时间标签

6字节)

数据包的第712字节,为数据包发出的时间,具体定义表2

源地址

6字节)

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

目的地址

6字节)

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

应用数据单元长度

2字节)

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

命令字节

1字节)

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

应用数据单元

(最大1024字节)

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

校验和

1字节)

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

结束符‘##

2字节)

为固定值 3535

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

 

三、代码部分

  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) + "\tFlowID:" + 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 }

 

三、协议测试

 

四、简单架构

  由于引入了自定义协议,所以需要对原先的流程进行简单的改造,下面这个图是某项目的架构图。

 

 

参考资料:

  https://www.cnblogs.com/sidesky/p/6913109.html

 

架构系列: https://www.cnblogs.com/wunaozai/p/8067577.html

本文地址: https://www.cnblogs.com/wunaozai/p/11403015.html

 

posted @ 2019-08-25 21:26  无脑仔的小明  阅读(10705)  评论(11编辑  收藏  举报