实现一个简单的Tomcat

1. Tomcat作用

我们的web应用会运行在Tomcat中,那么显然请求必定是先到达Tomcat的,Tomcat对于请求实际上会进行如下的处理:

  • 提供Socket服务:Tomcat的启动,必然是Socket服务,支持http协议。
  • 进行请求的分发:一个Tomcat可以为多个web应用提供服务,那么就需要把url下发到不同的web应用。
  • 需要将请求和响应封装成request和response:我们在写后端代码的时候都是直接使用request和response的,这是因为Tomcat已经做好了。

下面我们就自己来实现这三步。

2. 实现代码

项目结构:

  src
└─mytomcat
BookServlet.java
CarServlet.java
MyRequest.java
MyResponse.java
MyServlet.java
MyTomcat.java
ServletMapping.java
ServletMappingConfig.java

2.1 封装http请求和响应

package mytomcat;

import java.io.IOException;
import java.io.InputStream; /**
* 封装http请求
*/
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.split("\n")[0];
url = httpHead.split("\\s")[1];
method = httpHead.split("\\s")[0]; System.out.println(this.toString());
} 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;
} @Override
public String toString() {
return "MyRequest -- url:" + url + ",method:" + method;
} }
package mytomcat;

import java.io.IOException;
import java.io.OutputStream; /**
* 封装http响应
*/
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(content); outputStream.write(httpResponse.toString().getBytes());
outputStream.close();
} }

2.2 实现不同的Servlet

package mytomcat;
/**
* Servlet抽象类
*/
public abstract class MyServlet { public abstract void doGet(MyRequest myRequest, MyResponse myResponse); public abstract void doPost(MyRequest myRequest, MyResponse myResponse); public void service(MyRequest myRequest, MyResponse myResponse) {
if(myRequest.getMethod().equalsIgnoreCase("POST")) {
doPost(myRequest, myResponse);
}else if(myRequest.getMethod().equalsIgnoreCase("GET")) {
doGet(myRequest, myResponse);
}
}
}
package mytomcat;

import java.io.IOException;

/**
* 处理操作'书'的http请求
*/
public class BookServlet extends MyServlet { @Override
public void doGet(MyRequest myRequest, MyResponse myResponse) {
try {
myResponse.write("[get] book...");
}catch(IOException e) {
e.printStackTrace();
}
} @Override
public void doPost(MyRequest myRequest, MyResponse myResponse) {
try {
myResponse.write("[post] book...");
}catch(IOException e) {
e.printStackTrace();
}
} }
package mytomcat;

import java.io.IOException;

/**
* 处理操作'车'的http请求
*/
public class CarServlet extends MyServlet { @Override
public void doGet(MyRequest myRequest, MyResponse myResponse) {
try {
myResponse.write("[get] car...");
}catch(IOException e) {
e.printStackTrace();
} } @Override
public void doPost(MyRequest myRequest, MyResponse myResponse) {
try {
myResponse.write("[post] car...");
}catch(IOException e) {
e.printStackTrace();
}
} }

2.3 定义Servlet映射POJO类

package mytomcat;

public class ServletMapping {

	private String servletName;
private String url;
private String className; public ServletMapping(String servletName, String url, String className) {
super();
this.servletName = servletName;
this.url = url;
this.className = className;
} public String getServletName() {
return servletName;
} public void setServletName(String servletName) {
this.servletName = servletName;
} public String getUrl() {
return url;
} public void setUrl(String url) {
this.url = url;
} public String getClassName() {
return className;
} public void setClassName(String className) {
this.className = className;
} }

2.4 配置Servlet映射关系

package mytomcat;

import java.util.ArrayList;
import java.util.List; /**
* 配置请求url和处理的servlet的对应关系
*/
public class ServletMappingConfig { public static List<ServletMapping> servletMappingList = new ArrayList<>();; static {
servletMappingList.add(new ServletMapping("Book", "/book", "mytomcat.BookServlet"));
servletMappingList.add(new ServletMapping("Car", "/car", "mytomcat.CarServlet"));
} }

2.5 主类

package mytomcat;

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;
//保存请求url和处理请求servlet的对应关系
private Map<String, String> urlServletMap = new HashMap<String, String>(); public MyTomcat(int port) {
this.port = port;
} public void start() {
initServletMapping(); ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
System.out.println("MyTomcat is start...\n监听端口:" + port); while(true) {
System.out.println("等待请求...");
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream(); MyRequest myRequest = new MyRequest(inputStream);
MyResponse myResponse = new MyResponse(outputStream); //请求分发
disPatch(myRequest, myResponse);
socket.close();
}
}catch(IOException e) {
e.printStackTrace();
}finally {
if(serverSocket != null) {
try {
serverSocket.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}
} //初始化url和处理的servlet的对应关系
private void initServletMapping() {
for(ServletMapping servletMapping: ServletMappingConfig.servletMappingList) {
urlServletMap.put(servletMapping.getUrl(), servletMapping.getClassName());
}
} //分发处理请求
private void disPatch(MyRequest myRequest, MyResponse myResponse) {
String className = urlServletMap.get(myRequest.getUrl()); //反射
try {
Class<MyServlet> myServletClass = (Class<MyServlet>) Class.forName(className);
MyServlet myServlet = myServletClass.newInstance(); myServlet.service(myRequest, myResponse);
}catch(Exception e) {
e.printStackTrace();
}
} public static void main(String[] args) {
MyTomcat myTomcat = new MyTomcat(8080);
myTomcat.start();
}
}

