【Tomcat】Tomcat的实现,tomcat内部是怎么实现的,它是怎么做到对Servlet请求的处理的。

这篇具有很好参考价值的文章主要介绍了【Tomcat】Tomcat的实现,tomcat内部是怎么实现的,它是怎么做到对Servlet请求的处理的。。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

让你想手写一个tomcat容器 能做到吗

Tomcat是Servlet容器,这句话真的是精髓,但有怎么理解呢?

Tomcat的代码实现,原理

尝试自己手写一份tomcat服务,类似tomcat的功能。
tomcat是servlet容器。所以我们自己写的tomcat也要满足这个功能,能接受处理servlet请求。
这一段的代码还是很经典的,让我们可以真正的明白“tomcat是Servlet容器”这样一句话。
Service 容器包括了 Engine容器
Engine 容器包括了Host容器
Host 容器包括了Context容器

可以想象,Service容器是在外层的容器,他还有一个对外的Connector 接口,提供对外的连接服务。

大致思路是这样的:
1. 先创建一个 Tomcat 对象
2. Tomcat 对象创建一个 Server对象
3. Server对象创建一个Service容器
4. Service容器内创建一个Engine容器
5. Engine容器内创建一个Host容器
6. Host容器内创建一个Context容器

这样相当于我们手写了一个tomcat服务,实现对servlet请求的接收,处理工作。文章来源地址https://www.toymoban.com/news/detail-488238.html

创建一个tomcat容器

package com.simulate.protocol.http;

import org.apache.catalina.*;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.startup.Tomcat;

public class HttpServer {

    public void start(String hostname, Integer port) {

        Tomcat tomcat = new Tomcat();

        Server server = tomcat.getServer();
        Service service = server.findService("Tomcat");

        Connector connector = new Connector();
        connector.setPort(port);

        Engine engine = new StandardEngine();
        engine.setDefaultHost(hostname);

        Host host = new StandardHost();
        host.setName(hostname);

        String contextPath = "";
        Context context = new StandardContext();
        context.setPath(contextPath);
        context.addLifecycleListener(new Tomcat.FixContextListener());

        host.addChild(context);
        engine.addChild(host);

        service.setContainer(engine);
        service.addConnector(connector);

        // 接收到的所有请求最终都会转发到 DispatcherServlet 上面去处理
        tomcat.addServlet(contextPath, "dispatcher", new DispatcherServlet());
        context.addServletMappingDecoded("/*", "dispatcher");


        try {
            tomcat.start();
            tomcat.getServer().await();
        } catch (LifecycleException e) {
            e.printStackTrace();
        }


    }
}

Servlet转发

package com.simulate.protocol.http;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class DispatcherServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        new HttpServerHandler().handler(req, resp);
    }
}

Servlet的处理工作

package com.simulate.protocol.http;

import com.alibaba.fastjson.JSONObject;
import com.simulate.framework.Invocation;
import com.simulate.provider.api.HelloService;
import com.simulate.provider.impl.HelloServiceImpl;
import org.apache.commons.io.IOUtils;
import com.simulate.provider.LocalRegister;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

public class HttpServerHandler {

    // FIXME 这里应该是 服务启动的时候,自动注入进去,而不是在这个类中才注入,如果其他地方有用到这些对象的话,已经晚了
    public HttpServerHandler (){
        LocalRegister.regist(HelloService.class.getName(), HelloServiceImpl.class);
    }


    public void handler(HttpServletRequest req, HttpServletResponse resp) {

        // 获取到Request 请求中的url参数信息,然后可以转发给具体的servlet对象,进行处理。这里只做转发的工作。
        // 这里可以做很多工作,比如访问数据库,数据写入文件等,而我这里做的是通过反射,创建对象,调用对象的方法。
        try {
            Invocation invocation = JSONObject.parseObject(req.getInputStream(), Invocation.class);
            var interfaceName = invocation.getInterfaceName();
            var implClass = LocalRegister.get(interfaceName);
            var method = implClass.getMethod(invocation.getMethodName(), invocation.getParamType());
            var result = (String) method.invoke(implClass.newInstance(), invocation.getParams());

            System.out.println("tomcat:" + result);
            IOUtils.write(result, resp.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }


    }
}

怎么启动这个tomcat server端呢?可以这样做:

package com.simulate.protocol.http;

import com.simulate.framework.URL;

public class HttpServerTest {

