打在前面:部分图截自 马士兵老师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方法处理请求,响应。
运行后浏览器请求结果:
但还存在一些问题,如多线程高并发等,过后再实现。