断线重连,心跳检测

This commit is contained in:
wenc000 2020-07-31 19:24:05 +08:00
parent ab63d47dac
commit 9441aa1c83
14 changed files with 752 additions and 0 deletions

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cm-cloud</artifactId>
<groupId>com.cm</groupId>
<version>1.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-central-control-client</artifactId>
<dependencies>
<dependency>
<groupId>com.cm</groupId>
<artifactId>cloud-common-socket</artifactId>
<version>1.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,83 @@
package com.cm.central.control.client.socket.config.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: SocketClientProperties
* @Description: Socket客户端配置
* @Author: WangGeng
* @Date: 2020/7/29 10:06 上午
* @Version: 1.0
**/
@Component
@ConfigurationProperties(prefix = "socket.central-control.client")
public class SocketClientProperties {
private String clientId;
private String clientSecret;
private String host = "127.0.0.1";
private int port = 9999;
private int maxReconnectCount = 20;
private int reconnectTimeStep = 0;
private int delayPingSeconds = 3;
public String getClientId() {
return clientId == null ? "" : clientId.trim();
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getClientSecret() {
return clientSecret == null ? "" : clientSecret.trim();
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
public String getHost() {
return host == null ? "" : host.trim();
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public int getMaxReconnectCount() {
return maxReconnectCount <= 0 ? 20 : maxReconnectCount;
}
public void setMaxReconnectCount(int maxReconnectCount) {
this.maxReconnectCount = maxReconnectCount;
}
public int getReconnectTimeStep() {
return reconnectTimeStep <= 0 ? 0 : reconnectTimeStep;
}
public void setReconnectTimeStep(int reconnectTimeStep) {
this.reconnectTimeStep = reconnectTimeStep;
}
public int getDelayPingSeconds() {
return delayPingSeconds <= 0 ? 3 : delayPingSeconds;
}
public void setDelayPingSeconds(int delayPingSeconds) {
this.delayPingSeconds = delayPingSeconds;
}
}

View File

@ -0,0 +1,67 @@
package com.cm.central.control.client.socket.handler;
import com.cm.central.control.client.socket.config.properties.SocketClientProperties;
import com.cm.central.control.client.socket.socket.SocketClientRunnable;
import com.cm.socket.decoder.MessageDecoder;
import com.cm.socket.encoder.MessageEncoder;
import com.cm.socket.service.ISocketService;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: MessageClientChannelInitializer
* @Description: 消息客户端初始化
* @Author: WangGeng
* @Date: 2020/7/6 9:32 上午
* @Version: 1.0
**/
@Component
public class SocketClientChannelInitializer extends ChannelInitializer<SocketChannel> {
@Autowired
private SocketClientRunnable socketClientRunnable;
@Autowired
private SocketClientProperties socketClientProperties;
@Resource(name = "pingServiceImpl")
private ISocketService pingServiceImpl;
@Resource(name = "clientInfoServiceImpl")
private ISocketService clientInfoServiceImpl;
@Resource(name = "exceptionServiceImpl")
private ISocketService exceptionServiceImpl;
@Resource(name = "loginServiceImpl")
private ISocketService loginServiceImpl;
@Resource(name = "errorServiceImpl")
private ISocketService errorServiceImpl;
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new MessageEncoder());
ch.pipeline().addLast(new MessageDecoder());
ch.pipeline().addLast(getSocketClientHandler());
}
/**
* 获取消息处理器
*
* @return
*/
private SocketClientHandler getSocketClientHandler() {
SocketClientHandler socketClientHandler = new SocketClientHandler();
socketClientHandler.setClientInfoServiceImpl(clientInfoServiceImpl);
socketClientHandler.setExceptionServiceImpl(exceptionServiceImpl);
socketClientHandler.setLoginServiceImpl(loginServiceImpl);
socketClientHandler.setPingServiceImpl(pingServiceImpl);
socketClientHandler.setErrorServiceImpl(errorServiceImpl);
socketClientHandler.setSocketClientProperties(socketClientProperties);
socketClientHandler.setSocketClientRunnable(socketClientRunnable);
return socketClientHandler;
}
}

View File

@ -0,0 +1,110 @@
package com.cm.central.control.client.socket.handler;
import com.cm.central.control.client.socket.config.properties.SocketClientProperties;
import com.cm.central.control.client.socket.manager.SocketClientManager;
import com.cm.central.control.client.socket.socket.SocketClientRunnable;
import com.cm.socket.enums.SocketTypeMessageEnum;
import com.cm.socket.pojo.Message;
import com.cm.socket.service.ISocketService;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.TimeUnit;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: MessageClientHandler
* @Description: 消息客户端处理器
* @Author: WangGeng
* @Date: 2020/7/6 9:34 上午
* @Version: 1.0
**/
public class SocketClientHandler extends SimpleChannelInboundHandler<Message> {
private static final Logger LOG = LoggerFactory.getLogger(SocketClientHandler.class);
private SocketClientRunnable socketClientRunnable;
private SocketClientProperties socketClientProperties;
private ISocketService pingServiceImpl;
private ISocketService clientInfoServiceImpl;
private ISocketService exceptionServiceImpl;
private ISocketService loginServiceImpl;
private ISocketService errorServiceImpl;
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
LOG.debug("与服务器建立Socket链接已经建立登录");
loginServiceImpl.autoReply(ctx);
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, Message message) throws Exception {
if (message.getType() == SocketTypeMessageEnum.MESSAGE_TYPE_PONG.getType()) {
pingServiceImpl.readMessage(ctx, message);
} else if (message.getType() == SocketTypeMessageEnum.MESSAGE_TYPE_CLIENT_LOGIN.getType()) {
loginServiceImpl.readMessage(ctx, message);
} else if (message.getType() == SocketTypeMessageEnum.MESSAGE_TYPE_EXCEPTION.getType()) {
exceptionServiceImpl.readMessage(ctx, message);
} else if (message.getType() == SocketTypeMessageEnum.MESSAGE_TYPE_ERROR.getType()) {
errorServiceImpl.readMessage(ctx, message);
}
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
LOG.error("与服务断开连接");
SocketClientManager socketClientManager = SocketClientManager.getInstance();
int currentReconnectCount = socketClientManager.getCurrentReconnectCount();
int waitTime = socketClientManager.getCurrentReconnectTime();
if (socketClientManager.getCurrentReconnectCount() > socketClientProperties.getMaxReconnectCount()) {
LOG.error("服务器重连失败");
throw new RuntimeException("服务器重连失败");
}
LOG.error(waitTime + "s后进行第" + currentReconnectCount + "次重连");
ctx.channel().eventLoop().schedule(() -> {
LOG.debug("重新登录...");
socketClientRunnable.run();
}, waitTime, TimeUnit.SECONDS);
socketClientManager.setCurrentReconnectCount(++currentReconnectCount);
if (socketClientProperties.getReconnectTimeStep() > 0) {
socketClientManager.setCurrentReconnectTime(waitTime + socketClientProperties.getReconnectTimeStep());
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
LOG.error(cause.getMessage(), cause);
ctx.close();
}
public void setSocketClientRunnable(SocketClientRunnable socketClientRunnable) {
this.socketClientRunnable = socketClientRunnable;
}
public void setSocketClientProperties(SocketClientProperties socketClientProperties) {
this.socketClientProperties = socketClientProperties;
}
public void setPingServiceImpl(ISocketService pingServiceImpl) {
this.pingServiceImpl = pingServiceImpl;
}
public void setClientInfoServiceImpl(ISocketService clientInfoServiceImpl) {
this.clientInfoServiceImpl = clientInfoServiceImpl;
}
public void setExceptionServiceImpl(ISocketService exceptionServiceImpl) {
this.exceptionServiceImpl = exceptionServiceImpl;
}
public void setLoginServiceImpl(ISocketService loginServiceImpl) {
this.loginServiceImpl = loginServiceImpl;
}
public void setErrorServiceImpl(ISocketService errorServiceImpl) {
this.errorServiceImpl = errorServiceImpl;
}
}

View File

@ -0,0 +1,67 @@
package com.cm.central.control.client.socket.manager;
import io.netty.channel.Channel;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: SocketClientManager
* @Description: Socket客户端控制器
* @Author: WangGeng
* @Date: 2020/7/29 3:12 下午
* @Version: 1.0
**/
public class SocketClientManager {
private static SocketClientManager socketClientManager = SocketClientManagerBuilder.socketClientManager;
private String token;
private int currentReconnectCount = 1;
private int currentReconnectTime = 1;
private Channel channel;
private SocketClientManager() {
}
public static SocketClientManager getInstance() {
return socketClientManager;
}
public void setToken(String token) {
this.token = token;
}
public String getToken() {
return token == null ? "" : token.trim();
}
public int getCurrentReconnectCount() {
return currentReconnectCount;
}
public void setCurrentReconnectCount(int currentReconnectCount) {
this.currentReconnectCount = currentReconnectCount;
}
public int getCurrentReconnectTime() {
return currentReconnectTime;
}
public void setCurrentReconnectTime(int currentReconnectTime) {
this.currentReconnectTime = currentReconnectTime;
}
private static class SocketClientManagerBuilder {
public static SocketClientManager socketClientManager = new SocketClientManager();
}
public Channel getChannel() {
return channel;
}
public void setChannel(Channel channel) {
this.channel = channel;
}
}

View File

@ -0,0 +1,16 @@
package com.cm.central.control.client.socket.service;
import com.cm.common.base.AbstractService;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: BaseService
* @Description: 基础业务
* @Author: WangGeng
* @Date: 2020/7/29 10:41 上午
* @Version: 1.0
**/
public class BaseService extends AbstractService {
}

View File

@ -0,0 +1,81 @@
package com.cm.central.control.client.socket.service.socket;
import com.cm.central.control.client.socket.manager.SocketClientManager;
import com.cm.central.control.client.socket.service.BaseService;
import com.cm.socket.enums.SocketTypeMessageEnum;
import com.cm.socket.pojo.Message;
import com.cm.socket.service.AbstractSocketService;
import com.cm.socket.service.ISocketService;
import io.netty.channel.ChannelHandlerContext;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: AbstractSocketService
* @Description: socket业务
* @Author: WangGeng
* @Date: 2020/7/29 10:40 上午
* @Version: 1.0
**/
public abstract class BaseSocketService extends AbstractSocketService {
@Override
public void readMessage(ChannelHandlerContext channelHandlerContext, Message readMessage) {
readMessageService(channelHandlerContext, readMessage);
}
/**
* 读取信息业务
*
* @param channelHandlerContext
* @param readMessage
*/
@Override
protected abstract void readMessageService(ChannelHandlerContext channelHandlerContext, Message readMessage);
/**
* 输出信息
*
* @param channelHandlerContext
* @param socketTypeMessageEnum
* @param content
*/
@Override
public void writeMessage(ChannelHandlerContext channelHandlerContext, SocketTypeMessageEnum socketTypeMessageEnum, String content) {
Message message = new Message();
message.setStart(SocketTypeMessageEnum.MESSAGE_TYPE_START.getType());
message.setType(socketTypeMessageEnum.getType());
message.setToken(SocketClientManager.getInstance().getToken());
message.setContent(content);
write(channelHandlerContext, message);
}
/**
* 输出错误信息
*
* @param channelHandlerContext
* @param errorMessage
*/
@Override
public void writeError(ChannelHandlerContext channelHandlerContext, String errorMessage) {
Message message = new Message();
message.setStart(SocketTypeMessageEnum.MESSAGE_TYPE_START.getType());
message.setType(SocketTypeMessageEnum.MESSAGE_TYPE_ERROR.getType());
message.setToken(SocketClientManager.getInstance().getToken());
message.setContent(errorMessage);
write(channelHandlerContext, message);
}
/**
* 输出数据
*
* @param channelHandlerContext
* @param writeMessage
*/
@Override
protected void write(ChannelHandlerContext channelHandlerContext, Message writeMessage) {
channelHandlerContext.channel().writeAndFlush(writeMessage);
}
}

View File

@ -0,0 +1,30 @@
package com.cm.central.control.client.socket.service.socket.clientinfo;
import com.cm.central.control.client.socket.service.socket.BaseSocketService;
import com.cm.socket.pojo.Message;
import io.netty.channel.ChannelHandlerContext;
import org.springframework.stereotype.Service;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: ClientInfoServiceImpl
* @Description: 客户端信息
* @Author: WangGeng
* @Date: 2020/7/29 2:42 下午
* @Version: 1.0
**/
@Service("clientInfoServiceImpl")
public class ClientInfoServiceImpl extends BaseSocketService {
@Override
protected void readMessageService(ChannelHandlerContext channelHandlerContext, Message readMessage) {
}
@Override
public void autoReply(ChannelHandlerContext channelHandlerContext) {
}
}

View File

@ -0,0 +1,33 @@
package com.cm.central.control.client.socket.service.socket.error;
import com.alibaba.fastjson.JSONObject;
import com.cm.central.control.client.socket.service.socket.BaseSocketService;
import com.cm.socket.pojo.Message;
import com.cm.socket.pojo.SocketResult;
import io.netty.channel.ChannelHandlerContext;
import org.springframework.stereotype.Service;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: ErrorServiceImpl
* @Description: error业务
* @Author: WangGeng
* @Date: 2020/7/29 10:22 下午
* @Version: 1.0
**/
@Service("errorServiceImpl")
public class ErrorServiceImpl extends BaseSocketService {
@Override
protected void readMessageService(ChannelHandlerContext channelHandlerContext, Message readMessage) {
SocketResult<String> result = JSONObject.parseObject(readMessage.getContent(), SocketResult.class);
LOG.error(result.getErrorMsg());
}
@Override
public void autoReply(ChannelHandlerContext channelHandlerContext) {
}
}

View File

@ -0,0 +1,30 @@
package com.cm.central.control.client.socket.service.socket.exception;
import com.cm.central.control.client.socket.service.socket.BaseSocketService;
import com.cm.socket.pojo.Message;
import io.netty.channel.ChannelHandlerContext;
import org.springframework.stereotype.Service;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: ExceptionServiceImpl
* @Description: 异常业务
* @Author: WangGeng
* @Date: 2020/7/29 2:41 下午
* @Version: 1.0
**/
@Service("exceptionServiceImpl")
public class ExceptionServiceImpl extends BaseSocketService {
@Override
protected void readMessageService(ChannelHandlerContext channelHandlerContext, Message readMessage) {
}
@Override
public void autoReply(ChannelHandlerContext channelHandlerContext) {
}
}

View File

@ -0,0 +1,68 @@
package com.cm.central.control.client.socket.service.socket.login;
import com.alibaba.fastjson.JSONObject;
import com.cm.central.control.client.socket.config.properties.SocketClientProperties;
import com.cm.central.control.client.socket.manager.SocketClientManager;
import com.cm.central.control.client.socket.service.socket.BaseSocketService;
import com.cm.socket.consts.ISocketConst;
import com.cm.socket.enums.SocketTypeMessageEnum;
import com.cm.socket.pojo.Message;
import com.cm.socket.pojo.SocketResult;
import com.cm.socket.service.ISocketService;
import io.netty.channel.ChannelHandlerContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: LoginServiceImpl
* @Description: 登录业务
* @Author: WangGeng
* @Date: 2020/7/29 2:40 下午
* @Version: 1.0
**/
@Service("loginServiceImpl")
public class LoginServiceImpl extends BaseSocketService {
@Autowired
private SocketClientProperties socketClientProperties;
@Resource(name = "pingServiceImpl")
private ISocketService pingServiceImpl;
@Override
public void readMessage(ChannelHandlerContext channelHandlerContext, Message readMessage) {
readMessageService(channelHandlerContext, readMessage);
}
@Override
protected void readMessageService(ChannelHandlerContext channelHandlerContext, Message readMessage) {
SocketResult<String> socketResult = JSONObject.parseObject(readMessage.getContent(), SocketResult.class);
SocketClientManager socketClientManager = SocketClientManager.getInstance();
// 初始化重连
socketClientManager.setCurrentReconnectCount(1);
socketClientManager.setCurrentReconnectTime(1);
socketClientManager.setToken(socketResult.getData());
socketClientManager.setChannel(channelHandlerContext.channel());
LOG.debug("登录成功,开启 ping-pong 心跳");
pingServiceImpl.autoReply(channelHandlerContext);
}
@Override
public void autoReply(ChannelHandlerContext channelHandlerContext) {
String clientId = socketClientProperties.getClientId();
String clientSecret = socketClientProperties.getClientSecret();
Message message = new Message();
message.setStart(SocketTypeMessageEnum.MESSAGE_TYPE_START.getType());
message.setType(SocketTypeMessageEnum.MESSAGE_TYPE_CLIENT_LOGIN.getType());
JSONObject loginObj = new JSONObject();
loginObj.put(ISocketConst.CLIENT_ID, clientId);
loginObj.put(ISocketConst.CLIENT_SECRET, clientSecret);
message.setContent(loginObj.toJSONString());
channelHandlerContext.channel().writeAndFlush(message);
}
}

View File

@ -0,0 +1,54 @@
package com.cm.central.control.client.socket.service.socket.ping;
import com.cm.central.control.client.socket.config.properties.SocketClientProperties;
import com.cm.central.control.client.socket.service.socket.BaseSocketService;
import com.cm.socket.enums.SocketMessageEnum;
import com.cm.socket.enums.SocketTypeMessageEnum;
import com.cm.socket.pojo.Message;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.concurrent.ScheduledFuture;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: PingServiceImpl
* @Description: PING业务
* @Author: WangGeng
* @Date: 2020/7/29 10:51 上午
* @Version: 1.0
**/
@Component("pingServiceImpl")
public class PingServiceImpl extends BaseSocketService {
@Autowired
private SocketClientProperties socketClientProperties;
@Override
protected void readMessageService(ChannelHandlerContext channelHandlerContext, Message readMessage) {
System.out.println(readMessage.getToken() + ": " + readMessage.getContent());
}
@Override
public void autoReply(ChannelHandlerContext channelHandlerContext) {
Channel channel = channelHandlerContext.channel();
ScheduledFuture<?> scheduledFuture = channel.eventLoop().schedule(() -> {
if (channel.isActive()) {
writeMessage(channelHandlerContext, SocketTypeMessageEnum.MESSAGE_TYPE_PING, SocketMessageEnum.MESSAGE_PING.getMessage());
} else {
channelHandlerContext.close();
throw new RuntimeException();
}
}, socketClientProperties.getDelayPingSeconds(), TimeUnit.SECONDS);
scheduledFuture.addListener(future -> {
if (future.isSuccess()) {
autoReply(channelHandlerContext);
}
});
}
}

View File

@ -0,0 +1,61 @@
package com.cm.central.control.client.socket.socket;
import com.cm.central.control.client.socket.config.properties.SocketClientProperties;
import com.cm.central.control.client.socket.handler.SocketClientChannelInitializer;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: SocketClient
* @Description: Socket客户端
* @Author: WangGeng
* @Date: 2020/7/29 10:29 上午
* @Version: 1.0
**/
@Component
public class SocketClientRunnable implements Runnable, InitializingBean {
private static final Logger LOG = LoggerFactory.getLogger(SocketClientRunnable.class);
@Autowired
private SocketClientProperties socketClientProperties;
@Autowired
private SocketClientChannelInitializer socketClientChannelInitializer;
private Bootstrap bootstrap = new Bootstrap();
private EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
@Override
public void afterPropertiesSet() throws Exception {
bootstrap.group(eventLoopGroup);
bootstrap.channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
bootstrap.handler(socketClientChannelInitializer);
}
@Override
public void run() {
try {
ChannelFuture channelFuture = bootstrap.connect(socketClientProperties.getHost(), socketClientProperties.getPort());
channelFuture.addListener((ChannelFutureListener) future -> {
if (!future.isSuccess()) {
future.channel().pipeline().fireChannelInactive();
}
});
channelFuture.channel().closeFuture();
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
}
}

View File

@ -0,0 +1,30 @@
package com.cm.central.control.client.socket.startup;
import com.cm.central.control.client.socket.socket.SocketClientRunnable;
import com.cm.socket.pojo.SocketClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: SocketClientStartUp
* @Description: Socket客户端启动
* @Author: WangGeng
* @Date: 2020/7/29 4:55 下午
* @Version: 1.0
**/
@Component
public class SocketClientStartUp implements ApplicationRunner {
@Autowired
private SocketClientRunnable socketClientRunnable;
@Override
public void run(ApplicationArguments args) throws Exception {
new Thread(socketClientRunnable).start();
}
}