【JavaWeb】Tomcat底层机制和Servlet运行原理

简介: 网络通信:Tomcat使用Java的Socket API来监听特定的端口(通常是8080),接收来自客户端的HTTP请求。线程池:Tomcat使用线程池来处理并发的请求。当有新的请求到达时,Tomcat会从线程池中获取一个空闲线程来处理该请求,这样可以提高处理效率。生命周期管理:Tomcat负责管理Servlet和其他Web组件的生命周期,包括初始化、请求处理和销毁等阶段。(init(), run())

一. 一图明理


二. 概念

Tomcat是一个开源的Java Web服务器,它是基于Java Servlet和JavaServer Pages(JSP)技术的。下面是关于Tomcat底层机制和Servlet运行原理的简要说明:


Tomcat底层机制:


网络通信:Tomcat使用Java的Socket API来监听特定的端口(通常是8080),接收来自客户端的HTTP请求。

线程池:Tomcat使用线程池来处理并发的请求。当有新的请求到达时,Tomcat会从线程池中获取一个空闲线程来处理该请求,这样可以提高处理效率。

生命周期管理:Tomcat负责管理Servlet和其他Web组件的生命周期,包括初始化、请求处理和销毁等阶段。(init(), run())

请求处理管道:Tomcat通过请求处理管道来处理HTTP请求。请求经过一系列的处理器,如身份验证、日志记录和安全检查等,最终被交给适当的Servlet进行处理。(handle())

连接池:Tomcat使用连接池来管理与数据库的连接。这样可以提高性能,并避免频繁地创建和销毁数据库连接。(handle())

Servlet运行原理:


Servlet容器:Tomcat是一个Servlet容器,它负责加载、初始化和管理Servlet。当Tomcat启动时,它会读取配置文件(如web.xml)来确定需要加载的Servlet类。

生命周期:每个Servlet都有自己的生命周期,包括初始化、请求处理和销毁等阶段。Tomcat会在适当的时间调用Servlet的生命周期方法(如init()、service()和destroy())。

请求处理:当Tomcat接收到HTTP请求时,它会根据请求的URL找到对应的Servlet,并将请求转发给该Servlet进行处理。Servlet通过HttpServletRequest对象获取请求的信息,并通过HttpServletResponse对象发送响应给客户端。

多线程处理:Tomcat使用多线程来处理并发请求。每个请求都被分配给一个独立的线程进行处理,这样可以同时处理多个请求,提高服务器的性能。

三. 容器的理解

在tomcat底层实现中, servlet作为容器, 实现可以理解为HashMap, 键是servlet-name值是servlet-class, 而HashMap就是一个容器, 从容器中得到一个servlet实例, 对其进行初始化, 供web使用, 调用其中的service()方法, service()方法对HTTP请求的method进行判断, 对每个相应的method都有相应的do方法, 可以使用.


四. 案例



不用tomcat以及servlet实现


五. 代码分析和代码实现






LxbRequestHandle类

