JavaWeb学习笔记3:tomcat实现原理

打在前面:部分图截自 马士兵老师servlet与jsp
听课笔记。
视频链接:https://www.bilibili.com/video/BV1cV411H7RY?p=1

**tomcat运行原理:
*
客户端与服务器端交互图
交互流程:
客户端向服务器发送请求,tomcat request接收请求,并呈递给service request对象,request对象选取提前写好的applet程序来处理请求,并response响应,完成服务。在这个过程中,webserver容器有很多applet,service怎么知道调用哪个?applet里装的是对请求的处理。但刚开始一定要先处理的是封装request和response对象。
请求报文格式:
请求报文格式

package com.msb;

import java.io.IOException;
import java.io.InputStream;

public class MyRequest {
    
    
	private String requestMethod;
	private String requestUrl;
	public MyRequest(InputStream inputStream) throws IOException {
    
    
		//创建缓冲区
		byte[] buffer=new byte[1024];
		int len=0;
		String str=null;
		if((len=inputStream.read(buffer))>0) {
    
    
			str=new String(buffer,0,len);
		}
		String data=str.split("\n")[0];
		String[] params=data.split(" ");
		this.requestMethod=params[0];
		this.requestUrl=params[1];
	}
	public String getRequestMethod() {
    
    
		return requestMethod;
	}
	public void setRequestMethod(String requestMethod) {
    
    
		this.requestMethod = requestMethod;
	}
	public String getRequestUrl() {
    
    
		return requestUrl;
	}
	public void setRequestUrl(String requestUrl) {
    
    
		this.requestUrl = requestUrl;
	}
	
}

这里是request的简单封装,只是模拟原理。
代码解读:数据传输还是流的传输,请求对象接收inputstream流,设立缓冲区分割解析成字符串类型数据处理。
响应格式

package com.msb;

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 str) throws IOException {
    
    
		StringBuilder builder = new StringBuilder();
		builder.append("HTTP/1.1 200 OK\n")
				.append("Content-Type:text/html\n")
				.append("\r\n")
				.append("<html>")
				.append("<body>")
				.append("<h1>"+str+"</h1>")
				.append("</body>")
				.append("</html>");
		this.outputStream.write(builder.toString().getBytes());
		
	}
}

代码解读:response将处理好的字符串转换成流响应,注意“append(“\r\n”)”.封装
封装好我们发现:其实这个过程就是索取(request)和给予(response)的过程,你要索取什么(requesturl)就掉哪个applet,我们可以把每个requesturl和applet封装类做一个映射关系,因为每个applet都有相同的方法只是方法体不一样,所以我们可以用一个抽象类让他们都继承,或者用接口来规范他们。

package com.msb;

public abstract class MyHttpServlet {
    
    
	public static final String METHOD_GET="GET";
	public static final String METHOD_POST="POST";
	
	public abstract void doGet(MyRequest request,MyResponse response);
	public abstract void doPost(MyRequest request,MyResponse response);
	
	
	//根据请求判断调用哪个方法
	public void service(MyRequest request,MyResponse response) {
    
    
		if(METHOD_GET.equals(request.getRequestMethod())) {
    
    
			doGet(request,response);
		}else if(METHOD_POST.equals(response)) {
    
    doPost(request,response);}
	}
}
package com.msb;

import java.io.IOException;

public class MyServlet extends MyHttpServlet {
    
    

	@Override
	public void doGet(MyRequest request, MyResponse response) {
    
    
		try {
    
    
			response.write("doget:MyServlet");
		} catch (IOException e) {
    
    
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	@Override
	public void doPost(MyRequest request, MyResponse response) {
    
    
		try {
    
    
			response.write("doPost:MyServlet");
		} catch (IOException e) {
    
    
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

映射关系:

package com.msb;

import java.util.HashMap;

public class MyMapping {
    
    
	public static HashMap<String,String> mapping=new HashMap<String,String>();
	
	static {
    
    
		mapping.put("/MyTomCat", "com.msb.MyServlet");
		
	}

	public static HashMap<String, String> getMapping() {
    
    
		return mapping;
	}

	
}

回到图一:

我们把service、interface、applet封装好了,还缺少网络交互和service-applet交互。server便是完成这个过程。

package com.msb;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

//定义服务端的接收程序,接收socket请求

public class MyServer {
    
    

	//定义服务端的接受程序,接受socket请求
	
	@SuppressWarnings("deprecation")
	public static void startServer(int port) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
    
    
		ServerSocket serverSocket = new ServerSocket(port);
		Socket socket=null;
		while(true) {
    
    
			socket=serverSocket.accept();
			InputStream inputStream = socket.getInputStream();
			OutputStream outputStream = socket.getOutputStream();
			MyRequest request=new MyRequest(inputStream);
			MyResponse response = new MyResponse(outputStream);
			String clazzName = new MyMapping().getMapping().get(request.getRequestUrl());
			if(clazzName!=null) {
    
    
				Class<? extends MyHttpServlet> clazz = (Class<? extends MyHttpServlet>)Class.forName(clazzName);
				MyHttpServlet newInstance = clazz.newInstance();
				newInstance.service(request, response);
				
			}
		}
		
	}
	public static void main(String[] args) {
    
    
		try {
    
    
			startServer(1775);
		} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IOException e) {
    
    
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

代码解读:静态方法startserver方法参数:端口号。把参数传给服务器套接字(serversocket),铁门栓(死循环)实现长服务,服务器接受到请求赋给套接字处理,套接字获取流,传递创建MyRequest、MyRespond对象,关键代码:String clazzName = new MyMapping().getMapping().get(request.getRequestUrl());获取请求url映射调用的applet,再用反射机制创建applet对象,多态调用doget/dopost方法处理请求,响应。
运行后浏览器请求结果:

但还存在一些问题,如多线程高并发等,过后再实现。

猜你喜欢

转载自blog.csdn.net/qq_52605986/article/details/116995860