基于netty实现的迷你版TOMCat
程序员文章站
2022-05-13 21:38:35
...
1.首先有一个tomcat类用来管理网络请求和servlet映射
package com.tomcatmini;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
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.HttpRequest;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* Created by chenli on 2019/11/11.
*/
public class MiNiTomcat {
private int port=8080;//端口
private Map<String,MiNiServlet> map=new HashMap<>();
private Properties webxml=new Properties();
private void init(){
//加载xml文件
try{
String WEB_INF=this.getClass().getResource("/").getPath();
FileInputStream fis=new FileInputStream(WEB_INF+"webxml.properties");
//基于properties实现
webxml.load(fis);
for (Object k:webxml.keySet()){
String key=k.toString();
if (key.endsWith(".url")){
String servletName = key.replaceAll("\\.url$", "");
String url = webxml.getProperty(key);
String className = webxml.getProperty(servletName + ".className");
MiNiServlet obj = (MiNiServlet)Class.forName(className).newInstance();
map.put(url, obj);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
private void start() throws InterruptedException {
EventLoopGroup bossGroup=null;
EventLoopGroup workGroup=null;
try {
init();
//Netty 封装了NIO reator
//主线程
bossGroup = new NioEventLoopGroup();
//工作线程
workGroup = new NioEventLoopGroup();
//
ServerBootstrap server = new ServerBootstrap();
server.group(bossGroup, workGroup)
.channel(NioServerSocketChannel.class)
//子线程调用
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel client) throws Exception {
//客户端初始化处理
// 无锁化串行编程
//Netty对HTTP协议的封装,顺序有要求
//HttpResponseEncoder 编码器
client.pipeline().addLast(new HttpResponseEncoder());
//HttpRequestDecoder解码器
client.pipeline().addLast(new HttpRequestDecoder());
//业务逻辑处理
client.pipeline().addLast(new MiNiTomcatHander());
}
})
//针对于主线程分配最大线程数量 --128
.option(ChannelOption.SO_BACKLOG, 128)
//针对于子线程配置
.childOption(ChannelOption.SO_KEEPALIVE, true);
//启动服务
ChannelFuture future = server.bind(port).sync();
System.out.println("MiNi tomcat start " + port);
//关闭服务
future.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws InterruptedException {
new MiNiTomcat().start();
}
private class MiNiTomcatHander extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpRequest){
HttpRequest req=(HttpRequest) msg;
//转交给自己实现的请求
MiNiRequest request=new MiNiRequest(ctx,req);
//自己实现
MiNiResponse response=new MiNiResponse(ctx,req);
String url=request.getUrl();
if (map.containsKey(url)){
map.get(url).service(request,response);
}else {
response.write("404 not fund url");
}
}
}
}
}
2.封装请求类
package com.tomcatmini;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.HttpRequest;
/**
* Created by chenli on 2019/11/12.
*/
public class MiNiRequest {
ChannelHandlerContext ctx;
HttpRequest req;
public MiNiRequest(ChannelHandlerContext ctx, HttpRequest req) {
this.ctx=ctx;
this.req=req;
}
public String getUrl() {
return req.getUri();
}
public String getMethod() {
return req.getMethod().name();
}
}
3.封装响应类
package com.tomcatmini;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;
import java.io.UnsupportedEncodingException;
/**
* Created by chenli on 2019/11/12.
*/
public class MiNiResponse {
//SocketChannel的封装
private ChannelHandlerContext ctx;
private HttpRequest req;
public MiNiResponse(ChannelHandlerContext ctx, HttpRequest req) {
this.ctx=ctx;
this.req=req;
}
public void write(String out) {
if (out == null || out.length()==0){
return;
}
try {
FullHttpResponse fullHttpResponse=new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.OK,
// 将输出值写出 编码为UTF-8
Unpooled.wrappedBuffer(out.getBytes("UTF-8")));
fullHttpResponse.headers().set("Content-Type", "text/html;");
ctx.write(fullHttpResponse);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}finally {
ctx.flush();
ctx.close();
}
}
}
4.抽象servlet
package com.tomcatmini;
/**
* Created by chenli on 2019/11/11.
*/
public abstract class MiNiServlet {
public void service(MiNiRequest request, MiNiResponse response) {
if ("GET".equalsIgnoreCase(request.getMethod())){
doGet(request,response);
}else{
doPost(request,response);
}
}
protected abstract void doPost(MiNiRequest request, MiNiResponse response);
protected abstract void doGet(MiNiRequest request, MiNiResponse response);
}
5.第一个servlet
package com.tomcatmini;
/**
* Created by chenli on 2019/11/13.
*/
public class FirstServlet extends MiNiServlet {
@Override
protected void doPost(MiNiRequest request, MiNiResponse response) {
this.doPost(request,response);
}
@Override
protected void doGet(MiNiRequest request, MiNiResponse response) {
response.write("FirstServlet alreadly start !");
}
}
6.第二个servlet
package com.tomcatmini;
/**
* Created by chenli on 2019/11/13.
*/
public class SecondServlet extends MiNiServlet {
@Override
protected void doPost(MiNiRequest request, MiNiResponse response) {
System.out.println("第二个servlet");
}
@Override
protected void doGet(MiNiRequest request, MiNiResponse response) {
this.doPost(request,response);
}
}
7.配置文件
servlet.one.url=/firstServlet.do
servlet.one.className=com.tomcatmini.FirstServlet
servlet.two.url=/secondServlet.do
servlet.two.className=com.tomcatmini.SecondServlet