netty結合java_spring boot整合netty的實現方法

之前花了幾天去研究怎麼使用netty做一個閘道器伺服器,雖然最後還是沒能用上我做的閘道器,但是呢netty是會用了,總結一下netty和spring boot整合。感覺不用spring boot都不會寫程式碼了。哈哈哈

在pom檔案中新增相關的依賴,這裡主要的就是netty的依賴,spring boot的相關依賴本文不提

io.netty

netty-all

4.1.19.Final

SpringBoot-Netty

SpringBoot-Netty

1.0-SNAPSHOT

在application.yml檔案中配置

#不能用localhost,否則啟動報異常:Unresolved address

#tcp監聽的連接埠

tcp:

port: 8090

# bossGroup的執行緒數

boss:

thread:

count: 2

# worker的執行緒數

worker:

thread:

count: 2

#是否使用長連接

so:

keepalive: true

backlog: 100

3.撰寫NettyConfig netty的配置。

package com.advsun.netty.config;

import com.advsun.netty.handlers.StringProtocolInitalizer;

import io.netty.bootstrap.ServerBootstrap;

import io.netty.channel.ChannelOption;

import io.netty.channel.nio.NioEventLoopGroup;

import io.netty.channel.socket.nio.NioServerSocketChannel;

import io.netty.handler.codec.string.StringDecoder;

import io.netty.handler.codec.string.StringEncoder;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

import java.net.InetSocketAddress;

import java.util.HashMap;

import java.util.Map;

import java.util.Set;

/**

* @author 楊紅星

* @version 1.0.0

*/

@Configuration

public class NettyConfig {

//讀取yml中配置

@Value("${boss.thread.count}")

private int bossCount;

@Value("${worker.thread.count}")

private int workerCount;

@Value("${tcp.port}")

private int tcpPort;

@Value("${so.keepalive}")

private boolean keepAlive;

@Value("${so.backlog}")

private int backlog;

@Autowired

@Qualifier("springProtocolInitializer")

private StringProtocolInitalizer protocolInitalizer;

//bootstrap配置

@SuppressWarnings("unchecked")

@Bean(name = "serverBootstrap")

public ServerBootstrap bootstrap() {

ServerBootstrap b = new ServerBootstrap();

b.group(bossGroup(), workerGroup())

.channel(NioServerSocketChannel.class)

.childHandler(protocolInitalizer);

Map, Object> tcpChannelOptions = tcpChannelOptions();

Set> keySet = tcpChannelOptions.keySet();

for (@SuppressWarnings("rawtypes")

ChannelOption option : keySet) {

b.option(option, tcpChannelOptions.get(option));

}

return b;

}

@Bean(name = "bossGroup", destroyMethod = "shutdownGracefully")

public NioEventLoopGroup bossGroup() {

return new NioEventLoopGroup(bossCount);

}

@Bean(name = "workerGroup", destroyMethod = "shutdownGracefully")

public NioEventLoopGroup workerGroup() {

return new NioEventLoopGroup(workerCount);

}

@Bean(name = "tcpSocketAddress")

public InetSocketAddress tcpPort() {

return new InetSocketAddress(tcpPort);

}

@Bean(name = "tcpChannelOptions")

public Map, Object> tcpChannelOptions() {

Map, Object> options = new HashMap, Object>();

options.put(ChannelOption.SO_KEEPALIVE, keepAlive);

options.put(ChannelOption.SO_BACKLOG, backlog);

return options;

}

@Bean(name = "stringEncoder")

public StringEncoder stringEncoder() {

return new StringEncoder();

}

@Bean(name = "stringDecoder")

public StringDecoder stringDecoder() {

return new StringDecoder();

}

/**

* Necessary to make the Value annotations work.

*

* @return

*/

@Bean

public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {

return new PropertySourcesPlaceholderConfigurer();

}

}

4.初始化的相關配置

package com.advsun.netty.handlers;

import io.netty.channel.ChannelInitializer;

import io.netty.channel.ChannelPipeline;

import io.netty.channel.socket.SocketChannel;

import io.netty.handler.codec.string.StringDecoder;

import io.netty.handler.codec.string.StringEncoder;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.stereotype.Component;

/**

* @author 楊紅星

* @version 1.0.0

*/

@Component

@Qualifier("springProtocolInitializer")

