Tomcat 是非常流行的 Web Server,它还是一个满足 Servlet 规范的容器。那么想一想,Tomcat 和我们的 Web 应用是什么关系?

从感性上来说,我们一般需要把 Web 应用打成 WAR 包部署到 Tomcat 中,在我们的 Web 应用中,我们要指明 URL 被哪个类的哪个方法所处理「不论是原始的 Servlet 开发,还是现在流行的 Spring MVC 都必须指明」。

由于我们的 Web 应用是运行在 Tomcat 中,那么显然,请求必定是先到达Tomcat 的。Tomcat 对于请求实际上会进行如下的处理。了解 Tomcat 建议大家看下这篇文章《Tomcat 的 Server 文件配置详解!

第一,提供 Socket 服务

Tomcat 的启动,必然是 Socket 服务,只不过它支持 HTTP 协议而已!

这里其实可以扩展思考下,Tomcat 既然是基于 Socket,那么是基于BIO or NIO or AIO 呢?

第二,进行请求的分发

要知道一个 Tomcat 可以为多个 Web 应用提供服务,那么很显然,Tomcat 可以把 URL 下发到不同的Web应用。

第三,需要把请求和响应封装成 request / response

我们在 Web 应用这一层,可从来没有封装过 request/response 的,我们都是直接使用的,这就是因为 Tomcat 已经为你做好了!

话不多说,先来看一眼工程截图。

一、封装请求对象

    import java.io.IOException;
import java.io.InputStream; public class MyRequest {
private String url;
private String method; public MyRequest(InputStream inputStream) throws IOException {
String httpRequest = "";
byte[] httpRequestBytes = new byte[1024];
int length = 0;
if ((length = inputStream.read(httpRequestBytes)) > 0) {
httpRequest = new String(httpRequestBytes, 0, length);
} String httpHead = httpRequest.trim().split("\n")[0];
url = httpRequest.trim().split("\\s")[1];
method = httpRequest.trim().split("\\s")[0]; System.out.println(this + "^^^^^url:" + url + "^^^^^^method:" + method);
} public String getUrl() {
return url;
} public void setUrl(String url) {
this.url = url;
} public String getMethod() {
return method;
} public void setMethod(String method) {
this.method = method;
}
}

这里,你可以清楚的看到,我们通过输入流,对 HTTP 协议进行解析,拿到了 HTTP 请求头的方法以及 URL。

二、封装响应对象

    import java.io.IOException;
import java.io.OutputStream; public class MyResponse {
private OutputStream outputStream; public MyResponse(OutputStream outputStream) {
this.outputStream = outputStream;
} public void write(String content) throws IOException {
StringBuffer httpResponse = new StringBuffer();
httpResponse.append("HTTP/1.1 200 OK\n")
.append("Content-Type: text/html\n")
.append("\r\n")
.append("<html><body>")
.append(content)
.append("</body></html>"); outputStream.write(httpResponse.toString().getBytes());
outputStream.close();
} }

基于HTTP协议的格式进行输出写入。

三、Servlet 请求处理基类(模板模式)

    public abstract class MyServlet {
protected abstract void doGet(MyRequest myRequest, MyResponse myResponse); protected abstract void doPost(MyRequest myRequest, MyResponse myResponse); protected void service(MyRequest myRequest, MyResponse myResponse) {
if (myRequest.getMethod().equalsIgnoreCase("POST")) {
doPost(myRequest, myResponse);
} else if (myRequest.getMethod().equalsIgnoreCase("GET")) {
doGet(myRequest, myResponse);
}
}
}

前文说Tomcat是满足Servlet规范的容器,那么自然Tomcat需要提供API。这里你看到了Servlet常见的

doGet/doPost/service方法。

四、Servlet 实现类

    import java.io.IOException;

    public class HelloMyTomCatServlet extends MyServlet {
@Override
protected void doGet(MyRequest myRequest, MyResponse myResponse) {
try {
myResponse.write("get MyTomcat");
} catch (IOException e) {
e.printStackTrace();
}
} @Override
protected void doPost(MyRequest myRequest, MyResponse myResponse) {
try {
myResponse.write("post MyTomcat");
} catch (IOException e) {
e.printStackTrace();
}
}
}

    import java.io.IOException;

    public class FindCarServlet extends MyServlet {
@Override
protected void doGet(MyRequest myRequest, MyResponse myResponse) {
try {
myResponse.write("get BMW");
} catch (IOException e) {
e.printStackTrace();
}
} @Override
protected void doPost(MyRequest myRequest, MyResponse myResponse) {
try {
myResponse.write("post BYD");
} catch (IOException e) {
e.printStackTrace();
}
}
}

提供这2个具体的Servlet实现,只是为了后续的测试!

五、Servlet 配置

    public class ServletMapping {
private String servletName;
private String usl;
private String clazz; public ServletMapping(String servletName, String usl, String clazz) {
this.servletName = servletName;
this.usl = usl;
this.clazz = clazz;
} public String getServletName() {
return servletName;
} public void setServletName(String servletName) {
this.servletName = servletName;
} public String getUsl() {
return usl;
} public void setUsl(String usl) {
this.usl = usl;
} public String getClazz() {
return clazz;
} public void setClazz(String clazz) {
this.clazz = clazz;
}
}

    import java.util.ArrayList;
import java.util.List; public class ServletMappingConfig { public static List<ServletMapping> servletMappingList = new ArrayList<>();
static {
servletMappingList.add(new ServletMapping("findCar","/car","FindCarServlet"));
servletMappingList.add(new ServletMapping("helloMyTomcat","/hello","HelloMyTomCatServlet"));
}
}

我们在servlet开发中,会在 web.xml 中通过 和 来进行

指定哪个 URL 交给哪个 servlet 进行处理。

