手写tomcat——netty版
点击查看代码
package com.grady.diytomcat;
import com.grady.diytomcat.handler.DiyNettyTomcatHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
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.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.List;
public class DiyTomcat {
private int port = 8080;
public static final HashMap<String, DiyNettyServlet> SERVLET_MAPPING = new HashMap<>();
public static final HashMap<String,String> URL_MAPPING = new HashMap<>();
static {
loadServlet();
}
private static void loadServlet() {
try {
//获取web.xml目录地址
String path = DiyTomcat.class.getResource("/").getPath();
SAXReader reader = new SAXReader();
//读取web.xml文件
Document document = reader.read(new File(path + "web.xml"));
//获取根标签(servlet和servlet-mapping),放在一个List中
Element rootElement = document.getRootElement();
List<Element> elements = rootElement.elements();
//循环将映射写进map映射里
for(Element element : elements){
if ("servlet".equalsIgnoreCase(element.getName())){
Element servletName = element.element("servlet-name");
Element servletClass = element.element("servlet-class");
//需要注意的是servletMapping映射的第二个参数,要通过反射的方式进行实例化
SERVLET_MAPPING.put(servletName.getText(),
(DiyNettyServlet) Class.forName(servletClass.getText().trim()).newInstance());
}else if ("servlet-mapping".equalsIgnoreCase(element.getName())){
Element servletName = element.element("servlet-name");
Element urlPattern = element.element("url-pattern");
URL_MAPPING.put(urlPattern.getText(), servletName.getText());
}
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
public void start() throws IOException {
// Boss线程
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
// worker线程
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
// 1.创建对象
ServerBootstrap server = new ServerBootstrap();
//2. 配置参数
server.group(bossGroup,workerGroup)
// 主线程处理类
.channel(NioServerSocketChannel.class)
// 子线程处理类 Handler
.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new HttpResponseEncoder());
socketChannel.pipeline().addLast(new HttpRequestDecoder());
socketChannel.pipeline().addLast(new DiyNettyTomcatHandler());
}
})
//针对主线程的配置,最大线程数128
.option(ChannelOption.SO_BACKLOG,128)
// 针对子线程的配置,保持长连接
.childOption(ChannelOption.SO_KEEPALIVE,true);
try {
// 3 启动服务器
ChannelFuture f = server.bind(port).sync();
System.out.println("DiyTomcat启动成功,监听的端口是:" + port);
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
1. netty版会稍有些不同,因为netty内部的核心是channel(对socket进行了一层封装处理),所以我们不能直接拿到socket对应的InputStream和OutputStream
2. 我们的核心处理逻辑在DiyNettyTomcatHandler中
package com.grady.diytomcat.handler;
import com.grady.diytomcat.DiyNettyRequest;
import com.grady.diytomcat.DiyNettyResponse;
import com.grady.diytomcat.DiyNettyServlet;
import com.grady.diytomcat.DiyTomcat;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpRequest;
public class DiyNettyTomcatHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpRequest){
HttpRequest req = (HttpRequest) msg;
DiyNettyRequest request = new DiyNettyRequest(ctx, req);
DiyNettyResponse response = new DiyNettyResponse(ctx, req);
// 实际业务处理
String url = request.getUrl();
if(DiyTomcat.URL_MAPPING.containsKey(url)) {
String servletName = DiyTomcat.URL_MAPPING.get(url);
DiyNettyServlet servlet= DiyTomcat.SERVLET_MAPPING.get(servletName);
servlet.service(request, response);
} else {
response.write("404 - Not Found");
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
}
}
在这里,将ChannelHandlerContext 封装到DiyNettyRequest
和DiyNettyResponse中,这样我们的request和response就拥有了读数据和写数据的能力
<br/>
源码地址:
https://github.com/ZhongJinHacker/diy-tomcat/tree/netty-tomcat
手写tomcat——netty版的更多相关文章
- 手写Tomcat
学习JavaWeb之后,只知道如何部署项目到Tomcat中,而并不了解其内部如何运行,底层原理为何,因此写下此篇博客初步探究一下.学习之前需要知识铺垫已列出:Tomcat目录结构.HTTP协议.IO. ...
- 手写Tomcat服务器
预备知识 编写服务器用到的知识点 1) Socket 编程2) HTML3) HTTP 协议4) 反射5) XML 解析6) 服务器编写 Socket编程 https://www.cnblogs.co ...
- 识别手写数字增强版100% - pytorch从入门到入道(一)
手写数字识别,神经网络领域的“hello world”例子,通过pytorch一步步构建,通过训练与调整,达到“100%”准确率 1.快速开始 1.1 定义神经网络类,继承torch.nn.Modul ...
- 来,我们手写一个简易版的mock.js吧(模拟fetch && Ajax请求)
预期的mock的使用方式 首先我们从使用的角度出发,思考编码过程 M1. 通过配置文件配置url和response M2. 自动检测环境为开发环境时启动Mock.js M3. mock代码能直接覆盖g ...
- 手写一个简版 asp.net core
手写一个简版 asp.net core Intro 之前看到过蒋金楠老师的一篇 200 行代码带你了解 asp.net core 框架,最近参考蒋老师和 Edison 的文章和代码,结合自己对 asp ...
- 手写一个简易版Tomcat
前言 Tomcat Write MyTomcat Tomcat是非常流行的Web Server,它还是一个满足Servlet规范的容器.那么想一想,Tomcat和我们的Web应用是什么关系? 从感性上 ...
- 手写RPC-简陋版
前言 最近不小心被隔离,放假思考一番,决定开始在手写序列.这个序列在之前看Nacous和网关源码的时候就有想法,只是一直没落实下来,趁着隔离行动起来. 必备知识介绍 序列化与反序列化 序列化是把对象的 ...
- 手写tomcat——编写一个提供servlet能力的 http服务器
点击查看代码 package com.grady.diytomcat; import com.grady.diytomcat.handler.RequestHandler; import org.do ...
- 手写实现简单版IOC
概述 IOC (Inversion of Control) 控制反转,大家应该都比较熟悉了.应该也都有用过,这里就不具体介绍了.自己平时也有用到过IOC,但是对它的具体实现原理只有一个模糊的概念,所以 ...
随机推荐
- LVGL库入门教程 - 颜色和图像
颜色 构造颜色 在 LVGL 中,颜色以结构 lv_color_t 表示.在最开始移植整个工程时,曾经在 lv_conf.h 中修改过颜色深度: /*Color depth: 1 (1 byte pe ...
- ms08-067漏洞复现
一.环境说明 kali linux 靶机是 XP (xp启动445) 二.nmap扫描主机存在的漏洞 root@kali:~# nmap --script smb-vuln* 192.168.244. ...
- UiPath程序设计文档
1. [RPA之家]添加数据列UiPath.Core.Activities.AddDataColumn 链接: https://pan.baidu.com/s/1RRMw4voqJru-fJSoC3W ...
- NC200211 装备合成
NC200211 装备合成 题目 题目描述 牛牛有 \({x}\) 件材料 \({a}\) 和 \({y}\) 件材料 \({b}\) ,用 \({2}\) 件材料 \({a}\) 和 \({3}\) ...
- PTA(BasicLevel)-1094 谷歌的招聘
一.问题定义 2004 年 7 月,谷歌在硅谷的 101 号公路边竖立了一块巨大的广告牌(如下图)用于招聘.内容超级简单,就是一个以 .com 结尾的网址, 而前面的网址是一个 10 位素数,这个素数 ...
- Collection子接口:List接口
1. 存储的数据特点:存储序的.可重复的数据. 2. 常用方法:(记住)增:add(Object obj)删:remove(int index) / remove(Object obj)改:set(i ...
- Windows JDK 的下载与安装
Java Development Kit 简称 JDK,任何需要开发 Java 程序的环境都需要进行安装 JDK. JDK 下载地址:https://www.oracle.com/java/techn ...
- 用KVM安装MacOS/OSX
基本步骤按照大牛的步骤https://github.com/kholia/OSX-KVM 黑果镜像建议用黑果小兵的:macOS Big Sur(我试过,大牛的更卡),里面的双EFI就很够用. 将镜像名 ...
- Note -「因数的欧拉函数求和」
归档. 试证明:\(\sum \limits _{d | x} \varphi (d) = x\) Lemma 1. 试证明:\(\sum \limits _{d | p^k} \varphi (d) ...
- 掌握CSS中的z-index
前言 z-index是一个用于控制文档中图层顺序的属性.具有较高z-index值的元素将会出现在具有较低值的元素之上.就像页面上的x轴和y轴决定一个元素在水平和垂直方向上的位置一样,z-index控制 ...