最近开课学到了Tomcat,对这个挺感兴趣,就跟着网上的教程自己实现了一遍。
众所周知,Tomcat是一个满足Servlet规范的容器,在Java Web的项目中大量使用;一般来说,我们需要将Web应用打包成War文件部署到Tomcat服务器中,通过制定映射关系来制定路径,指明被哪个方法处理。Tomcat对于实际的请求会做出以下的操作:
- 提供Socket服务,不过是支持HTTP的Socket
- 进行请求的下发
- 将请求与响应封装成response和request
下面上代码:
一.封装请求对象
import java.io.IOException;
import java.io.InputStream;
//封装请求对象,通过输入流,对 HTTP 协议进行解析,拿到 HTTP 请求头的方法以及 URl
public class MyRequest {
private String url;
private String method;
public MyRequest(InputStream inputStream) throws IOException {
String httpRequest = " ";
byte[] httpRequestBytes = new byte[1024];
int length;
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];
}
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;
}
}
//通过Socket中的输入输出流,进行对网址的解析,分别将url和method进行分离。
二.封装响应对象
import java.io.IOException;
import java.io.OutputStream;
//封装响应对象,基于HTTP协议的格式进行输出
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("<html><body>")
.append(content)
.append("<body><html>");
outputStream.write(httpResponse.toString().getBytes());
outputStream.close();
}
}
//基于HTTP协议格式进行写入操作
三.Servlet请求处理基类
import java.io.IOException;
public class MyServlet {
public void doGet(MyRequest myRequest,MyResponse myResponse){
try{
myResponse.write(" get Hello World");
}catch (IOException e){
e.printStackTrace();
}
}
public void doPost(MyRequest myRequest,MyResponse myResponse){
try{
myResponse.write(" post Hello World");
}catch (IOException e){
e.printStackTrace();
}
}
public void service(MyRequest myRequest,MyResponse myResponse){
if(myRequest.getMethod().equalsIgnoreCase("post")){
doPost(myRequest,myResponse);
}else if(myRequest.getMethod().equalsIgnoreCase("get")){
doGet(myRequest,myResponse);
}
}
}
//Tomcat提供doPost(),doGet(),service()方法
四.Servletp配置
public class ServletMapping {
private String servletName;
private String url;
private String clazz;
public ServletMapping(String servletName,String url,String clazz){
this.servletName = servletName;
this.url = url;
this.clazz = clazz;
}
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 getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
}
import java.util.ArrayList;
import java.util.List;
public class ServletMappingConfig {
public static List<ServletMapping> servletMappingList = new ArrayList<>();
static {
servletMappingList.add(new ServletMapping("Hello World","/world","MyServlet"));
}
}
//通过设置映射关系对方法进行map映射调用。
五.启动类
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
//tomcat服务的启动类
public class MyTomcat {
private int port ;
private Map<String,String> urlServletMap = new HashMap<>();
public static void main(String[] args) {
new MyTomcat(8080).start();
}
public MyTomcat(int port){
this.port = port;
}
public void start(){
//初始化 URL与对应处理的servlet的关系
initServletMapping();
ServerSocket serverSocket = null;
try{
serverSocket = new ServerSocket(port);
System.out.println("MyTomcat is start on " + port);
while(true){
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 与对应servler的关系
private void initServletMapping(){
for(ServletMapping servletMapping : ServletMappingConfig.servletMappingList){
urlServletMap.put(servletMapping.getUrl(),servletMapping.getClazz());
}
}
//请求分发
private void dispatch(MyRequest myRequest,MyResponse myResponse){
String clazz = urlServletMap.get(myRequest.getUrl());
//利用反射实例化具体的servlet处理请求
try{
Class<MyServlet> myServletClass =(Class<MyServlet>) Class.forName(clazz);
MyServlet myServlet = myServletClass.newInstance();
myServlet.service(myRequest,myResponse);
}catch (ClassNotFoundException e){
e.printStackTrace();
}catch (InstantiationException e){
e.printStackTrace();
}catch (IllegalAccessException e){
e.printStackTrace();
}
}
}
//解析HTTP协议,封装请求/响应对象,使用反射的实例化进行映射。