SpringBoot 整合 Netty 多端口監(jiān)聽(tīng)的操作方法
SpringBoot 整合 Netty 并監(jiān)聽(tīng)多端口
Netty 是由 JBOSS 提供的一個(gè) Java 開(kāi)源框架。Netty 提供異步的、基于事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用程序框架,用以快速開(kāi)發(fā)高性能、高可靠性的網(wǎng)絡(luò) IO 程序,是目前最流行的 NIO 框架,Netty 在互聯(lián)網(wǎng)領(lǐng)域、大數(shù)據(jù)分布式計(jì)算領(lǐng)域、游戲行業(yè)、通信行業(yè)等獲得了廣泛的應(yīng)用,知名的 Elasticsearch 、Dubbo 框架內(nèi)部都采用了 Netty。
1.依賴
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.28.Final</version>
</dependency>2.PortDefinition
讀取yml 配置中的多端口配置
//netty:
// port: {8300: A, 8500: B}
@Data
@Configuration
@ConfigurationProperties(prefix = "netty")
public class PortDefinition {
Map<Integer, String> port;
}3.GatewayType
多端口判斷使用的常量類(lèi)
public class GatewayType {
//個(gè)人設(shè)備
public final static String GERNESHEBEI_SHOUHUA="A";
}4.NettyServer
實(shí)現(xiàn)Netty服務(wù)端
@Slf4j
@RefreshScope
@Component
public class NettyServer {
@Autowired
private PortDefinition portDefinition;
public void start() throws InterruptedException {
/**
* 創(chuàng)建兩個(gè)線程組 bossGroup 和 workerGroup
* bossGroup 只是處理連接請(qǐng)求,真正的和客戶端業(yè)務(wù)處理,會(huì)交給 workerGroup 完成
* 兩個(gè)都是無(wú)線循環(huán)
*/
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//創(chuàng)建服務(wù)器端的啟動(dòng)對(duì)象,配置參數(shù)
ServerBootstrap bootstrap = new ServerBootstrap();
//設(shè)置兩個(gè)線程組
bootstrap.group(bossGroup, workerGroup)
//使用NioServerSocketChannel 作為服務(wù)器的通道實(shí)現(xiàn)
.channel(NioServerSocketChannel.class)
//設(shè)置線程隊(duì)列得到連接個(gè)數(shù)
.option(ChannelOption.SO_BACKLOG, 128)
//設(shè)置保持活動(dòng)連接狀態(tài)
.childOption(ChannelOption.SO_KEEPALIVE, true)
//通過(guò)NoDelay禁用Nagle,使消息立即發(fā)出去,不用等待到一定的數(shù)據(jù)量才發(fā)出去
.childOption(ChannelOption.TCP_NODELAY, true)
//可以給 bossGroup 加個(gè)日志處理器
.handler(new LoggingHandler(LogLevel.INFO))
//監(jiān)聽(tīng)多個(gè)端口
.childHandler(new SocketChannelInitHandler(portDefinition.getPort()))
;
// 監(jiān)聽(tīng)多個(gè)端口
Map<Integer, String> ports = portDefinition.getPort();
log.info("netty服務(wù)器在{}端口啟動(dòng)監(jiān)聽(tīng)", JSONObject.toJSONString(ports));
for (Map.Entry<Integer, String> p : ports.entrySet()) {
final int port = p.getKey();
// 綁定端口
ChannelFuture cf = bootstrap.bind(new InetSocketAddress(port)).sync();
if (cf.isSuccess()) {
log.info("netty 啟動(dòng)成功,端口:{}", port);
} else {
log.info("netty 啟動(dòng)失敗,端口:{}", port);
}
//對(duì)關(guān)閉通道進(jìn)行監(jiān)聽(tīng)
cf.channel().closeFuture().sync();
}
} finally {
//發(fā)送異常關(guān)閉
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}5.SocketChannelInitHandler
根據(jù)多端口去判斷去執(zhí)行那個(gè)業(yè)務(wù)的 Handler 方法
@Slf4j
public class SocketChannelInitHandler extends ChannelInitializer<SocketChannel> {
/**
* 用來(lái)存儲(chǔ)每個(gè)連接上來(lái)的設(shè)備
*/
public static final Map<ChannelId, ChannelPipeline> CHANNEL_MAP = new ConcurrentHashMap<>();
/**
* 端口信息,用來(lái)區(qū)分這個(gè)端口屬于哪種類(lèi)型的連接 如:8300 屬于 A
*/
Map<Integer, String> ports;
public SocketChannelInitHandler(Map<Integer, String> ports) {
this.ports = ports;
}
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//每次連接上來(lái) 對(duì)通道進(jìn)行保存
CHANNEL_MAP.put(socketChannel.id(), socketChannel.pipeline());
ChannelPipeline pipeline = socketChannel.pipeline();
int port = socketChannel.localAddress().getPort();
String type = ports.get(port);
pipeline.addLast(new StringEncoder(StandardCharsets.UTF_8));
pipeline.addLast(new StringDecoder(StandardCharsets.UTF_8));
pipeline.addLast(new LengthFieldBasedFrameDecoder(24*1024,0,2));
log.info("【initChannel】端口號(hào): "+port+" 類(lèi)型: "+type);
//不同類(lèi)型連接,處理鏈中加入不同處理協(xié)議
switch (type) {
case GatewayType.GERNESHEBEI_SHOUHUA:
//手環(huán)
pipeline.addLast(new NettyServerHandler());
break;
default:
log.error("當(dāng)前網(wǎng)關(guān)類(lèi)型并不存在于配置文件中,無(wú)法初始化通道");
break;
}
}
}6.NettyServerHandler
業(yè)務(wù)員的Handler 方法
@Slf4j
public class NettyServerHandler extends SimpleChannelInboundHandler<Object> {
//private static final Logger log = LoggerFactory.getLogger(NettyServerHandler.class);
protected void channelRead0(ChannelHandlerContext context, Object obj) throws Exception {
log.info(">>>>>>>>>>>服務(wù)端接收到客戶端的消息:{}",obj);
String message = (String)obj;
//之后寫(xiě)自己的業(yè)務(wù)邏輯即可
String b=message.replace("[", "")
.replace("]","");
String[] split1 = b.split("\\*");
String key = split1[1];
SocketChannel socketChannel = (SocketChannel) context.channel();
//調(diào)用業(yè)務(wù)代碼類(lèi)并執(zhí)行
WristWatchSocket.runSocket(key,message,socketChannel,true);
ReferenceCountUtil.release(obj);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}7.WristWatchSocket 業(yè)務(wù)代碼調(diào)用,根據(jù)自己的業(yè)務(wù)需要
@Slf4j
//@Data
public class WristWatchSocket{
//業(yè)務(wù)代碼
public static void runSocket(String key, String message, SocketChannel socketChannel, Boolean isNotFirst){
try {
if(message==null||message.trim().equals("")){
return;
}
String restr="測(cè)試發(fā)送";
if(!"".equals(restr)){
socketChannel.writeAndFlush(restr);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}8.配置文件配置多端口
netty:
port: {8300: A, 8500: B}9.配置Netty 啟動(dòng)
在啟動(dòng)類(lèi)中配置
@EnableAsync
@EnableSwagger2
@EnableFeignClients
@EnableTransactionManagement
@Slf4j
@MapperScan({"com.yuandian.platform.mapper"})
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
public class YunYiplatformApplication {
public static void main(String[] args) {
ApplicationContext run = SpringApplication.run(YunYiplatformApplication.class, args);
log.info("\n\n【【【【平臺(tái)成功啟動(dòng)!】】】】\n");
//netty 啟動(dòng)配置
try {
run.getBean(NettyServer.class).start();
}catch (Exception e){
e.printStackTrace();
}
}
}截圖


到此這篇關(guān)于SpringBoot 整合 Netty 并監(jiān)聽(tīng)多端口的文章就介紹到這了,更多相關(guān)SpringBoot 整合 Netty 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java實(shí)現(xiàn)protocol傳輸?shù)目蛻舳撕头?wù)端的示例代碼
本文主要介紹了java實(shí)現(xiàn)protocol傳輸?shù)目蛻舳撕头?wù)端的示例代碼,基于TCP協(xié)議的客戶端和服務(wù)端,包括了基本的連接、消息傳遞和關(guān)閉連接的操作,感興趣的可以了解一下2024-07-07
Spring Boot實(shí)現(xiàn)郵件注冊(cè)功能示例代碼
本篇文章主要介紹了Spring Boot實(shí)現(xiàn)郵件注冊(cè)功能示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05
計(jì)算機(jī)二級(jí)考試java軟件操作教程 教大家如何學(xué)習(xí)java
如何成為一名知識(shí)豐富的Java程序員,順利通過(guò)計(jì)算機(jī)二級(jí)Java考試,這篇文章主要主要教大家如何學(xué)習(xí)java,java的學(xué)習(xí)路線是什么,從何學(xué)起,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
Java執(zhí)行Python代碼的五種場(chǎng)景與示例方法
python可以搭建后端讓Java調(diào)用接口,但某些時(shí)候我們用到的python代碼可能并不多也許只有一個(gè)算法,此時(shí)就需要其他方法了,下面小編就來(lái)和大家詳細(xì)介紹一下吧2025-07-07
java使用Feign實(shí)現(xiàn)聲明式Restful風(fēng)格調(diào)用
這篇文章主要為大家詳細(xì)介紹了java使用Feign實(shí)現(xiàn)聲明式Restful風(fēng)格調(diào)用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-04-04
SpringBoot項(xiàng)目打包發(fā)布到外部tomcat(出現(xiàn)各種異常的解決)
這篇文章主要介紹了SpringBoot項(xiàng)目打包發(fā)布到外部tomcat(出現(xiàn)各種異常的解決),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
Mybatis-plus中的@EnumValue注解使用詳解
這篇文章主要介紹了Mybatis-plus中的@EnumValue注解使用詳解,在PO類(lèi)中,如果我們直接使用枚舉類(lèi)型去映射數(shù)據(jù)庫(kù)的對(duì)應(yīng)字段保存時(shí),往往就會(huì)因?yàn)轭?lèi)型不匹配導(dǎo)致映射失敗,Mybatis-plus提供了一種解決辦法,就是使用@EnumValue注解,需要的朋友可以參考下2024-02-02
Java并發(fā)編程之ReentrantLock實(shí)現(xiàn)原理及源碼剖析
ReentrantLock 是常用的鎖,相對(duì)于Synchronized ,lock鎖更人性化,閱讀性更強(qiáng),文中將會(huì)詳細(xì)的說(shuō)明,請(qǐng)君往下閱讀2021-09-09