public class StringProtocolInitalizer extends ChannelInitializer {

@Autowired

StringDecoder stringDecoder;

@Autowired

StringEncoder stringEncoder;

@Autowired

ServerHandler serverHandler;

@Override

protected void initChannel(SocketChannel ch) throws Exception {

ChannelPipeline pipeline = ch.pipeline();

pipeline.addLast("decoder", stringDecoder);

pipeline.addLast("handler", serverHandler);

pipeline.addLast("encoder", stringEncoder);

}

public StringDecoder getStringDecoder() {

return stringDecoder;

}

public void setStringDecoder(StringDecoder stringDecoder) {

this.stringDecoder = stringDecoder;

}

public StringEncoder getStringEncoder() {

return stringEncoder;

}

public void setStringEncoder(StringEncoder stringEncoder) {

this.stringEncoder = stringEncoder;

}

public ServerHandler getServerHandler() {

return serverHandler;

}

public void setServerHandler(ServerHandler serverHandler) {

this.serverHandler = serverHandler;

}

}

5.tcp服務的配置

package com.advsun.netty.config;

import io.netty.bootstrap.ServerBootstrap;

import io.netty.channel.ChannelFuture;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

import javax.annotation.PreDestroy;

import java.net.InetSocketAddress;

/**

* @author 楊紅星

* @version 1.0.0

*/

@Component

public class TCPServer {

@Autowired

@Qualifier("serverBootstrap")

private ServerBootstrap b;

@Autowired

@Qualifier("tcpSocketAddress")

private InetSocketAddress tcpPort;

private ChannelFuture serverChannelFuture;

@PostConstruct

public void start() throws Exception {

System.out.println("Starting server at " + tcpPort);

serverChannelFuture = b.bind(tcpPort).sync();

}

@PreDestroy

public void stop() throws Exception {

serverChannelFuture.channel().closeFuture().sync();

}

public ServerBootstrap getB() {

return b;

}

public void setB(ServerBootstrap b) {

this.b = b;

}

public InetSocketAddress getTcpPort() {

return tcpPort;

}

public void setTcpPort(InetSocketAddress tcpPort) {

this.tcpPort = tcpPort;

}

}

6.serverHandler配置這裡是實現業務邏輯的地方

package com.advsun.netty.handlers;

import io.netty.channel.ChannelHandler;

import io.netty.channel.ChannelHandlerContext;

import io.netty.channel.SimpleChannelInboundHandler;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.stereotype.Component;

import java.net.InetAddress;

/**

* @author 楊紅星

* @version 1.0.0

*/

@Component

@Qualifier("serverHandler")

@ChannelHandler.Sharable

public class ServerHandler extends SimpleChannelInboundHandler {

private static final Logger log = LoggerFactory.getLogger(ServerHandler.class);

@Override

public void channelRead0(ChannelHandlerContext ctx, String msg)

throws Exception {

log.info("client msg:"+msg);

String clientIdToLong= ctx.channel().id().asLongText();

log.info("client long id:"+clientIdToLong);

String clientIdToShort= ctx.channel().id().asShortText();

log.info("client short id:"+clientIdToShort);

if(msg.indexOf("bye")!=-1){

//close

ctx.channel().close();

}else{

//send to client

ctx.channel().writeAndFlush("Yoru msg is:"+msg);

}

}

@Override

public void channelActive(ChannelHandlerContext ctx) throws Exception {

log.info("RamoteAddress : " + ctx.channel().remoteAddress() + " active !");

ctx.channel().writeAndFlush( "Welcome to " + InetAddress.getLocalHost().getHostName() + " service!
");

super.channelActive(ctx);

}

@Override

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {

cause.printStackTrace();

ctx.close();

}

@Override

public void channelInactive(ChannelHandlerContext ctx) throws Exception {

log.info("
Channel is disconnected");

super.channelInactive(ctx);

}

}

這裡的 channelRead0(ChannelHandlerContext ctx, String msg)當客戶機有訊息發送過來時會呼叫這個方法,這個方法的名字叫的是真的差,所以netty5.0之後取消了這個名字, 5.0之後叫messageReceived。官方都說這名字叫的傻逼

channelRead0() → messageReceived()

I know. It was a silly mistake. If you are using SimpleChannelInboundHandler, you have to rename channelRead0() to messageReceived().

最後在貼一張自己在看netty實作時候畫的思維導圖

f174e9acba629c91e8dc2c49dfdc2d66.png

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援腳本之家。