手写 Tomcat
作为java开发者,都知道Tomcat是一个家户喻晓的Web服务器。手写一个Tomcat对我们理解Tomcat的工作原理,还有servlet的执行流程有很大的帮助,下面是我手写一个简要版Tomcat的总结和收获!
首先,需要了解浏览器与Web服务器是如何处理请求的
1. 浏览器与服务器
当我们打开浏览器,在浏览器的地址栏中输入URL地址访问服务器上的资源的过程中,浏览器和服务器都做了神马操作呢,我们是怎么在浏览器里面看到1.
浏览器和服务器做了以下几个操作:
1、浏览器根据主机名去操作系统的Hosts文件中查找主机名对应的IP地址。
2、浏览器如果在操作系统的Hosts文件中没有找到对应的IP地址,就去互联网上的DNS服务器上查找这台主机对应的IP地址。
3、浏览器查找到"访问地址"这台主机对应的IP地址后,就使用IP地址连接到Web服务器。
4、浏览器连接到web服务器后,就使用http协议向服务器发送请求,发送请求的过程中,浏览器会向Web服务器以Stream(流)的形式传输数据,告诉Web服务器要访问服务器里面的哪个Web应用下的Web资源
5、浏览器做完上面4步工作后,就开始等待,等待Web服务器把自己想要访问的资源给它
6.服务器接收到浏览器传输的数据后,开始解析接收到的数据,服务器解析里面的内容时知道客户端浏览器的请求,然后服务器响应请求,讲请求的内容传输给浏览器。
7.浏览器拿到服务器传输给它的数据之后,就可以把数据展现给用户看了
了解了浏览器与服务器的加护过程,我们重点要注意的是tomcat是如何解析和响应请求的
2 tomcat是如何解析和响应请求的
-
首先接受用户发送url访问地址,也就是我们浏览器地址栏的地址,
-
然后web.xml或者web.properties里面配置好访问路径和对应要交给处理的servlet的全类名,然后项目初始化的时候,加载web.xml配置文件,将其中的url和className提取出来,将其封装到ServletMapping中,这是一个键值对,键是url,值是className。
-
接着就这就去找我们自己定义的servlet,我们自己写的servlet都会继承HttpServlet,然后就会执行父类的service在这个方法中,判断是执行doGet()还是doPost,而接收这些http协议的是HttpRequest,这个对象获取到用户的url和执行方法,然后再通过HttpResponse响应结果
明白了tomcat的详细流程,我们可以总结出Tomcat的工作流程
3.Tomcat的大致流程
1.加载配置文件,初始化ServletMapping
2.等待用户请求
3.获取到Socket对象,将socket.getInputStream()封装成request 将socket.getOutputStream()封装成response
4.实现动态调用doGet/doPost方法,并且能够自定义返回结果
代码如下
下面是我的项目结构:
主程序
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import com.kkb.http.TzRequest;
import com.kkb.http.TzResponse;
import com.kkb.http.TzServlet;
//主要思路:
//1.加载配置文件,初始化ServletMapping
//2.等待用户请求,用一个死循环等待用户请求
//3.获取到Socket对象,将socket.getInputStream()封装成request
// 将socket.getOutputStream()封装成response
//4.实现动态调用doGet/doPost方法,并且能够自定义返回结果
public class TzTomcat {
private int port=2080;//指定端口号
private ServerSocket server;
private Map<String, TzServlet> servletMapping=new HashMap<String,TzServlet>();
private Properties webxml=new Properties();
//1.加载配置文件,初始化ServletMapping
private void init() {
//加载web.xml文件,同时初始化ServletMapping对象
try {
String WEB_INF=this.getClass().getResource("/").getPath();
FileInputStream fis=new FileInputStream(WEB_INF+"web.properties");
webxml.load(fis);
for (Object k : webxml.keySet()) {
String key=k.toString();
if(key.endsWith(".url")) {
//投机取巧,取到servletName
String servletName=key.replaceAll("\\.url$","");
String url=webxml.getProperty(key);
String className=webxml.getProperty(servletName+".class");
TzServlet obj=(TzServlet)Class.forName(className).newInstance();
servletMapping.put(url, obj);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void process(Socket client) throws Exception {
//3.获取到Socket对象,将socket.getInputStream()封装成request
// 将socket.getOutputStream()封装成response
InputStream is=client.getInputStream();
OutputStream out=client.getOutputStream();
TzRequest request=new TzRequest(is);
TzResponse response=new TzResponse(out);
//4.实现动态调用doGet/doPost方法,并且能够自定义返回结果
//想办法拿到用户所请求的url
String url=request.getUrl();
if(servletMapping.containsKey(url)) {
servletMapping.get(url).service(request, response);
}else {
response.write("404 - Not Found");
}
out.flush();
out.close();
//为什么要关闭client?因为HTTP请求都是采用短连接
client.close();
}
//启动Tomcat
public void start() {
//1.加载配置文件,初始化ServletMapping
init();
try {
server=new ServerSocket(this.port);
System.out.println("Tuzi Tomcat 已启动,监听的端口是:"+this.port);
//得到一个客户端
//Socket socket=server.accept();
//2.等待用户请求,用一个死循环等待用户请求
while(true) {
Socket client=server.accept();
process(client);
}
//System.out.println(socket);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new TzTomcat().start();
}
}
第一个测试Servlet
package com.kkb.servlet;
import com.kkb.http.TzRequest;
import com.kkb.http.TzResponse;
import com.kkb.http.TzServlet;
public class FirstServlet extends TzServlet {
@Override
public void doGet(TzRequest request, TzResponse response) throws Exception {
this.doPost(request, response);
}
@Override
public void doPost(TzRequest request, TzResponse response) throws Exception {
response.write("Welcome to tuzi Tomcat!<br/><br/>");
response.write("This is tuzi01 Servlet");
}
}
访问测试结果
上一篇: Rxjava学习笔记-01