手写简化版Tomcat

tomacat是什么:
在这里插入图片描述
web容器,servlet容器只知道用导致我至今不是分得很清晰。看下面这篇文章,思路清晰

博客一https://blog.csdn.net/lz233333/article/details/68065749?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
博客二
https://blog.csdn.net/qq_39688352/article/details/76794973?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

Tomcat作为Web服务器深受市场欢迎,有必要对其进行深入的研究。在工作中,我们经常会把写好的代码打包放在Tomcat里并启动,然后在浏览器里就能愉快的调用我们写的代码来实现相应的功能了,那么Tomcat是如何工作的?

启动Tomcat时双击的startup.bat文件的主要作用是找到catalina.bat,并且把参数传递给它,而catalina.bat中有这样一段话:

在这里插入图片描述

找到
在这里插入图片描述
解压到桌面可查看源码,将.class文件拖进idea可自动反编译
在这里插入图片描述
在这里插入图片描述
这个类有两个作用 :1.初始化一个守护进程变量、加载类和相应参数。2.解析命令,并执行。

实现一个简单的Tomcat

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

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

下面是参考的代码
文章摘自:wangjun

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

看代码吧
在这里插入图片描述
一、新建一个配置类保存tomcat的访问地址,相当于tomcat中配置的项目访问路径


/**
 * 配置请求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"));
	}

}

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;
	}
	
}

二、服务器收到一个Servlet请求时,就会产生一个新进程,在这个线程中,让Servlet对象调用service()方法为请求做出响应。service方法首先检查HTTP请求类型(get或post),并根据用户的请求方式,在service()方法中对应的调用doGet()或doPost()方法。

在Servlet类中重写doGet()或doPost()方法来响应用户的请求,可以增加响应的灵活度,同时减轻服务器的负担。
一般情况下无论用户请求是post或get,服务器的处理过程完全相同。
也可以在doPost()中写处理过程的代码,而在doGet()方法内再调用doPost方法。这里在子类中实现

package mytomcat;

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);
		}
	}
}

这里写两个类来实现doget和dopost,.抽象Servlet类来转码处理请求和响应的业务。发过来的请求会有很多,也就意味着我们应该会有很多的Servlet,可以用到类似于工厂模式的方法处理,随时产生很多的Servlet,来满足不同的功能性的请求。

package mytomcat;

import java.io.IOException;

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();
		}
	}

}

package mytomcat;

import java.io.IOException;

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();
		}
	}

}

三、tomcat是servlet的容器,现在有了servelt,当有请求进入的时候,我们需要监听,也需要返回,这就许要用到socket去做中间的获取端口的http请求:
socket servlet tomcat 关系参考:

文章一
https://blog.csdn.net/MuErHuoXu/article/details/86606970
文章二
https://www.cnblogs.com/aspnetdream/p/4217581.html

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) {
			System.out.println("没有该地址");
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		MyTomcat myTomcat = new MyTomcat(8080);
		myTomcat.start();
	}
}

package mytomcat;

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(content);
		
		outputStream.write(httpResponse.toString().getBytes());
		outputStream.close();
	}

}

package mytomcat;

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.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;
		}

}

测试
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

健身小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值