文章目录
注:更多netty相关文章请访问博主专栏: netty专栏
概述
目前主流的Java web服务器还是采用springboot+Tomcat来实现的,底层还是基于servlet开发的。servlet不是异步的,所以性能并不是很理性,无法满足当下的快速服务器的要求。
目前spring5已经实现了基于reactor的webflux异步编程(响应式编程),springboot2.X也已经支持webflux,性能会提升很多。其底层实现就是netty。
要想更深入了解响应式编程,请移步至笔者博客:java9 响应式编程支持,里面包含什么是响应式编程,reactor基本讲解以及在springboot中使用响应式编程。
因此netty不仅仅可以作为组件的通信,还可以作为HTTP服务器使用 ,接下来我们就看看如何使用netty实现HTTP服务器。
本文只是简单使用netty搭建HTTP服务器,功能不够完善,不可以用于生产服务。
HTTP服务器代码实现
编写一个HTTPserver服务类。
public class MyHttpServer {
int port ;
public MyHttpServer(int port){
this.port = port;
}
public void start() throws Exception{
ServerBootstrap bootstrap = new ServerBootstrap();
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup work = new NioEventLoopGroup();
try {
bootstrap.group(boss, work)
.handler(new LoggingHandler(LogLevel.DEBUG))
.channel(NioServerSocketChannel.class)
.childHandler(new HttpServerInitializer());
ChannelFuture f = bootstrap.bind(new InetSocketAddress(port)).sync();
System.out.println("http server started . port : " + port);
f.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
boss.shutdownGracefully();
work.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception{
MyHttpServer server = new MyHttpServer(8080);// 8080为启动端口
server.start();
}
}
class HttpServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new HttpServerCodec());// http 编解码
pipeline.addLast("httpAggregator",new HttpObjectAggregator(512*1024)); // http 消息聚合器 512*1024为接收的最大contentlength
pipeline.addLast(new HttpRequestHandler());// 请求处理器
}
}
上面代码主要看HttpServerInitializer
这个类。
咋ChannelPipeline
中依次添加了HttpServerCodec,HttpObjectAggregator 和 HttpRequestHandler
。
HttpServerCodec
是HTTP消息的编解码器。HttpServerCodec是HttpRequestDecoder
和HttpResponseEncoder
的组合类,用于简化HTTP编程。
- HttpRequestDecoder 即把 ByteBuf 解码到 HttpRequest 和 HttpContent。
- HttpResponseEncoder 即把 HttpResponse 或 HttpContent 编码到 ByteBuf。
-
HttpObjectAggregator 作用是HTTP消息聚合,将多个消息转换为单一的FullHttpRequest和FullHttpResponse。因为HttpServerCodec解码器在每个HTTP消息中会生产多个对象:HttpRequest、HttpResponse、HttpContent、LastHttpContent。
HttpObjectAggregator 是负责多个chunk的http 请求和响应的。他让我们的handler 处理看到的是一个完整的fullHttpResponse,不需要考虑是Content 是否是 LastHttpContent,netty的LastHttpContent代表body结束部分。一个chunk 代表一个HttpContent,最后一个chunk 由 LastHttpContent 表示。 -
HttpRequestHandler 是我们的业务逻辑处理类。
请求处理类HttpRequestHandler :
class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) {
// 获取请求的uri
String uri = req.uri();
Map<String,String> resMap = new HashMap<>();
resMap.put("method",req.method().name());
resMap.put("uri",uri);
String msg = "<html><head><title>test</title></head><body>你请求uri为:" + uri+"</body></html>";
// 创建http响应
FullHttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.OK,
Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8));
// 设置头信息
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
//response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
// 将html write到客户端
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
}
很简单,就是读取请求URL,回复客户端一个字符串。
验证
启动服务
浏览器访问 localhost:8080/任意字符串。比如:http://localhost:8080/index1/q
在浏览器页面中返回:
你请求uri为:/index1/q
注:更多netty相关文章请访问博主专栏: netty专栏