点击查看代码
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对应的InputStreamOutputStream
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中,这样我们的requestresponse就拥有了读数据和写数据的能力

<br/>

源码地址:

https://github.com/ZhongJinHacker/diy-tomcat/tree/netty-tomcat

手写tomcat——netty版的更多相关文章

  1. 手写Tomcat

    学习JavaWeb之后,只知道如何部署项目到Tomcat中,而并不了解其内部如何运行,底层原理为何,因此写下此篇博客初步探究一下.学习之前需要知识铺垫已列出:Tomcat目录结构.HTTP协议.IO. ...

  2. 手写Tomcat服务器

    预备知识 编写服务器用到的知识点 1) Socket 编程2) HTML3) HTTP 协议4) 反射5) XML 解析6) 服务器编写 Socket编程 https://www.cnblogs.co ...

  3. 识别手写数字增强版100% - pytorch从入门到入道(一)

    手写数字识别,神经网络领域的“hello world”例子,通过pytorch一步步构建,通过训练与调整,达到“100%”准确率 1.快速开始 1.1 定义神经网络类,继承torch.nn.Modul ...

  4. 来,我们手写一个简易版的mock.js吧(模拟fetch && Ajax请求)

    预期的mock的使用方式 首先我们从使用的角度出发,思考编码过程 M1. 通过配置文件配置url和response M2. 自动检测环境为开发环境时启动Mock.js M3. mock代码能直接覆盖g ...

  5. 手写一个简版 asp.net core

    手写一个简版 asp.net core Intro 之前看到过蒋金楠老师的一篇 200 行代码带你了解 asp.net core 框架,最近参考蒋老师和 Edison 的文章和代码,结合自己对 asp ...

  6. 手写一个简易版Tomcat

    前言 Tomcat Write MyTomcat Tomcat是非常流行的Web Server,它还是一个满足Servlet规范的容器.那么想一想,Tomcat和我们的Web应用是什么关系? 从感性上 ...

  7. 手写RPC-简陋版

    前言 最近不小心被隔离,放假思考一番,决定开始在手写序列.这个序列在之前看Nacous和网关源码的时候就有想法,只是一直没落实下来,趁着隔离行动起来. 必备知识介绍 序列化与反序列化 序列化是把对象的 ...

  8. 手写tomcat——编写一个提供servlet能力的 http服务器

    点击查看代码 package com.grady.diytomcat; import com.grady.diytomcat.handler.RequestHandler; import org.do ...

  9. 手写实现简单版IOC

    概述 IOC (Inversion of Control) 控制反转,大家应该都比较熟悉了.应该也都有用过,这里就不具体介绍了.自己平时也有用到过IOC,但是对它的具体实现原理只有一个模糊的概念,所以 ...

随机推荐

  1. LVGL库入门教程 - 颜色和图像

    颜色 构造颜色 在 LVGL 中,颜色以结构 lv_color_t 表示.在最开始移植整个工程时,曾经在 lv_conf.h 中修改过颜色深度: /*Color depth: 1 (1 byte pe ...

  2. ms08-067漏洞复现

    一.环境说明 kali linux 靶机是 XP (xp启动445) 二.nmap扫描主机存在的漏洞 root@kali:~# nmap --script smb-vuln* 192.168.244. ...

  3. UiPath程序设计文档

    1. [RPA之家]添加数据列UiPath.Core.Activities.AddDataColumn 链接: https://pan.baidu.com/s/1RRMw4voqJru-fJSoC3W ...

  4. NC200211 装备合成

    NC200211 装备合成 题目 题目描述 牛牛有 \({x}\) 件材料 \({a}\) 和 \({y}\) 件材料 \({b}\) ,用 \({2}\) 件材料 \({a}\) 和 \({3}\) ...

  5. PTA(BasicLevel)-1094 谷歌的招聘

    一.问题定义 2004 年 7 月,谷歌在硅谷的 101 号公路边竖立了一块巨大的广告牌(如下图)用于招聘.内容超级简单,就是一个以 .com 结尾的网址, 而前面的网址是一个 10 位素数,这个素数 ...

  6. Collection子接口:List接口

    1. 存储的数据特点:存储序的.可重复的数据. 2. 常用方法:(记住)增:add(Object obj)删:remove(int index) / remove(Object obj)改:set(i ...

  7. Windows JDK 的下载与安装

    Java Development Kit 简称 JDK,任何需要开发 Java 程序的环境都需要进行安装 JDK. JDK 下载地址:https://www.oracle.com/java/techn ...

  8. 用KVM安装MacOS/OSX

    基本步骤按照大牛的步骤https://github.com/kholia/OSX-KVM 黑果镜像建议用黑果小兵的:macOS Big Sur(我试过,大牛的更卡),里面的双EFI就很够用. 将镜像名 ...

  9. Note -「因数的欧拉函数求和」

    归档. 试证明:\(\sum \limits _{d | x} \varphi (d) = x\) Lemma 1. 试证明:\(\sum \limits _{d | p^k} \varphi (d) ...

  10. 掌握CSS中的z-index

    前言 z-index是一个用于控制文档中图层顺序的属性.具有较高z-index值的元素将会出现在具有较低值的元素之上.就像页面上的x轴和y轴决定一个元素在水平和垂直方向上的位置一样,z-index控制 ...