3. 测试

运行MyTomcat主类,然后在浏览器输入http://localhost:8080/car,可以看到返回[get] car...,大功告成。

源码地址:

https://github.com/WangJun-SCU/mytomcat

实现一个简单的Tomcat的更多相关文章

  1. 自己模拟的一个简单的tomcat

    servlet容器的职责 总的来说,一个全功能的servlet容器会为servlet的每个HTTP请求做下面的一些工作: 1,当第一次调用servlet的时候,加载该servlet类并调用servle ...

  2. 模拟一个简单的tomcat

    目录 简单处理 每个请求一个线程 模拟tomcat 参考 简单处理 // 客户端和服务器的通信,说到底就是两个数据的传输, // 客户端发送inputStream给服务器,服务器回复 // outpu ...

  3. IntelliJ IDEA 15 部署Tomcat及创建一个简单的Web工程

    一.部署Tomcat 二.创建一个简单的Web工程 2.1创建一个新工程 创建一个新工程 设置JDK及选择Web Application (创建的是Web工程) 点击Next,选择工作空间,起个工程名 ...

  4. Web开发之tomcat配置及使用(环境变量设置及测试,一个简单的web应用实例)

    Tomcat的配置及测试: 第一步:下载tomcat,然后解压到任意盘符 第二步:配置系统环境变量 tomcat解压到的D盘 (路径为: D:\tomcat), 配置环境变量: 启动tomcat需要两 ...

  5. how tomcat works 札记(两)----------一个简单的servlet集装箱

    app1 (看着眼前这章建议读者,看how tomcat works 札记(一个)----------一个简单的webserver http://blog.csdn.net/dlf123321/art ...

  6. Tomcat剖析(二):一个简单的Servlet服务器

    Tomcat剖析(二):一个简单的Servlet服务器 1. Tomcat剖析(一):一个简单的Web服务器 2. Tomcat剖析(二):一个简单的Servlet服务器 3. Tomcat剖析(三) ...

  7. Tomcat剖析(一):一个简单的Web服务器

    Tomcat剖析(一):一个简单的Web服务器 1. Tomcat剖析(一):一个简单的Web服务器 2. Tomcat剖析(二):一个简单的Servlet服务器 3. Tomcat剖析(三):连接器 ...

  8. how tomcat works 读书笔记(二)----------一个简单的servlet容器

    app1 (建议读者在看本章之前,先看how tomcat works 读书笔记(一)----------一个简单的web服务器 http://blog.csdn.net/dlf123321/arti ...

  9. tomcat原理解析(一):一个简单的实现

    tomcat原理解析(一):一个简单的实现 https://blog.csdn.net/qiangcai/article/details/60583330 2017年03月07日 09:54:27 逆 ...

随机推荐

  1. NumPy 百题大冲关,冲鸭!

    角色名称:NumPy 角色描述:NumPy是一个NASA都在用的扩展库. NumPy提供了许多高级的数值编程技能,如:矩阵数据类型.矢量处理,以及精密的运算库.专为进行严格的数字处理而战斗.是很多大型 ...

  2. django 配置文件settings.py 设置模板

    INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'dj ...

  3. 3D Experience — 产品协同研发平台

    随着产品复杂程度的提升,市场竞争愈加激烈,基于模型的正向研发已经作为有效的应对手段被广泛接受.但研发流程中仍然存在复杂功能架构定义困难.多方案难以权衡.多系统难以联合仿真,仿真效率低,验证不充分等问题 ...

  4. 基于Java+Selenium的WebUI自动化测试框架(六)---浏览器初始化

    本篇我们来讨论,如何写一个浏览器初始化的类.在写之前,先思考一下,我们需要一个什么样的初始化? 先来看看使用原生的Java + selenium是怎么做的.(以firefox为例) System.se ...

  5. 胡搞-强化版的light oj-1055-的思路-AI版的6重暴力For循环的BFS

    新题目大意: 三个棋子按照先后顺序,可以随意方向合法地走到空位置上(而不是像原题light oj-1055中的一样三个棋子每次走的方向都一致),当三个棋子全部走进目标地点,就结束:求需要指挥的最少次数 ...

  6. 14 webpack中url-loader的使用

    默认情况下,webpack无法处理css文件中的url地址,不管是图片还是字体库,只要是URL地址,都处理不了,需要第三方loader 1.安装loader cnpm i url-loader fil ...

  7. Jenkins+jmeter+ant+Git 持续集成(六、代码提交到Gitlab即自动构建)

    实现原理: 利用jenkins和gitlab的webhook结合,实现提交代码之后,自动触发jenkins的构建. 1.Jenkins的插件安装: 需要安装两个gitlab的插件:Gitlab Hoo ...

  8. Django连接MySQL数据库配置

    1.自己手动创建数据库 create database 数据库名; # 如: create database bms character set utf8; # 授权访问: grant all pri ...

  9. 【noi2019集训题1】 脑部进食 期望dp+高斯消元

    题目大意:有n个点,m条有向边,每条边上有一个小写字母. 有一个人从1号点开始在这个图上随机游走,游走过程中他会按顺序记录下走过的边上的字符. 如果在某个时刻,他记录下的字符串中,存在一个子序列和S2 ...

  10. vscode源码启动时需要的electron缓存位置

    C:\Users\Administrator\AppData\Local\Temp\gulp-electron-cache 可以把下好的electron release直接放到这个目录,就不用重新下了 ...