    public static void main(String[] args) {
        URL url = new URL("localhost", 9090);
        HttpServer httpServer = new HttpServer();
        httpServer.start(url.getHostname(), url.getPort());
        System.out.println("==========[httpserver start!]==============");
    }
}

上面的 tomcat启动完成后,就处于等待监听的状态,本地端口是9090的等待状态。等待什么?等待客户端的请求,如果有客户端请求 这个地址 http://localhost:9090/xxx 就会被这个tomcat容器捕捉到,进行后续的处理。

那我们继续看看客户端怎么发起请求呢?

我这里用的是jdk11, 在jdk11中,把HttpClient这个对象纳入进去了,而不需要像以前一样,还要依赖第三方的jar包。如果你用的不是jdk11,可以使用下面注释的代码,就是原生的HttpURLConnection 对象进行 http 连接,请求操作。

package com.simulate.protocol.http;

import com.alibaba.fastjson.JSONObject;
import com.simulate.framework.Invocation;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class HttpClient {

    public String send(String hostname, Integer port, Invocation invocation) {

        try {
            var request = HttpRequest.newBuilder()
                    .uri(new URI("http", null, hostname, port, "/", null, null))
                    .POST(HttpRequest.BodyPublishers.ofString(JSONObject.toJSONString(invocation)))
                    .build();
            var client = java.net.http.HttpClient.newHttpClient();

            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

            String result = response.body();

//            URL url = new URL("http", hostname, port, "/");
//            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
//
//            httpURLConnection.setRequestMethod("POST");
//            httpURLConnection.setDoOutput(true);
//
//            OutputStream outputStream = httpURLConnection.getOutputStream();
//            ObjectOutputStream oos = new ObjectOutputStream(outputStream);
//
//            oos.writeObject(invocation);
//            oos.flush();
//            oos.close();
//
//            InputStream inputStream = httpURLConnection.getInputStream();
//            String result = IOUtils.toString(inputStream);
            return result;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }

        return null;

    }
}

那这个客户端怎么使用呢?

package com.simulate.protocol.http;

import com.simulate.framework.Invocation;
import com.simulate.framework.URL;
import com.simulate.provider.api.HelloService;

public class HttpClientTest {

    public static void main(String[] args) {
        URL url = new URL("localhost", 9090);
        HttpClient httpClient = new HttpClient();
        String data = httpClient.send("localhost", 9090, new Invocation(HelloService.class.getName(), "sayHello",
                new Object[]{"World"}, new Class[]{String.class}));

        // LocalRegister.regist(HelloService.class.getName(), HelloServiceImpl.class);
        System.out.println("===========");
        System.out.println(data);
        System.out.println("===========");
    }
}

其他代码:

package com.simulate.framework;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.io.Serializable;

@Data
@AllArgsConstructor
public class Invocation implements Serializable {

    private String interfaceName;
    private String methodName;
    private Object[] params;
    private Class[] paramType;
}



package com.simulate.provider.api;

public interface HelloService {

    String sayHello(String userName);
}



package com.simulate.provider.impl;

import com.simulate.provider.api.HelloService;

public class HelloServiceImpl implements HelloService {

    @Override
    public String sayHello(String userName) {
        return "Hello: " + userName;
    }
}

先启动HttpServerTest中的main方法

在启动HttpClientTest 中的main方法, 就能看到结果了。

这样相当于我们手写了一个tomcat服务,实现对servlet请求的接收,处理工作。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion> 

    <groupId>com.simulate</groupId>
    <artifactId>simulate</artifactId>
    <version>1.0-SNAPSHOT</version>


    <dependencies>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.16.Final</version>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>9.0.12</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.4</version>
            <scope>provided</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.51</version>
        </dependency>

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-client</artifactId>
            <version>4.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.13</version>
        </dependency>
    </dependencies>
</project>

到了这里,关于【Tomcat】Tomcat的实现,tomcat内部是怎么实现的,它是怎么做到对Servlet请求的处理的。的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 使用Servlet实现表白墙网站(前后端互联)小项目,Mac的M1(没有setting)在哪里找到Setting页面,下载smart tomcat及smart tomcat的配置。

    首先我认为,最清楚的就是了解了前后端进行的初步作用,前端是布置画面,制作用户的交互,后端相当于,保存你的每一步操作,每一步进行的操作,历史搜索记录,保存一些数据,以及和前端相互连接,当然这个也是针对这个小项目,要是更大的则也需要更加细化。 目录

