tomcat是十分常用的轻量级的web服务容器,其原理其实不复杂,本质就是在jdk的socket,输入输出流,反射,线程池等技术基础上封装出的一套方便开发与客户端交互的服务器。但更常用于http协议的web项目开发。
下面我们实现一个自己的简易的tomcat服务。
1,服务总类
程序的入口,负责创建一个ServerSocket 服务端,监听客户端请求并创建Socket 客户端响应,为提升并发能力,创建连接池来分发任务。
package com.lly;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyWebServer {
public static void startServer(int port) throws Exception{
@SuppressWarnings("resource")
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("创建服务成功");
Socket socket = null;
int count =0;
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(32);
while (true) {
socket = serverSocket.accept();
System.out.println("收到客户端请求次数:"+(++count));
newFixedThreadPool.execute(new MyRunnable(socket));
}
}
public static void main(String[] args) {
try {
System.out.println("start WebServer");
startServer(8080);
} catch (Exception e) {
e.printStackTrace();
}
}
}
2,处理每个服务的Runnable 线程类
接收服务总类分配过来的socket对象,并获取到输入输出流来创建request和response对象,通过request得到请求的相关信息,分配给相应的servlet来处理业务请求。
package com.lly;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* Handles requests received by the socket server
*/
public class MyRunnable implements Runnable {
Socket socket = null;
public MyRunnable() {
super();
}
public MyRunnable(Socket socket) {
super();
this.socket = socket;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println("当前线程:" + name);
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
MyRequest request;
request = new MyRequest(inputStream);
MyResponse response = new MyResponse(outputStream);
String clazz = new MyMapping().getMapping().get(request.getRequestUrl());
if (clazz != null) {
Class<MyAbstractHttpServlet> myServletClass = (Class<MyAbstractHttpServlet>)Class.forName(clazz);
MyAbstractHttpServlet myServlet;
myServlet = myServletClass.newInstance();
myServlet.service(request, response);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
3,Request 类
负责根据输入流解析请求数据。
package com.lly;
import java.io.IOException;
import java.io.InputStream;
public class MyRequest {
private String requestMethod="";
private String requestUrl="";
public MyRequest(InputStream inputStream) throws Exception{
byte[] buffer = new byte[1024];
String[] params = extracted(inputStream, buffer);
if(params!=null && params.length>=2) {
this.requestMethod = params[0];
this.requestUrl = params[1];
}
}
private String[] extracted(InputStream inputStream, byte[] buffer) throws IOException {
String[] params = null;
try {
int len;
String str = "";
if((len = inputStream.read(buffer,0,1024))>0){
str += new String(buffer,0,len);
}
String data = str.split("\n")[0];
params = data.split(" ");
} catch (Exception e) {
System.out.println(e.toString());
}
return params;
}
public String getRequestMethod() {
return requestMethod;
}
public String getRequestUrl() {
return requestUrl;
}
}
4,Response类
负责按照servlet服务类给的返回数据来给客户端响应数据。
package com.lly;
import java.io.OutputStream;
public class MyResponse {
private OutputStream outputStream;
public MyResponse(OutputStream outputStream) {
this.outputStream = outputStream;
}
public void write(String str) throws Exception {
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());
this.outputStream.flush();
this.outputStream.close();
System.out.println("响应success...");
}
}
5,AbstractHttpServlet
定义一套Servlet的规范,包含doGet和doPost两个抽象方法和一个service方法。
package com.lly;
public abstract class MyAbstractHttpServlet {
public static final String METHOD_GET = "GET";
public static final String METHOD_POST = "POST";
public abstract void doGet(MyRequest request,MyResponse response) throws Exception;
public abstract void doPost(MyRequest request,MyResponse response) throws Exception;
/**
* @param request
* @param response
*/
public void service(MyRequest request,MyResponse response) throws Exception{
if(METHOD_GET.equals(request.getRequestMethod())){
doGet(request,response);
}else if(METHOD_POST.equals(request.getRequestMethod())){
doPost(request,response);
}
}
}
6,Servlet 类
接收request,response对象,并调用相应的业务类处理后用response响应客户端。
package com.lly;
public class MyServlet extends MyAbstractHttpServlet {
@Override
public void doGet(MyRequest request, MyResponse response) throws Exception {
response.write("<a href=\"https://user.qzone.qq.com/172496791?source=friendlist\">click me</a>");
}
@Override
public void doPost(MyRequest request, MyResponse response) throws Exception {
doGet(request, response);
}
}
7,Mapping 类
负责映射服务端请求地址和servlet类的关系
package com.lly;
import java.util.HashMap;
public class MyMapping {
public static HashMap<String,String> mapping = new HashMap<String,String>();
static {
mapping.put("/myTomcat","com.lly.MyServlet");
}
public HashMap<String,String> getMapping(){
return mapping;
}
}
简单总结一下,tomcat负责创建socket服务端监听客户端的请求,为每个请求分配一个线程,并发的解析请求数据并传递给相应的servlet类处理。
servlet中可调用复杂的业务逻辑并通过response响应数据给客户端。
网友评论