[JavaWeb]模拟一个简易的Tomcat服务(Servlet注解)
大家天天开心!
文章目录
- 前言
- 一、对我的这个Tomcat简介:
- 二、完整详细代码:
- 下面是代码的详细解释:
- 总结
前言
我们在最开始学JavaWeb的时候,是需要配置web.xml文件,来找到Servlet相应的服务,然后还有以注解的方式,这里要清楚注解的方式是@interface.然后我想带着大家了解一下Tomcat到底替我们干了多少事,我们就知道Tomcat有多牛逼了。
提示:以下是本篇文章正文内容,下面案例可供参考
一、对我的这个Tomcat简介:
该Tomcat(或其他Servlet容器)是通过反射获取@WebServlet
注解信息并实例化Servlet的。
对于这个写的Tomcat服务所完成的:
-
反射运用正确:你使用
Class.forName()
加载类,并用getAnnotation(WebServlet.class)
获取注解对象,这是标准做法。 -
成功提取注解信息:你通过
annotation.urlPatterns()
拿到了配置的URL模式,这正是Servlet容器建立映射关系的关键。 -
实例化Servlet:使用
aClass.newInstance()
(注:较新JDK版本推荐使用getDeclaredConstructor().newInstance()
)创建了Servlet实例,模拟了容器初始化Servlet的过程。
二、完整详细代码:
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对象,得到AnnotationWebServlet 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实例,放入到hashmapObject instance = aClass.newInstance();System.out.println("instance= " + instance);//OkServlet//简单的模拟,没有深入.hm.put("OkServlet", instance);System.out.println(hm);}
}
你的代码 | 完整的 Tomcat |
---|---|
手动指定 | 自动扫描整个 classpath 或指定包下的所有类,寻找带有 |
使用 | 使用复杂的上下文和生命周期管理。 |
没有 HTTP 服务器功能,无法接收和处理实际请求。 | 包含一个 HTTP 服务器(基于 Socket),监听端口,解析 HTTP 协议,并将请求路由到对应的 Servlet。 |
实例化后直接放入 Map,没有初始化过程。 | 在 Servlet 实例化后,会回调其 |
没有请求处理和分发逻辑。 | 接收到 HTTP 请求后,根据 URL 查找映射到哪个 Servlet,然后调用该 Servlet 的 |
下面是代码的详细解释:
String classAllPath = "com.hspedu.servlet.annotation.OkServlet";
Class<?> aClass = Class.forName(classAllPath);
-
-
这行代码手动指定了要加载的 Servlet 类的全限定名。在实际的 Tomcat 中,这个过程是自动的。Tomcat 会扫描整个 Web 应用(如 WAR 包的
WEB-INF/classes
和WEB-INF/lib
中的 JAR 包),找到所有带有@WebServlet
注解的类。 -
Class.forName()
方法利用 Java 的反射机制,根据类名动态地加载这个类到 JVM 中,并返回它的Class
对象。这是所有后续操作的基础。
-
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"}, ...)
。
String[] strings = annotation.urlPatterns();
for (String url : strings) {System.out.println("url= " + url);
}
-
这是整个模拟的关键目的。从注解对象中,你可以调用其方法(如
urlPatterns()
)来获取配置的属性值。 -
Tomcat 在启动时就是这样做的:它读取所有 Servlet 类上的
@WebServlet
注解,建立了一个 URL 路径到 Servlet 类的映射表。
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
的形式,证明实例化成功了。
hm.put("OkServlet", instance);
System.out.println(hm);
-
这里用一个
HashMap
来模拟 Tomcat 内部用于管理 Servlet 实例的容器。 -
在真实的 Tomcat 中,维护了一个更为复杂但功能类似的结构,用来根据 URL 查找并获取对应的 Servlet 实例来处理请求。
总结
最核心的“发现”和“装载”机制:
-
发现 (Discovery):通过扫描或配置,找到所有需要管理的 Servlet 类。
-
解析 (Parsing):读取类上的元信息(这里是
@WebServlet
注解),特别是 URL 映射。 -
装载 (Loading & Instantiation):使用反射机制动态地创建这些 Servlet 的实例。
-
管理 (Management):将实例存储起来,建立 URL 到实例的映射关系,以备请求时调用。
如果要让这个模拟更接近真实的 Tomcat,接下来可以考虑:
-
实现一个简单的 HTTP 服务器:使用
ServerSocket
监听端口(如 8080)。 -
解析 HTTP 请求:从 Socket 连接中读取数据,解析出请求的 URL 路径。
-
实现请求分发:根据解析出的路径,从你的
HashMap
里找到对应的 Servlet 实例,然后通过反射调用其service
方法。