点击查看代码
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. ABAP CDS - Language Elements

    The following sections summarize the language elements of the DDL and DCL of the ABAP CDS, arranged ...

  2. Banner自定义图案

    Banner大全https://www.bootschool.net/ascii

  3. gnet: 一个轻量级且高性能的 Go 网络框架 使用笔记

    一个偶然的机会接触到了golang,被它的高并发传说所吸引,就开始学这门语言,越学感觉越有意思^_^ 注册了博客园这么多年,第一次写东西,年纪大了,脑子不好使了,就得写下来,记下来,为了自己以后查阅, ...

  4. SDK导入问题 __imp_与__imp__

    目前刚刚实习一周,接触的第一个项目是CMake编译的QT项目,需要引入公司的SDK,编译能过去但是程序就是找不到SDK的接口, 排查了半天发现问题在于:公司的SDK是32位的,自己项目的build k ...

  5. ICMP 介绍

    简介 ICMP(Internet 控制报文协议,Internet Control Message Protocol , RFC 792).主要用于在IP主机与路由器之间传递控制消息,用于报告主机是否可 ...

  6. Java 技术栈中间件优雅停机方案设计与实现全景图

    欢迎关注公众号:bin的技术小屋,阅读公众号原文 本系列 Netty 源码解析文章基于 4.1.56.Final 版本 本文概要 在上篇文章 我为 Netty 贡献源码 | 且看 Netty 如何应对 ...

  7. 我有 7种 实现web实时消息推送的方案,7种!

    技术交流,公众号:程序员小富 大家好,我是小富- 我有一个朋友- 做了一个小破站,现在要实现一个站内信web消息推送的功能,对,就是下图这个小红点,一个很常用的功能. 不过他还没想好用什么方式做,这里 ...

  8. ACWing93.递归实现组合型枚举

    题面 \93. 递归实现组合型枚举 从 1∼n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案. 输入格式 两个整数 n,m ,在同一行用空格隔开. 输出格式 按照从小到大的顺序输出所有方案 ...

  9. python3学习笔记之字符串

    字符串 1.一个个字符组成的有序的序列,是字符的集合: 2.使用单引号.双引号.三引号引住的字符序列 3.字符串是不可变对象 4.python3起,字符串就是Unicode类型: 字符串特殊举例: 不 ...

  10. 分享一些小tips

    谷歌浏览器破解 google拓展商店中hackbar地址 https://chrome.google.com/webstore/detail/djmoeoifnlhjolebkehmpaocfnipk ...