[JavaWeb]模拟一个简易的Tomcat服务(Servlet注解)

大家天天开心!

文章目录

  • 前言
  • 一、对我的这个Tomcat简介:
  • 、完整详细代码:
    • 下面是代码的详细解释:
  • 总结

前言

我们在最开始学JavaWeb的时候,是需要配置web.xml文件,来找到Servlet相应的服务,然后还有以注解的方式,这里要清楚注解的方式是@interface.然后我想带着大家了解一下Tomcat到底替我们干了多少事,我们就知道Tomcat有多牛逼了。


提示:以下是本篇文章正文内容,下面案例可供参考

一、对我的这个Tomcat简介:

该Tomcat(或其他Servlet容器)是通过反射获取@WebServlet注解信息并实例化Servlet的。

对于这个写的Tomcat服务所完成的:

  1. ​​反射运用正确​​:你使用 Class.forName()加载类,并用 getAnnotation(WebServlet.class)获取注解对象,这是标准做法。

  2. ​​成功提取注解信息​​:你通过 annotation.urlPatterns()拿到了配置的URL模式,这正是Servlet容器建立映射关系的关键。

  3. ​​实例化Servlet​​:使用 aClass.newInstance()(注:较新JDK版本推荐使用 getDeclaredConstructor().newInstance())创建了Servlet实例,模拟了容器初始化Servlet的过程。

二、完整详细代码:

java 复制代码
package com.hspedu.servlet.annotation;

import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsServer;

import javax.servlet.annotation.WebServlet;
import java.util.HashMap;

/**
 * @author 韩顺平
 * @version 1.0
 * 模拟一把Tomcat是如果通过 @WebServlet(urlPatterns = {"/ok1", "/ok2"})
 * 来装载一个Servlet的
 *
 * 说明:这代码主要的目的,就是打破 注解的神秘感
 */
public class TestAnnotationServlet {

    private static final HashMap<String, Object> hm = new HashMap<>();

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {

        //1. 首先要得到扫描的包 路径 io, 进而得到类的全路径
        String classAllPath = "com.hspedu.servlet.annotation.OkServlet";
        //2. 得到 OkServlet的Class对象
        Class<?> aClass = Class.forName(classAllPath);
        //3. 通过class对象,得到Annotation
        WebServlet annotation = aClass.getAnnotation(WebServlet.class);
        System.out.println(annotation);
        String[] strings = annotation.urlPatterns();
        for (String url : strings) {
            System.out.println("url= " + url);
        }

        //如果匹配url,如果是第一次,tomcat就会创建一个OkServlet实例,放入到hashmap
        Object instance = aClass.newInstance();
        System.out.println("instance= " + instance);//OkServlet

        //简单的模拟,没有深入.
        hm.put("OkServlet", instance);

        System.out.println(hm);

    }
}
你的代码 完整的 Tomcat
手动指定 OkServlet的全类名进行加载。 ​自动扫描​ ​整个 classpath 或指定包下的所有类,寻找带有 @WebServlet等注解的类。
使用 HashMap<String, Object>存储实例。 使用复杂的​​上下文和生命周期管理​ ​。HashMap的 value 通常是 Servlet 实例,key 则是其配置名或 URL 模式。
没有 HTTP 服务器功能,无法接收和处理实际请求。 包含一个 ​​HTTP 服务器​​(基于 Socket),监听端口,解析 HTTP 协议,并将请求路由到对应的 Servlet。
实例化后直接放入 Map,没有初始化过程。 在 Servlet 实例化后,会​​回调其 init(ServletConfig)方法​​,完成初始化。
没有请求处理和分发逻辑。 接收到 HTTP 请求后,根据 URL ​​查找映射到哪个 Servlet​ ​,然后调用该 Servlet 的 ​service方法​ ​,进而分发到 doGetdoPost等方法。
下面是代码的详细解释:
java 复制代码
String classAllPath = "com.hspedu.servlet.annotation.OkServlet";
Class<?> aClass = Class.forName(classAllPath);
    • 这行代码手动指定了要加载的 Servlet 类的全限定名。​​在实际的 Tomcat 中,这个过程是自动的​ ​。Tomcat 会扫描整个 Web 应用(如 WAR 包的 WEB-INF/classesWEB-INF/lib中的 JAR 包),找到所有带有 @WebServlet注解的类。

    • Class.forName()方法利用 ​​Java 的反射机制​ ​,根据类名动态地加载这个类到 JVM 中,并返回它的 Class对象。这是所有后续操作的基础。