六、启动类

    import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map; public class MyTomcat {
private int port = 8080; private Map<String, String> urlServletMap = new HashMap<>(); public MyTomcat(int port) {
this.port = port;
} public void start() {
initServletMapping(); try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("MyTomcat is Start...################");
while (true) {
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
MyRequest myRequest = new MyRequest(inputStream);
MyResponse myResponse = new MyResponse(outputStream);
dispathch(myRequest, myResponse);
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
} private void initServletMapping(){
for (ServletMapping servletMapping : ServletMappingConfig.servletMappingList) {
urlServletMap.put(servletMapping.getUsl(),servletMapping.getClazz());
}
} private void dispathch(MyRequest myRequest, MyResponse myResponse){
String clazz = urlServletMap.get(myRequest.getUrl());
if (myRequest.getUrl().equalsIgnoreCase("/favicon.ico")) {
return;
}
try {
Class<MyServlet> myServletClass = (Class<MyServlet>)Class.forName(clazz);
MyServlet myServlet = myServletClass.newInstance();
myServlet.service(myRequest,myResponse); } catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
} public static void main(String[] args) {
new MyTomcat(8888).start();
}
}

这里,你能够看到 Tomcat 的处理流程,即把 URL 对应处理的 Servlet 关系形成,解析 HTTP 协议,封装请求/响应对象,利用反射实例化具体的 Servlet 进行处理即可。

七、测试





参考java技术栈

MyTomcat(手写服务器)的更多相关文章

  1. java24 手写服务器最终版本

    手写服务器最终版本; <?xml version="1.0" encoding="UTF-8"?> <web-app> <serv ...

  2. 通过手写服务器的方式,立体学习Http

    前言 Http我们都已经耳熟能详了,而关于Http学习的文章网上有很多,各个知识点的讲解也可说是深入浅出.然而,学习过后,我们对Http还是一知半解.问题出在了哪? Http是一个客户机与服务器之间的 ...

  3. 不使用tomcat,仅适用javaSE手写服务器--模拟登陆

    1.搭建框架 我们只是简单模拟,框架简单分三个模块 a,服务器端server包 b,servlet,根据不同的请求url,利用反射生产对应的servlet c,IO工具包,用来关闭IO流 d,编写we ...

  4. Java修炼——手写服务器项目

    项目工程总览: 1.Dispatcher类(一个请求与响应就是一个Dispatcher) package com.bjsxt.server; import java.io.IOException; i ...

  5. 手写简易WEB服务器

    今天我们来写一个类似于Tomcat的简易服务器.可供大家深入理解一下tomcat的工作原理,本文仅供新手参考,请各位大神指正!首先我们要准备的知识是: Socket编程 HTML HTTP协议 服务器 ...

  6. 手写Tomcat服务器

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

  7. 手写Javaweb服务器

    简单web服务器 回忆socket 创建客服端(在httpClient_1包下) public class Client {    public static void main(String[] a ...

  8. 【教程】手写简易web服务器

    package com.littlepage.testjdbc; import java.io.BufferedReader; import java.io.FileReader; import ja ...

  9. JavaSE 手写 Web 服务器(二)

    原文地址:JavaSE 手写 Web 服务器(二) 博客地址:http://www.extlight.com 一.背景 在上一篇文章 <JavaSE 手写 Web 服务器(一)> 中介绍了 ...

随机推荐

  1. JS模态框 简单案例

    演示: <!doctype html> <html lang="en"> <head> <meta charset="UTF-8 ...

  2. [JavaScript-Function] Function Invocation/Call(函数调用) 以及call() and apply() 方法

    介绍:JS函数中的代码会被函数被invoke(调用)时执行. 函数被定义时代码不执行, 函数调用时函数内的代码会被执行. 常用的term是 call a function 而不是 invoke a f ...

  3. three.js 第二篇:场景 相机 渲染器 物体之间的关系

    w我用画画来形容他们之间的关系 场景就是纸张 相机就是我们的眼睛 物体就是在我们脑海中构思的那个画面 渲染器就是绘画这个动作 场景(Scene): 初始化:var scene = new THREE. ...

  4. 『TensorFlow』从磁盘读取数据

    十图详解TensorFlow数据读取机制 一.输入流水线读取数据流程 1). 创建文件名列表 相关函数:tf.train.match_filenames_once 2). 创建文件名队列 相关函数:t ...

  5. edu30F. Forbidden Indices

    题意:给你一个字符串s有一些位置被ban了,字符串t的价值是|t|*t在s中出现次数而且终点没有被ban.问你最大的价值是多少 题解:很明显t是s子串,建个sam,对于sam中每个位置,我们需要删除中 ...

  6. canvas实现点连线动画

    给定一系列坐标(x, y)点, 实现将各个点按照先后顺序连接起来的动画.还有两个要求: 1.点与点之间直接用线段连接, 不用考虑曲线 2.动画支持暂停, 继续, 重头开始播放功能 这个功能该怎么实现呢 ...

  7. python几种常见的模块安装方法

    1. 在线安装 1.1 在命令提示符中运行 pip install package_name 指令  注:具体前置步骤和教程:http://www.cnblogs.com/jfl-xx/p/72895 ...

  8. easyui datebox时间控件如何只显示年月

    easyui datebox控件,只显示年月,不显示年月日 需要的效果图如下: 具体的js代码: <script> $(function(){ intiMonthBox('costTime ...

  9. Python人工智能之路 - 第二篇 : 算法实在太难了有现成的直接用吧

    本节内容 预备资料: 1.FFmpeg: 链接:https://pan.baidu.com/s/1jonSAa_TG2XuaJEy3iTmHg 密码:w6hk 2.baidu-aip: pip ins ...

  10. [Leetcode 15]三数之和 3 Sum

    [题目] Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? ...