博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
手写一个Tomcat服务器
阅读量:3898 次
发布时间:2019-05-23

本文共 6167 字,大约阅读时间需要 20 分钟。

作为java开发者,都知道Tomcat是一个家户喻晓的Web服务器。手写一个Tomcat对我们理解Tomcat的工作原理,还有servlet的执行流程有很大的帮助,下面是我手写一个简要版Tomcat的总结和收获!

首先,先还原Tomcat的本质:

在这里插入图片描述
相信大家之前在开发的时候,虽然已经能上手开发web程序,但是对于Servlet的执行流程以及项目还会存在很多疑问,下面是我总结的我之前的疑问也给出相应的总结:

1.为什么要配置一个web.xml ?

2.为什么要继承Servlet,不继承不行吗?
3.为什么要重写doPost/doGet方法?
4.HttpRequest和HttpResponse是哪里冒出来的,自己从来没new过?
5.在浏览器输入Url是如何转换为调用java方法?

在这里插入图片描述

下面是我总结的Tomcat的工作流程:
1.加载配置文件,初始化ServletMapping
2.等待用户请求
3.获取到Socket对象,将socket.getInputStream()封装成request 将socket.getOutputStream()封装成response
4.实现动态调用doGet/doPost方法,并且能够自定义返回结果

详细流程:

首先用户发送url访问地址,也就是我们浏览器地址栏的地址,然后web.xml或者web.properties里面配置好访问路径和对应要交给处理的servlet的全类名,然后项目初始化的时候,加载web.xml配置文件,将其中的url和className提取出来,将其封装到ServletMapping中,这是一个键值对,键是url,值是className。然后就这就去找我们自己定义的servlet,我们自己写的servlet都会继承HttpServlet,然后就会执行父类的service在这个方法中,判断是执行doGet()还是doPost,而接收这些http协议的是HttpRequest,这个对象获取到用户的url和执行方法,然后再通过HttpResponse响应结果。

下面是我的项目结构:

在这里插入图片描述

web.properties配置文件:

在这里插入图片描述

主程序

package com.ycc.tomcat;import java.io.FileInputStream;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;import java.util.Properties;import com.ycc.http.YccRequest;import com.ycc.http.YccResponse;import com.ycc.http.YccServlet;//主要思路://1.加载配置文件,初始化ServletMapping//2.等待用户请求,用一个死循环等待用户请求//3.获取到Socket对象,将socket.getInputStream()封装成request//	                                          将socket.getOutputStream()封装成response//4.实现动态调用doGet/doPost方法,并且能够自定义返回结果public class YccTomcat {	private int port=8072;//指定端口号	private ServerSocket server;		private Map
servletMapping=new HashMap
(); 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"); YccServlet obj=(YccServlet)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(); YccRequest request=new YccRequest(is); YccResponse response=new YccResponse(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"); } // OutputStream os=socket.getOutputStream();// os.write("yechengcaho Tomact".getBytes());// out.flush(); out.close(); //为什么要关闭client?因为HTTP请求都是采用短连接 client.close(); } //启动Tomcat public void start() { //1.加载配置文件,初始化ServletMapping init(); try { server=new ServerSocket(this.port); System.out.println("Ycc 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 YccTomcat().start(); }}

YccServlet,也就是HttpServlet

package com.ycc.http;public abstract class YccServlet {	public void service(YccRequest request,YccResponse response)throws Exception {		//由service方法决定,来调用doGet或者是doPost				if("GET".equalsIgnoreCase(request.getMethod())) {			doGet(request, response);		}else {			doPost(request, response);		}	}		public abstract void doGet(YccRequest request,YccResponse response)throws Exception;		public abstract void doPost(YccRequest request,YccResponse response)throws Exception;}

YccRequest,也就是HttpRequest

package com.ycc.http;

import java.io.InputStream;

import java.util.Map;

public class YccRequest {

private String method;private String url;public YccRequest(InputStream is) {	try {	//HTTP协议就是一串字符串		String content="";	byte[] buff=new byte[1024];	int len=0;	if((len=is.read(buff))>0) {		content=new String(buff,0,len);		System.out.println(content);	}		String line=content.split("\\n")[0];	String[] arr=line.split("\\s");		this.method=arr[0];	this.url=arr[1].split("\\?")[0];		}catch(Exception e) {		e.printStackTrace();	}}public String getMethod() {	return method;}public String getUrl() {	return url;}public Map
getParmenter(){ return null;}

}

YccResponse,也就是HttpResponse

package com.ycc.http;import java.io.OutputStream;public class YccResponse {		private OutputStream os;	public YccResponse(OutputStream os) {		this.os=os;	}		public void write(String outString)throws Exception{		os.write(outString.getBytes());	}}

第一个测试Servlet:

package com.ycc.servlet;import com.ycc.http.YccRequest;import com.ycc.http.YccResponse;import com.ycc.http.YccServlet;public class FirstServlet extends YccServlet {	@Override	public void doGet(YccRequest request, YccResponse response) throws Exception {		this.doPost(request, response);			}	@Override	public void doPost(YccRequest request, YccResponse response) throws Exception {		response.write("Welcome to yechengchao Tomcat!
"); response.write("This is yechengchao01 Servlet"); }}

第二个测试Servlet:

package com.ycc.servlet;import com.ycc.http.YccRequest;import com.ycc.http.YccResponse;import com.ycc.http.YccServlet;public class SecondServlet extends YccServlet {	@Override	public void doGet(YccRequest request, YccResponse response) throws Exception {		this.doPost(request, response);			}	@Override	public void doPost(YccRequest request, YccResponse response) throws Exception {		response.write("Welcome to yechengchao Tomcat!
"); response.write("This is yechengchao02 Servlet"); }}

测试效果

在这里插入图片描述

在这里插入图片描述

转载地址:http://kiyen.baihongyu.com/

你可能感兴趣的文章
Part-Guided Attention Learning for Vehicle Instance Retrieval
查看>>
Deep Residual Learning for Image Recognition
查看>>
Bag of Tricks and A Strong Baseline for Deep Person Re-identification
查看>>
vue+flask实现视频目标检测yolov5
查看>>
关于BigInteger
查看>>
UIScrollView不能响应UITouch事件
查看>>
iOS TextFiled 文本密码切换 光标偏移解决
查看>>
iOS 当前应用所占内存和设备可用内存
查看>>
iOS 文件属性
查看>>
UIView的layoutSubviews和drawRect方法何时调用
查看>>
iOS GCD多线程下载原理
查看>>
NSData全部API解释
查看>>
iOS 侧滑菜单封装Demo(类似QQ侧滑效果)
查看>>
Spring学习(二)
查看>>
Spring学习(三)
查看>>
Spring学习(四)
查看>>
java解惑——易错知识点归纳总结
查看>>
Memcached 集群部署
查看>>
Memcached与Spring AOP构建数分布式据库前端缓存框架
查看>>
数据挖掘常用算法整理
查看>>