源码下载链接](https://download.csdn.net/download/yang134679/11092413)
我们先来看一段代码
package com.ys.tomcat.test;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class MyTomcatPre {
public static void main(String[] args) throws Exception{
//定义服务端的端口号
ServerSocket serverSocket = new ServerSocket(9999);
//TomCat启动
System.out.println("TomCat已经启动");
//永无休止的接收服务
while(true){
//建立一个socket请求,一旦有客户端连上了进行接收
Socket socket = serverSocket.accept();
//获取输入流
InputStream inputStream = socket.getInputStream();
//缓冲
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
//将接收到的信息打印到控制台
String msg = null;
while ((msg = bufferedReader.readLine()) != null){
if (msg.length() == 0){
break;
}
System.out.println(msg);
}
}
}
}
这是我们设置的一个ServerSocket 服务,端口号9999,当浏览器向其发出请求,会在控制台打印出对应的http请求。
我们启动测试类
在浏览器发起请求
得到以下结果
有了基本服务器知识后,进行简易源码实现
项目主体结构
当我们tomcat启动时收到请求后,需要对请求进行处理,之前我们使用servlet的doget和dopost方法进行请求,这里我们进行实现的还原
主类(MyTomcat)源码
package com.ys.tomcat;
import com.ys.tomcat.servlet.HttpServlet;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
public class MyTomcat {
//使用HashMap存储,初始化servlet信息
public static final HashMap servletMapping = new HashMap<>();
public static void main(String[] args) throws Exception{
//第一步,初始化servlet
//资源路径
String basePath;
//获取basePath
basePath = MyTomcat.class.getResource("/").getPath();
//1.获取解析器
SAXReader reader = new SAXReader();
//2。获取document文档对象
Document document = reader.read(new File(basePath + "web.xml"));
//3.获取根元素
Element root = document.getRootElement();
//4.获取根元素下的子元素
List childElements = root.elements();
//5.遍历子元素
for (Element element: childElements) {
//6.判断元素名称为servlet的元素
if("servlet".equals(element.getName())){
//7.获取servlet—name元素
Element servletName = element.element("servlet-name");
//8.获取servlet-class元素
Element servletClass = element.element("servlet-class");
//检测输出
System.out.println(servletName.getText()+"\t"+servletClass.getText());
//9.将web.xml中的servlet-name和servlet-class值进行存储
servletMapping.put(servletName.getText(),
(HttpServlet)Class.forName(servletClass.getText()).newInstance());
}
}
//第二阶段--暴露接口,处理请求
//定义服务端的端口号
ServerSocket serverSocket = new ServerSocket(8080);
//TomCat启动
System.out.println("TomCat已经启动");
//永无休止的接收服务
while(true){
//建立一个socket请求,一旦有客户端连上了进行接收
Socket socket = serverSocket.accept();
//接收一个开启一个线程
Thread thread = new ServletThread(socket);
//开启线程
thread.start();
}
}
}
首先我们利用dom4j这个jar包对web.xml文件进行解析,保证在main方法中首先启动servlet服务
web.xml源码
mytomcat
com.ys.tomcat.servlet.MyServlet
但是我们首先要封装一个Request类,这个类我们用来获取请求头信息中的请求方法和请求的url信息
package com.ys.tomcat.http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
/**
* http请求封装类
*/
public class Request {
//请求类型 get/post
private String method;
//请求资源路径 url
private String url;
public Request(InputStream inputStream) throws IOException{
//缓冲,转码
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
//创建一个String数组保存请求头信息,先读取一行信息,然后按照“ ”切割
String[] input = reader.readLine().split(" ");
//数组第一个是请求方法
this.method = input[0];
//数组的第二位是url
this.url = input[1];
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
同时我们也需要对Response响应做数据封装
Response源码
package com.ys.tomcat.http;
import java.io.OutputStream;
/**
* 请求封装类
*/
public class Response {
//response是输出响应,用输出流
public OutputStream outputStream;
//状态行
//Http版本,状态码,状态信息
//响应报文头部
//用于说明服务器要使用的附加资源
//空行
//请求头和主体数据间必须有换行
public static String responseHeader = "Http/1.1 200 \r\n"
+"Content-Type:text/html \r\n"
+"\r\n";
public Response(OutputStream outputStream) {
this.outputStream = outputStream;
}
}
读取到了servlet配置之后,我们还原servlet
SuperServlet源码
package com.ys.tomcat.servlet;
import com.ys.tomcat.http.Request;
import com.ys.tomcat.http.Response;
import java.io.IOException;
public interface SuperServlet {
//初始化方法
void init();
//service方法
void service(Request request, Response response) throws IOException;
//销毁方法
void destroy();
}
HttpServlet源码(仿照原jdk中HttpServlet),service中判断调用的方法,再调用具体实现类中
package com.ys.tomcat.servlet;
import com.ys.tomcat.http.Request;
import com.ys.tomcat.http.Response;
import java.io.IOException;
public abstract class HttpServlet implements SuperServlet{
//初始化方法
@Override
public void init() {
}
//销毁方法
@Override
public void destroy() {
}
//核心业务方法
@Override
public void service(Request request, Response response) throws IOException {
//判断是否哪种请求方法get/post
if("get".equalsIgnoreCase(request.getMethod())){
doGet(request,response);
}else{
doPost(request,response);
}
}
//等待实例类调用
public abstract void doGet(Request request, Response response);
public abstract void doPost(Request request, Response response);
}
MyServlet源码,在这里具体处理调用方法
package com.ys.tomcat.servlet;
/**
* 自定义servlet
*/
import com.ys.tomcat.http.Request;
import com.ys.tomcat.http.Response;
import java.io.OutputStream;
public class MyServlet extends HttpServlet{
@Override
public void doPost(Request request, Response response) {
try{
System.out.println("请求的method(类型)"+request.getMethod());
System.out.println("请求的url"+request.getUrl());
//返回response请求头+请求信息
String res = Response.responseHeader + "connection succession...";
//
OutputStream outputStream = response.outputStream;
//
outputStream.write(res.getBytes());
//冲刷
outputStream.flush();
//关闭流对象
outputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void doGet(Request request, Response response) {
doPost(request,response);
}
}
处理好servlet之后,我们第二部就要等待访问连接了,主类中一旦有请求,就会创建一个ServletThread线程,进行服务
ServletThread源码
package com.ys.tomcat;
import com.ys.tomcat.http.Request;
import com.ys.tomcat.http.Response;
import com.ys.tomcat.servlet.HttpServlet;
import java.io.OutputStream;
import java.net.Socket;
/**
*自定义的线程执行tomcat操作(对servlet进行处理)
*
*/
public class ServletThread extends Thread{
//创建socket对象接受数据
protected Socket socket;
//初始化传值
public ServletThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try{
System.out.println("执行的线程"+Thread.currentThread());
//将输入流对象传递给request对象
Request request = new Request(socket.getInputStream());
//拿到响应封装
Response response = new Response(socket.getOutputStream());
//service来处理(通过请求路径来实例化servlet—servletMapping)
HttpServlet httpServlet = MyTomcat.servletMapping.get(request.getUrl().replace("/",""));
//判断取出的HttpServlet对象是否为空
if(httpServlet != null){//存在对应的servlet
//调用servlet执行方法
httpServlet.service(request,response);
}else{//如果找不到对应的servlet信息
//返回response请求头+请求信息
String res = Response.responseHeader + "connection default...";
//
OutputStream outputStream = socket.getOutputStream();
//
outputStream.write(res.getBytes("utf-8"));
//冲刷
outputStream.flush();
//关闭流对象
outputStream.close();
}
}catch(Exception e){
e.printStackTrace();
}finally{
//关闭socket连接
if(socket != null){
try{
socket.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
}
至此一个简单的tomcat实现原理就完成了,需要源码请访问添加链接描述