java 复制代码
WebServlet annotation = aClass.getAnnotation(WebServlet.class);
System.out.println(annotation);
  • 通过 Class对象的 getAnnotation()方法,并传入注解的类型(WebServlet.class),可以​​获取到该类上的特定注解对象​​。

  • 如果这个类上确实标注了 @WebServlet,那么这里返回的就是一个包含了所有注解属性值的 WebServlet注解实例。如果不存在,则返回 null

  • 打印 annotation可以看到注解的具体信息,如 @javax.servlet.annotation.WebServlet(urlPatterns={"/ok1", "/ok2"}, ...)

java 复制代码
String[] strings = annotation.urlPatterns();
for (String url : strings) {
    System.out.println("url= " + url);
}
  • 这是整个模拟的​​关键目的​ ​。从注解对象中,你可以调用其方法(如 urlPatterns())来获取配置的属性值。

  • ​Tomcat 在启动时就是这样做的​ ​:它读取所有 Servlet 类上的 @WebServlet注解,​​建立了一个 URL 路径到 Servlet 类的映射表​​。

java 复制代码
Object instance = aClass.newInstance(); // 注意:较新JDK推荐getDeclaredConstructor().newInstance()
System.out.println("instance= " + instance);
  • 通过 Class对象的 newInstance()方法(​​注:较新版本的 JDK 已弃用此方法,推荐使用 getDeclaredConstructor().newInstance() ​),可以​​创建该 Servlet 类的一个新实例​​。

  • ​Tomcat 正是在这个时候创建 Servlet 实例的​​(通常在容器启动或首次请求时,取决于配置)。

  • 打印出的 instance应该是类似 com.hspedu.servlet.annotation.OkServlet@xxx的形式,证明实例化成功了。

java 复制代码
hm.put("OkServlet", instance);
System.out.println(hm);
  • 这里用一个 HashMap来模拟 Tomcat 内部用于​​管理 Servlet 实例的容器​​。

  • 在真实的 Tomcat 中,维护了一个更为复杂但功能类似的结构,用来根据 URL 查找并获取对应的 Servlet 实例来处理请求。


总结

​最核心的"发现"和"装载"机制​​:

  1. ​发现 (Discovery)​​:通过扫描或配置,找到所有需要管理的 Servlet 类。

  2. ​解析 (Parsing)​ ​:读取类上的元信息(这里是 @WebServlet注解),特别是 URL 映射。

  3. ​装载 (Loading & Instantiation)​ ​:使用​​反射​​机制动态地创建这些 Servlet 的实例。

  4. ​管理 (Management)​​:将实例存储起来,建立 URL 到实例的映射关系,以备请求时调用。

​如果要让这个模拟更接近真实的 Tomcat,接下来可以考虑:​

  • ​实现一个简单的 HTTP 服务器​ ​:使用 ServerSocket监听端口(如 8080)。

  • ​解析 HTTP 请求​ ​:从 Socket 连接中读取数据,解析出请求的 ​​URL 路径​​。

  • ​实现请求分发​ ​:根据解析出的路径,从你的 HashMap里找到对应的 Servlet 实例,然后​​通过反射调用其 service方法​​。

相关推荐
华仔啊3 小时前
SpringBoot 中 6 种数据脱敏方案,第 5 种太强了,支持深度递归!
java·后端
异常驯兽师3 小时前
Spring 中处理 HTTP 请求参数注解全解析
java·spring·http
连合机器人4 小时前
晨曦中的守望者:当科技为景区赋予温度
java·前端·科技
AD钙奶-lalala4 小时前
idea新建的项目new 没有java class选项
java·ide·intellij-idea
sheji34164 小时前
【开题答辩全过程】以 12306候补购票服务系统为例,包含答辩的问题和答案
java·eclipse
勇敢牛牛_5 小时前
使用Rust实现服务配置/注册中心
开发语言·后端·rust·注册中心·配置中心
deepwater_zone5 小时前
Go语言核心技术
后端·golang
hzzzzzo05 小时前
微服务网关全解析:从入门到实践
java·开发语言·微服务
纪莫5 小时前
技术面:Spring (bean的生命周期、创建方式、注入方式、作用域)
java·spring·java面试⑧股