现在我们把原来的BIO改成基于netty的NIO
因为netty中自带了HTTPRequest,所以我们就不在需要之前的HTTPRequest
Response也需要做一定的修改,因为netty封装了OutputString,我们需要使用netty通过socket连接建立的管道
HTTPResponse
public class HTTPResponse {
private ChannelHandlerContext ctx;
public HTTPResponse(ChannelHandlerContext ctx) {
this.ctx = ctx;
}
// 使用netty的管道来返回数据
public void write(String message) throws IOException {
DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(message.getBytes()));
response.headers().set("Content-Type", "text/html; charset=UTF-8");
ctx.writeAndFlush(response);
ctx.channel().close();
}
}
ServletMapping,ServletMappingConfig没有任何改动
Servlet将原来的HTTPRequest类改成netty封装的HttpRequest类
Servlet
public abstract class Servlet {
public abstract void doGet(HttpRequest httpRequest, HTTPResponse httpResponse) throws IOException;
public abstract void doPost(HttpRequest httpRequest, HTTPResponse httpResponse) throws IOException;
public void service(HttpRequest httpRequest, HTTPResponse httpResponse) throws IOException {
if ("GET".equals(httpRequest.getMethod().name())) {
doGet(httpRequest, httpResponse);
} else if ("POST".equals(httpRequest.getMethod().name())) {
doPost(httpRequest, httpResponse);
}
}
}
HelloServlet 也是一样
public class HelloServlet extends Servlet {
@Override
public void doGet(HttpRequest httpRequest, HTTPResponse httpResponse) throws IOException {
httpResponse.write("hello Get");
}
@Override
public void doPost(HttpRequest httpRequest, HTTPResponse httpResponse) throws IOException {
httpResponse.write("hello Post");
}
}
主类只需要启动netty就可以了,之前的分发,我们新建一个的类,因为对于数据的读取,我们放在Hander事件处理器中了,无法从WebServer中分发
public class WebServer {
private static Logger logger = LoggerFactory.getLogger(WebServer.class);
private int port;
private ServerSocket serverSocket;
public WebServer(int port) throws IOException {
this.port = port;
}
private void start() throws IOException {
logger.info("服务器启动");
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new HttpRequestDecoder());
ch.pipeline().addLast(new HttpResponseEncoder());
ch.pipeline().addLast(new ServerHandler());
}
});
try {
ChannelFuture f = bootstrap.bind(port).sync();
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws IOException {
new WebServer(8888).start();
}
}
事件处理器,定义了读取数据之后的业务逻辑
public class ServerHandler extends SimpleChannelInboundHandler<HttpRequest> {
private static Logger logger = LoggerFactory.getLogger(ServerHandler.class);
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
logger.info("有客户端连接:" + ctx.channel().remoteAddress().toString());
super.channelActive(ctx);
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpRequest httpRequest) throws Exception {
HTTPResponse httpResponse = new HTTPResponse(ctx);
Dispatcher.dispatcher(httpRequest, httpResponse);
}
}
Dispatcher 能够将request分发到正确的Servlet中
public class Dispatcher {
private static HashMap<String, ServletMapping> hashMap;
static {
hashMap = new HashMap<>();
for (ServletMapping i : ServletMappingConfig.list) {
hashMap.put(i.getUri(), i);
}
}
public static void dispatcher(HttpRequest httpRequest, HTTPResponse httpResponse) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
String clazz = hashMap.get(httpRequest.getUri()).getClazz();
Class<Servlet> servletClass = (Class<Servlet>) Class.forName(clazz);
Servlet servlet = servletClass.newInstance();
servlet.service(httpRequest, httpResponse);
}
}
这样我们就完成了一个基于NIO的web服务器,并且简化了之前的代码
网友评论