package com.lxb.tomcat.handle;
//-*- code = utf-8 -*-
//@Time : 2023-07-20 13:22:00
//@Authors : 罗雄波
//@File : LxbRequestHandle.java
//@Software : IntelliJ IDEA
import com.lxb.tomcat.LxbTomcatV3;
import com.lxb.tomcat.http.LxbHttpRequest;
import com.lxb.tomcat.http.LxbHttpResponse;
import com.lxb.tomcat.servlet.LxbHttpServlet;
import com.lxb.tomcat.utils.WebUtils;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class LxbRequestHandle implements Runnable{
    private Socket accept;
    public LxbRequestHandle(Socket socket) {
        this.accept = socket;
    }
    public void run() {
        try {
            LxbHttpRequest request = new LxbHttpRequest(accept);
            LxbHttpResponse response = new LxbHttpResponse(accept.getOutputStream());
            String uri = request.getUri();
            if(WebUtils.isHtml(uri)) {
                System.out.println(uri.substring(1));
                String resp = WebUtils.readFile(uri.substring(1));
                String responseInfo = LxbHttpResponse.respHeader + resp;
                OutputStream outputStream = response.getOutputStream();
                outputStream.write(responseInfo.getBytes());
                outputStream.flush();
                outputStream.close();
                accept.close();
                return;
            }
            String servletName = LxbTomcatV3.servletMapping.get(uri);
            if(servletName == null) {
                servletName = "";
            }
            LxbHttpServlet servlet = LxbTomcatV3.servlet.get(servletName);
            if(servlet != null) {
                servlet.service(request, response);
            } else {
                String resp = LxbHttpResponse.respHeader + "<h1>404 not found!!!</h>";
                OutputStream responseOutputStream = response.getOutputStream();
                responseOutputStream.write(resp.getBytes());
                responseOutputStream.flush();
                responseOutputStream.close();
            }
            accept.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (accept != null) {
                try {
                    accept.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


LxbHttpRequest和LxbHttpResponse

package com.lxb.tomcat.http;
//-*- code = utf-8 -*-
//@Time : 2023-07-20 14:59:24
//@Authors : 罗雄波
//@File : LxbHttpRequest.java
//@Software : IntelliJ IDEA
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.HashMap;
public class LxbHttpRequest {
    private Socket socket;
    private String method;
    private String uri;
    private HashMap<String, String> parameterMapping = new HashMap<String, String>();
    public LxbHttpRequest(Socket socket) {
        this.socket = socket;
        try {
            ParseProcess();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public void ParseProcess() throws Exception {
        BufferedReader reader =
                new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8"));
        String temp;
        temp = reader.readLine();
//        GET /cal.html HTTP/1.1
        String[] request = temp.split(" ");
        method = request[0];
        int index = request[1].indexOf("?");
        if (index == -1) {
            uri = request[1];
        } else {
            uri = request[1].substring(0, index);
            String parameterPair = request[1].substring(index + 1);
            String[] parameters = parameterPair.split("&");
            if (parameters[0] != null && !parameters[0].equals("")) {
                for (String parameter : parameters) {
                    String[] split = parameter.split("=");
                    if(split.length == 2) {
                        parameterMapping.put(split[0], split[1]);
                    }
                }
            }
        }
    }
    public String getMethod() {
        return method;
    }
    public String getUri() {
        return uri;
    }
    public String getParameter(String key) {
        if(parameterMapping.get(key) != null) {
            return parameterMapping.get(key);
        } else {
            return "";
        }
    }
    @Override
    public String toString() {
        return "LxbHttpRequest" +
                "{ method = " + method +
                ", uri = " +  uri +
                ", parameter = " + parameterMapping +
                "}";
    }
}



package com.lxb.tomcat.http;

package com.lxb.tomcat.http;
//-*- code = utf-8 -*-
//@Time : 2023-07-20 15:49:29
//@Authors : 罗雄波
//@File : LxbHttpResponse.java
//@Software : IntelliJ IDEA
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class LxbHttpResponse {
    private OutputStream outputStream = null;
    public static final String respHeader = "HTTP/1.1 200 OK\r\n" +
            "Content-Type: text/html;charset=utf-8\r\n\r\n";
    public LxbHttpResponse(OutputStream outputStream) {
        this.outputStream = outputStream;
    }
    public OutputStream getOutputStream() {
        return outputStream;
    }
}



LxbTomcat

package com.lxb.tomcat;
//-*- code = utf-8 -*-
//@Time : 2023-07-20 15:37:29
//@Authors : 罗雄波
//@File : LxbTomcatV3.java
//@Software : IntelliJ IDEA
import com.lxb.tomcat.handle.LxbRequestHandle;
import com.lxb.tomcat.servlet.LxbHttpServlet;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
public class LxbTomcatV3 {
    public static ConcurrentHashMap<String, LxbHttpServlet> servlet =
            new ConcurrentHashMap<String, LxbHttpServlet>();
    public static ConcurrentHashMap<String, String> servletMapping =
            new ConcurrentHashMap<String, String>();
    public static void main(String[] args) throws Exception {
        LxbTomcatV3 lxbTomcatV3 = new LxbTomcatV3();
        lxbTomcatV3.Init();
        lxbTomcatV3.run();
    }
    public void run() {
        try {
            ServerSocket socket = new ServerSocket(8080);
            while (!socket.isClosed()) {
                Socket accept = socket.accept();
                LxbRequestHandle requestHandle = new LxbRequestHandle(accept);
                new Thread(requestHandle).start();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    @Test
    public void Init() {
        String path = LxbTomcatV3.class.getResource("/").getPath();
//        System.out.println(path);
//   该类的路径 /D:/NewExecllction/exicese%20code/lxb-tomcat/target/classes/com/lxb/tomcat/
//   根路径    /D:/NewExecllction/exicese%20code/lxb-tomcat/target/classes/
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(new File(path + "web.xml"));
//            System.out.println(document);
            Element rootElement = document.getRootElement();
            List<Element> elements = rootElement.elements();
            for (Element element : elements) {
                if ("servlet".equalsIgnoreCase(element.getName())) {
                    Element servletName = element.element("servlet-name");
                    Element servletClass = element.element("servlet-class");
                    servlet.put(servletName.getText(), (LxbHttpServlet) Class.forName(servletClass.getText().trim()).newInstance());
                } else if ("servlet-mapping".equalsIgnoreCase(element.getName())) {
                    Element servletName = element.element("servlet-name");
                    Element servletUrl = element.element("url-pattern");
                    servletMapping.put(servletUrl.getText(), servletName.getText());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(servlet);
        System.out.println(servletMapping);
    }
    @Test
    public void test() {
        String path = LxbTomcatV3.class.getResource("/").getPath();
        System.out.println(path + "web.xml");
    }
}


WebUtils

package com.lxb.tomcat.utils;
//-*- code = utf-8 -*-
//@Time : 2023-07-19 16:00:33
//@Authors : 罗雄波
//@File : WebUtils.java
//@Software : IntelliJ IDEA
import org.junit.Test;
import java.io.*;
public class WebUtils {
    public static int parseInt(String strNum, int defaultVal) {
        try {
            return Integer.parseInt(strNum);
        } catch (NumberFormatException e) {
            System.out.println(strNum + "数字格式异常, 无法包装");
        }
        return defaultVal;
    }
    public static boolean isHtml(String uri) {
        return uri.endsWith(".html");
    }
    public static String readFile(String filename) {
        String path = com.lxb.tomcat.utils.WebUtils.class.getResource("/").getPath();
        StringBuilder stringBuffer = new StringBuilder();
        try {
            System.out.println(path + filename);
            BufferedReader bufferedReader = new BufferedReader(new FileReader(path + filename));
            String buffer = null;
            while ((buffer = bufferedReader.readLine()) != null && !buffer.equals("")) {
                stringBuffer.append(buffer);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return stringBuffer.toString();
    }
}

   


LxbCalServlet

package com.lxb.tomcat.servlet;
//-*- code = utf-8 -*-
//@Time : 2023-07-20 16:14:24
//@Authors : 罗雄波
//@File : LxbCalServlet.java
//@Software : IntelliJ IDEA
import com.lxb.tomcat.http.LxbHttpRequest;
import com.lxb.tomcat.http.LxbHttpResponse;
import com.lxb.tomcat.utils.WebUtils;
import java.io.IOException;
import java.io.OutputStream;
public class LxbCalServlet extends LxbHttpServlet {
    @Override
    public void doGet(LxbHttpRequest request, LxbHttpResponse response) {
        doPost(request, response);
    }
    @Override
    public void doPost(LxbHttpRequest request, LxbHttpResponse response) {
        int num1 = WebUtils.parseInt(request.getParameter("num1"), 0);
        int num2 = WebUtils.parseInt(request.getParameter("num2"), 0);
        int result = num1 + num2;
        OutputStream outputStream = response.getOutputStream();
        String resp = LxbHttpResponse.respHeader + "<h1>求和: " + num1 + "+" + num2 + " = " + result + "</h>";
        try {
            outputStream.write(resp.getBytes());
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public void init() throws Exception {
    }
    public void destroy() {
    }
}


LxbServlet

package com.lxb.tomcat.servlet;
//-*- code = utf-8 -*-
//@Time : 2023-07-20 16:09:43
//@Authors : 罗雄波
//@File : LxbServlet.java
//@Software : IntelliJ IDEA
import com.lxb.tomcat.http.LxbHttpRequest;
import com.lxb.tomcat.http.LxbHttpResponse;
import java.io.IOException;
public interface LxbServlet {
    void init() throws Exception;
    void service(LxbHttpRequest request, LxbHttpResponse response) throws IOException;
    void destroy();
}

LxbHttpServlet

package com.lxb.tomcat.servlet;
//-*- code = utf-8 -*-
//@Time : 2023-07-20 16:11:02
//@Authors : 罗雄波
//@File : lxbHttpServlet.java
//@Software : IntelliJ IDEA
import com.lxb.tomcat.http.LxbHttpRequest;
import com.lxb.tomcat.http.LxbHttpResponse;
import java.io.IOException;
public abstract class LxbHttpServlet implements LxbServlet{
    public void service(LxbHttpRequest request, LxbHttpResponse response) throws IOException {
        if(request.getMethod().equals("GET")) {
            this.doGet(request, response);
        } else if(request.getMethod().equals("POST")) {
            this.doPost(request, response);
        }
    }
    public void doGet(LxbHttpRequest request, LxbHttpResponse response) {
    }
    public void doPost(LxbHttpRequest request, LxbHttpResponse response) {
    }
}


六. 注意

相关文章
|
1月前
|
网络协议 Java 应用服务中间件
深入浅出Tomcat网络通信的高并发处理机制
【10月更文挑战第3天】本文详细解析了Tomcat在处理高并发网络请求时的机制,重点关注了其三种不同的IO模型:NioEndPoint、Nio2EndPoint 和 AprEndPoint。NioEndPoint 采用多路复用模型,通过 Acceptor 接收连接、Poller 监听事件及 Executor 处理请求;Nio2EndPoint 则使用 AIO 异步模型,通过回调函数处理连接和数据就绪事件;AprEndPoint 通过 JNI 调用本地库实现高性能,但已在 Tomcat 10 中弃用
深入浅出Tomcat网络通信的高并发处理机制
|
1月前
|
前端开发 Java 应用服务中间件
21张图解析Tomcat运行原理与架构全貌
【10月更文挑战第2天】本文通过21张图详细解析了Tomcat的运行原理与架构。Tomcat作为Java Web开发中最流行的Web服务器之一,其架构设计精妙。文章首先介绍了Tomcat的基本组件:Connector(连接器)负责网络通信,Container(容器)处理业务逻辑。连接器内部包括EndPoint、Processor和Adapter等组件,分别处理通信、协议解析和请求封装。容器采用多级结构(Engine、Host、Context、Wrapper),并通过Mapper组件进行请求路由。文章还探讨了Tomcat的生命周期管理、启动与停止机制,并通过源码分析展示了请求处理流程。
|
2月前
|
Java 应用服务中间件 Maven
JavaWeb基础5——HTTP,Tomcat&Servlet
JavaWeb技术栈、HTTP、get和post区别、响应状态码、请求响应格数据式、IDEA使用Tomcat、报错解决、Servlet的体系结构、IDEA使用模板创建Servlet
JavaWeb基础5——HTTP,Tomcat&Servlet
|
2月前
|
设计模式 人工智能 安全
【Tomcat源码分析】生命周期机制 Lifecycle
Tomcat内部通过各种组件协同工作,构建了一个复杂的Web服务器架构。其中,`Lifecycle`机制作为核心,管理组件从创建到销毁的整个生命周期。本文详细解析了Lifecycle的工作原理及其方法,如初始化、启动、停止和销毁等关键步骤,并展示了LifecycleBase类如何通过状态机和模板模式实现这一过程。通过深入理解Lifecycle,我们可以更好地掌握组件生命周期管理,提升系统设计能力。欢迎关注【码上遇见你】获取更多信息,或搜索【AI贝塔】体验免费的Chat GPT。希望本章内容对你有所帮助。
|
3月前
|
缓存 前端开发 Java
【Azure 应用服务】App Service 使用Tomcat运行Java应用,如何设置前端网页缓存的相应参数呢(-Xms512m -Xmx1204m)?
【Azure 应用服务】App Service 使用Tomcat运行Java应用,如何设置前端网页缓存的相应参数呢(-Xms512m -Xmx1204m)?
|
4月前
|
弹性计算 运维 应用服务中间件
容器的优势,在Docker中运行Tomcat
摘要:了解Docker与虚拟机的区别:虚拟机使用Hypervisor创建完整操作系统,而容器通过namespace和cgroup实现轻量级隔离,共享主机内核。Docker启动快、资源利用率高,适合快速部署和跨平台移植。但安全性相对较低。示例介绍了如何通过Docker搜索、拉取官方Tomcat镜像并运行容器,最后验证Tomcat服务的正常运行。
|
4月前
|
应用服务中间件
修改Tomcat路径不变怎么办,点击clear清空,重新运行
修改Tomcat路径不变怎么办,点击clear清空,重新运行
|
4月前
|
Java 应用服务中间件 API
开发与运维机制问题之Tomcat要打破双亲委派机制如何解决
开发与运维机制问题之Tomcat要打破双亲委派机制如何解决
39 0
|
5月前
|
Java 应用服务中间件 程序员
JavaWeb基础第四章(SpringBootWeb工程,HTTP协议与Web服务器-Tomcat)
JavaWeb基础第四章(SpringBootWeb工程,HTTP协议与Web服务器-Tomcat)
|
3月前
|
缓存 安全 Java
Java服务器端技术:Servlet与JSP的集成与扩展
Java服务器端技术:Servlet与JSP的集成与扩展
33 3