SpringBoot 에서 Netty 프레임 워 크 를 통합 하 는 상세 한 튜 토리 얼
13884 단어 SpringBoot통합Netty
Netty 와 SpringBoot 의 통합 은 단지 몇 곳 을 통합 시 키 는 것 이 라 고 생각 합 니 다.
SpringBoot 에서 Netty 를 사용 하여 Websocket 서 비 스 를 제공 하 는 사례 를 보 여 줍 니 다.
servlet 용기 자체 가 웹 소켓 의 실현 을 제 공 했 지만,여기 서 netty 의 실현:sparklingheart:
의존 도 를 높이다
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
네,버 전 번 호 를 밝 힐 필요 가 없습니다.spring-boot-dependencies 에서 최신 netty 의존 도 를 밝 혔 기 때문이다.Yml 를 통 해 기본 속성 설정
server:
port: 80
logging:
level:
root: DEBUG
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
shutdown:
enabled: true
netty:
websocket:
# Websocket
port: 1024
#
ip: 0.0.0.0
#
max-frame-size: 10240
# URI
path: /channel
앱 은'actuator'를 사용 하고 노출shutdown
점 을 켜 서 SpringBoot 앱 을 우아 하 게 정지 시 킬 수 있 습 니 다.웹 소켓 서비스 와 관련 된 설정 을netty.websocket.*
통 해 설정 합 니 다.응용 프로그램 Runner 를 통 해 웹 소켓 서 비 스 를 시작 합 니 다.
import java.net.InetSocketAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.stereotype.Component;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.springboot.netty.websocket.handler.WebsocketMessageHandler;
/**
* Netty
* @author Administrator
*/
@Component
public class NettyBootsrapRunner implements ApplicationRunner, ApplicationListener<ContextClosedEvent>, ApplicationContextAware {
private static final Logger LOGGER = LoggerFactory.getLogger(NettyBootsrapRunner.class);
@Value("${netty.websocket.port}")
private int port;
@Value("${netty.websocket.ip}")
private String ip;
@Value("${netty.websocket.path}")
private String path;
@Value("${netty.websocket.max-frame-size}")
private long maxFrameSize;
private ApplicationContext applicationContext;
private Channel serverChannel;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void run(ApplicationArguments args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup);
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.localAddress(new InetSocketAddress(this.ip, this.port));
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new ChunkedWriteHandler());
pipeline.addLast(new HttpObjectAggregator(65536));
pipeline.addLast(new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if(msg instanceof FullHttpRequest) {
FullHttpRequest fullHttpRequest = (FullHttpRequest) msg;
String uri = fullHttpRequest.uri();
if (!uri.equals(path)) {
// websocket , 404
ctx.channel().writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND))
.addListener(ChannelFutureListener.CLOSE);
return ;
}
}
super.channelRead(ctx, msg);
}
});
pipeline.addLast(new WebSocketServerCompressionHandler());
pipeline.addLast(new WebSocketServerProtocolHandler(path, null, true, maxFrameSize));
/**
* IOC Handler
*/
pipeline.addLast(applicationContext.getBean(WebsocketMessageHandler.class));
}
});
Channel channel = serverBootstrap.bind().sync().channel();
this.serverChannel = channel;
LOGGER.info("websocket ,ip={},port={}", this.ip, this.port);
channel.closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public void onApplicationEvent(ContextClosedEvent event) {
if (this.serverChannel != null) {
this.serverChannel.close();
}
LOGGER.info("websocket ");
}
}
NettyBootsrapRunner
ApplicationRunner,ApplicationListener<ContextClosedEvent>
,ApplicationContextAware
인 터 페 이 스 를 실현 했다.이렇게 되면
NettyBootsrapRunner
앱 이 시작 되 고 닫 힐 때 Websocket 서비스의 시작 과 닫 기 를 실행 할 수 있 습 니 다.그리고ApplicationContextAware
를 통 해 얻 을 수 있 습 니 다ApplicationContext
IOC 를 통 해 Netty 를 관리 하 는 Handler 입 니 다.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketCloseStatus;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.springboot.netty.service.DiscardService;
/**
*
* @author Administrator
*
*/
@Sharable
@Component
public class WebsocketMessageHandler extends SimpleChannelInboundHandler<WebSocketFrame> {
private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketMessageHandler.class);
@Autowired
DiscardService discardService;
@Override
protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame msg) throws Exception {
if (msg instanceof TextWebSocketFrame) {
TextWebSocketFrame textWebSocketFrame = (TextWebSocketFrame) msg;
//
this.discardService.discard(textWebSocketFrame.text());
//
ctx.channel().writeAndFlush(new TextWebSocketFrame(" :" + System.currentTimeMillis()));
} else {
//
ctx.channel().writeAndFlush(WebSocketCloseStatus.INVALID_MESSAGE_TYPE).addListener(ChannelFutureListener.CLOSE);
}
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
super.channelInactive(ctx);
LOGGER.info(" :{}", ctx.channel().remoteAddress());
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
LOGGER.info(" :{}", ctx.channel().remoteAddress());
}
}
handler 는 이미 IOC 가 관리 하 는 Bean 으로 주입 등 Spring 에 의존 하 는 빠 른 기능 을 자 유 롭 게 사용 할 수 있다.단일 사례 가 존재 하기 때문에 모든 링크 는 같은 hander 를 사용 하기 때문에 인 스 턴 스 변 수 를 저장 하지 마 십시오.이 Handler 는 클 라 이언 트 의 메 시 지 를 처리 한 후에 클 라 이언 트 에 게 다음 과 같은 메 시 지 를 응답 합 니 다.
" :" + System.currentTimeMillis()
Handler 에서 업무 층 을 사용 하 는 것 을 보 여주 기 위해DiscardService
서 비 스 를 주입 한 척 했다.그것 의 논 리 는 매우 간단 하 다.바로 소식 을 버 리 는 것 이다.
public void discard (String message) {
LOGGER.info(" :{}", message);
}
시범 을 보이다시작 클 라 이언 트
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Websocket</title>
</head>
<body>
</body>
<script type="text/javascript">
;(function(){
const websocket = new WebSocket('ws://localhost:1024/channel');
websocket.onmessage = e => {
console.log(' :', e.data);
}
websocket.onclose = e => {
let {code, reason} = e;
console.log(` :code=$[code], reason=${reason}`);
}
websocket.onopen = () => {
console.log(` ...`);
websocket.send('Hello');
}
websocket.onerror = e => {
console.log(' :', e);
}
})();
</script>
</html>
링크 생 성 후 서버 에 메 시 지 를 보 냅 니 다:Hello
서버 닫 기PostMan 을 사용 하여 서버 의 정지 점 을 요청 합 니 다.
로그
클 라 이언 트 로그
서버 로그
2020-06-22 17:08:22.728 INFO 9392 --- [ main] io.undertow : starting server: Undertow - 2.1.3.Final
2020-06-22 17:08:22.740 INFO 9392 --- [ main] org.xnio : XNIO version 3.8.0.Final
2020-06-22 17:08:22.752 INFO 9392 --- [ main] org.xnio.nio : XNIO NIO Implementation Version 3.8.0.Final
2020-06-22 17:08:22.839 INFO 9392 --- [ main] org.jboss.threads : JBoss Threads version 3.1.0.Final
2020-06-22 17:08:22.913 INFO 9392 --- [ main] o.s.b.w.e.undertow.UndertowWebServer : Undertow started on port(s) 80 (http)
2020-06-22 17:08:22.931 INFO 9392 --- [ main] io.springboot.netty.NettyApplication : Started NettyApplication in 4.536 seconds (JVM running for 5.175)
2020-06-22 17:08:23.653 INFO 9392 --- [ main] i.s.n.w.runner.NettyBootsrapRunner : 웹 소켓 서비스 시작,ip=0.0.0.0,port=1024
2020-06-22 17:08:28.484 INFO 9392 --- [ XNIO-1 task-1] io.undertow.servlet : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-06-22 17:08:28.484 INFO 9392 --- [ XNIO-1 task-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-06-22 17:08:28.492 INFO 9392 --- [ XNIO-1 task-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 8 ms
2020-06-22 17:08:28.724 INFO 9392 --- [ntLoopGroup-3-1] i.s.n.w.handler.WebsocketMessageHandler : 링크 생 성:/0:0:0:0:0:1:12093
2020-06-22 17:08:28.790 INFO 9392 --- [ntLoopGroup-3-1] i.s.netty.service.DiscardService : 메시지 버 리 기:Hello
2020-06-22 17:08:33.688 INFO 9392 --- [ Thread-232] i.s.n.w.runner.NettyBootsrapRunner : 웹 소켓 서비스 정지
2020-06-22 17:08:33.691 INFO 9392 --- [ntLoopGroup-3-1] i.s.n.w.handler.WebsocketMessageHandler : 링크 차단:/0:0:0:0:0:0:1:12093
2020-06-22 17:08:33.699 INFO 9392 --- [ Thread-232] io.undertow : stopping server: Undertow - 2.1.3.Final
2020-06-22 17:08:33.704 INFO 9392 --- [ Thread-232] io.undertow.servlet : Destroying Spring FrameworkServlet 'dispatcherServlet'
2020-06-22 17:08:33.708 INFO 9392 --- [ Thread-232] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
넷 티 는 스프링 부 트 앱 이 시 작 된 후 시작 하고,앱 이 멈 춘 뒤 닫 히 면 정상적으로 대외 서 비 스 를 제공 할 수 있 으 며,핸들 러 가 IOC 관리 에 맡 기 면 서 비 스 를 주입 해 업무 처 리 를 완료 할 수 있다.
총결산
SpringBoot 에서 Netty 프레임 워 크 를 통합 하여 사용 하 는 것 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 SpringBoot 통합 Netty 프레임 워 크 내용 은 예전 의 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 도 많은 응원 부 탁 드 리 겠 습 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
【Java・SpringBoot・Thymeleaf】 에러 메세지를 구현(SpringBoot 어플리케이션 실천편 3)로그인하여 사용자 목록을 표시하는 응용 프로그램을 만들고, Spring에서의 개발에 대해 공부하겠습니다 🌟 마지막 데이터 바인딩에 계속 바인딩 실패 시 오류 메시지를 구현합니다. 마지막 기사🌟 src/main/res...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.