    2024年02月08日
    浏览(46)
  • 通过Tomcat / Small Tomcat,如何部署Servlet?(超详细)

    目录 基于Tomcat对Servlet进行部署 一、创建项目 二、引入Servlet依赖 三、构建目录结构 四、编写代码 五、打包程序 六、部署程序 七、验证程序 基于Smart Tomcat对Servlet进行部署 第一步:下载Smart Tomcat插件 第二步:进行相关配置   第三步:运行配置  第四步:确认部署是否成功

    2024年01月18日
    浏览(39)
  • Tomcat 学习之 Servlet

    目录 1 Servlet 介绍 2 创建一个 Servlet 3 web.xml 介绍(不涉及 filter 和 listener 标签) 3.1 display-name 3.2 welcome-file-list 3.3 servlet 3.4 session-config 3.5 error-page 4 Tomcat 如何根据 URL 定位到 Servlet 5 执行 Servlet 5.1 Servlet 接口(规范) 5.2 Servlet 生命周期 5.3 执行 init 初始化方法 5.4 执行 service

    2024年02月22日
    浏览(43)
  • Tomcat和Servlet

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 提示:这里可以添加本文要记录的大概内容: 因为现在都用spring框架了,所以本文就简单介绍一下Tomcat和Servlet 提示:以下是本篇文章正文内容,下面案例可供参考 官网地址 我下载的时8版本,其实应用

    2024年02月03日
    浏览(42)
  • Tomcat+Http+Servlet

    JAVAWeb技术栈 BS架构: B/S架构(Browser/Server架构)是一种常见的软件架构模式,用于构建Web应用程序。在B/S架构中,浏览器(Browser)作为客户端,通过网络协议(通常是HTTP)与服务器(Server)进行通信,而服务器负责处理客户端的请求并生成响应。 客户端(浏览器):客户端

    2024年02月12日
    浏览(62)
  • [JAVAee]Tomcat - Servlet

    目录 Tomcat Servlet的工作 创建Servlet ①项目 ②依赖  ③目录  ④代码 ⑤打包 ⑥部署 ⑦验证 Servlet的运行原理 Servlet API HttpServlet 方法 处理Get/POST请求  HttpServletRequest 方法 获取请求中的信息  获取GET请求中的参数 获取POST请求中的参数 FORM表格形式 JSON形式 方法一: 方法二: Http

    2024年02月12日
    浏览(42)
  • tomcat与servlet

    目录 一、Http服务器 二、tomcat 1、概念 2、tomcat解压缩文件 (1)bin文件夹 (2)conf文件夹 (3)logs (4)webapps 3、借助tomcat服务器访问网页 三、servlet 1、概念 2、servlet实现在浏览器上显示hello (1)创建Maven项目 (2)引入依赖 (3)创建目录 (4)编写代码 (5)打包程序 (

    2024年01月20日
    浏览(49)
  • 【Servlet学习二】Servlet原理(Tomcat)&& ServletAPI

    目录 🌟一、Servlet运行原理 🌈1、Servlet的执行原理(重点) 🌈2、Tomcat伪代码的简单理解 2.1  Tomcat初始化流程 2.2  Tomcat处理请求流程 2.3 Servlet 的 service 方法的实现 🌟二、Servlet API 详解 1、HttpServlet 2、HttpServletRequest 3、HttpServletResponse 面试题:请求转发与请求重定向的区别?

    2024年02月12日
    浏览(39)
  • Javaweb基础-tomcat,servlet

    properties配置文件: 由键值对组成 键和值之间的符号是等号 每一行都必须顶格写,前面不能有空格之类的其他符号 xml配置文件:(xml语法=HTML语法+HTML约束)xml约束-DTD /  Schema DOM4J进行XML解析:(jar包 dom4j.jar ) web项目标准文件结构(Tomcat/webapps下): app 本应用根目录 stat

    2024年02月19日
    浏览(50)
  • 基于Java+MySQL+Tomcat+Servlet+Maven+JQuery+jackson+开源Markdown编辑器实现前后端分离个人博客系统

    目录 项目简介 模块实现 设计实现数据库相关代码 博客列表页 博客详情页 注册页 登录页 检测登录状态 显示用户信息 退出登录 发布博客 删除博客 统计博客数量 效果展示 部分代码展示 小结:     项目中使用了Java ,MySQL ,Tomcat ,Servlet ,Maven ,JQuery ,jackson,开源MarkDo

    2024年02月02日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包