当前位置: 首页 > news >正文

从0搭建Tomcat第二天:深入理解Servlet容器与反射机制

在上一篇博客中,我们从0开始搭建了一个简易的Tomcat服务器,并实现了基本的HTTP请求处理。今天,我们将继续深入探讨Tomcat的核心组件之一——Servlet容器,并介绍如何使用反射机制动态加载和管理Servlet。

1. Servlet容器的作用

Servlet容器是Tomcat的核心组件之一,负责管理Servlet的生命周期,并将HTTP请求分发给相应的Servlet进行处理。Servlet容器的主要功能包括:

  • 加载和初始化Servlet:在Tomcat启动时,Servlet容器会加载所有的Servlet类,并调用它们的init方法进行初始化。

  • 处理HTTP请求:当客户端发送HTTP请求时,Servlet容器会根据请求的URL找到对应的Servlet,并调用其service方法处理请求。

  • 销毁Servlet:在Tomcat关闭时,Servlet容器会调用Servlet的destroy方法进行资源释放。

2. 实现Servlet容器

2.1 使用Map管理Servlet

我们可以使用一个Map来管理Servlet对象,其中key是Servlet的访问路径,value是对应的Servlet对象。以下是一个简单的实现:

Map<String, Servlet> servletContainer = new HashMap<>();// 在Tomcat启动时加载Servlet
servletContainer.put("/login", new LoginServlet());
servletContainer.put("/show", new ShowServlet());// 根据请求路径获取相应的Servlet
Servlet servlet = servletContainer.get(request.getPath());
if (servlet != null) {servlet.service(request, response);
}

在这个实现中,我们手动将LoginServletShowServlet对象放入servletContainer中。然而,在实际的Tomcat中,Servlet的加载和管理是自动化的,通常通过反射机制来实现。

2.2 使用反射动态加载Servlet

为了动态加载Servlet,我们可以使用Java的反射机制。反射允许我们在运行时获取类的信息,并动态创建对象。以下是一个使用反射加载Servlet的示例:

package com.qcby.Util;import java.io.File;
import java.util.ArrayList;
import java.util.List;public class SearchClassUtil {public static List<String> classPaths = new ArrayList<String>();/*** 扫描指定包下的所有类,并获取全路径名*/public static List<String> searchClass() {String basePack = "com.qcby.webapps";String classPath = SearchClassUtil.class.getResource("/").getPath();basePack = basePack.replace(".", File.separator);String searchPath = classPath + basePack;doPath(new File(searchPath), classPath);return classPaths;}/*** 递归扫描目录,获取所有类的全路径名*/private static void doPath(File file, String classpath) {if (file.isDirectory()) {File[] files = file.listFiles();if (files != null) {for (File f1 : files) {doPath(f1, classpath);}}} else {if (file.getName().endsWith(".class")) {String path = file.getPath().replace(classpath.replace("/", "\\").replaceFirst("\\\\", ""), "").replace("\\", ".").replace(".class", "");classPaths.add(path);}}}/*** 根据全路径名加载类对象*/public static List<Class<?>> loadClasses(List<String> classPaths) {List<Class<?>> classes = new ArrayList<>();for (String className : classPaths) {try {Class<?> clazz = Class.forName(className);classes.add(clazz);} catch (ClassNotFoundException e) {System.err.println("无法加载类: " + className);e.printStackTrace();}}return classes;}/*** 获取类中的 @WebServlet 注解值*/public static void getWebServletAnnotation(List<Class<?>> classes) {for (Class<?> clazz : classes) {if (clazz.isAnnotationPresent(WebServlet.class)) {WebServlet webServletAnnotation = clazz.getAnnotation(WebServlet.class);String urlMapping = webServletAnnotation.urlMapping();System.out.println("类 " + clazz.getName() + " 的 @WebServlet 注解值: " + urlMapping);}}}public static void main(String[] args) {List<String> classPaths = searchClass();List<Class<?>> classes = loadClasses(classPaths);getWebServletAnnotation(classes);}
}

在这个代码中,我们使用SearchClassUtil类扫描指定包下的所有类,并加载带有@WebServlet注解的类。通过反射,我们可以动态获取这些类的注解信息,并根据注解中的urlMapping值将Servlet对象放入servletContainer中。

2.3 自定义@WebServlet注解

为了标识哪些类是Servlet,我们可以定义一个自定义注解@WebServlet

package com.qcby.Util;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface WebServlet {String urlMapping() default "";
}

在Servlet类中,我们可以使用这个注解来指定Servlet的访问路径:

package com.qcby.webapps.myweb;import com.qcby.Util.WebServlet;
import com.qcby.servlet.HttpServlet;
import com.qcby.servlet.req.HttpServletRequest;
import com.qcby.servlet.req.HttpServletResponse;@WebServlet(urlMapping = "/login")
public class LoginServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) {System.out.println("处理登录的GET请求");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) {System.out.println("处理登录的POST请求");}
}

3. 总结

通过本文,我们深入探讨了Tomcat的Servlet容器,并实现了动态加载和管理Servlet的功能。我们使用反射机制扫描指定包下的类,并根据自定义注解@WebServlet动态创建Servlet对象。这种方式使得Servlet的管理更加灵活和自动化。

在下一篇博客中,我们将继续探讨Tomcat的其他核心组件,如线程池、连接器等。如果你对Tomcat的更多细节感兴趣,欢迎继续关注。


参考文献:

  • Java Reflection Tutorial

  • Apache Tomcat Documentation

相关推荐:

  • 深入理解Java Web开发

  • Tomcat源码解析

相关文章:

从0搭建Tomcat第二天:深入理解Servlet容器与反射机制

在上一篇博客中&#xff0c;我们从0开始搭建了一个简易的Tomcat服务器&#xff0c;并实现了基本的HTTP请求处理。今天&#xff0c;我们将继续深入探讨Tomcat的核心组件之一——Servlet容器&#xff0c;并介绍如何使用反射机制动态加载和管理Servlet。 1. Servlet容器的作用 S…...

【Python】yield函数

【Python】yield函数 1. yield介绍2.yield基本用法3.yield高级用法3.1 yield send() 方法3.2 yield from方法3.3 yield 和yield from叠加处理复杂情况下的叠加 4.yield主要应用场景5.总结 python官方api地址 1. yield介绍 在Python中&#xff0c;yield关键字主要用于生成器函…...

Android13修改多媒体默认音量

干就完了! 设置音量为最大音量,修改如下: /framework/base/media/java/android/media/AudioSystem.java/** hide */public static int[] DEFAULT_STREAM_VOLUME new int[] {4, // STREAM_VOICE_CALL7, // STREAM_SYSTEM5, // STREAM_RING-5, // STREAM_MUSIC15, // STREAM…...

nginx+keepalived负载均衡及高可用

一、环境准备 主机名ip地址备注openEuler-1 192.168.121.11&#xff08;本机&#xff09; 192.168.131.11&#xff08;心跳连接&#xff09; nginx主负载均衡调度器openEuler-2 192.168.121.12&#xff08;本机&#xff09; 192.168.131.12&#xff08;心跳连接&#xff09; n…...

SP导入智能材质球

智能材质球路径 ...\Adobe Substance 3D Painter\resources\starter_assets\smart-materials 放入之后就会自动刷新...

Kotlin语言特性(一):空安全、扩展函数与协程

Kotlin语言特性&#xff08;一&#xff09;&#xff1a;空安全、扩展函数与协程 一、引言 Kotlin作为Android官方推荐的开发语言&#xff0c;相比Java具有诸多现代化特性。本文将重点介绍Kotlin三个最具特色的语言特性&#xff1a;空安全、扩展函数和协程&#xff0c;并结合A…...

Sqlserver安全篇之_启用TLS即配置SQL Server 数据库引擎以加密连接

官方文档 https://learn.microsoft.com/zh-cn/sql/database-engine/configure-windows/configure-sql-server-encryption?viewsql-server-ver16 https://learn.microsoft.com/zh-cn/sql/database-engine/configure-windows/manage-certificates?viewsql-server-ver15&pre…...

Python 爬虫 – BeautifulSoup

Python 爬虫&#xff08;Web Scraping&#xff09;是指通过编写 Python 程序从互联网上自动提取信息的过程。 爬虫的基本流程通常包括发送 HTTP 请求获取网页内容、解析网页并提取数据&#xff0c;然后存储数据。 Python 的丰富生态使其成为开发爬虫的热门语言&#xff0c;特…...

【星云 Orbit-STM32F4】07. 用判断数据尾来接收据的串口通用程序框架

【星云 Orbit-STM32F4】用判断数据尾来接收一串数据的串口通用程序框架 摘要 本文介绍了一种基于STM32F407微控制器的串口数据接收通用程序框架。该框架通过判断数据尾来实现一串数据的完整接收&#xff0c;适用于需要可靠数据传输的应用场景。本文从零开始&#xff0c;详细讲…...

授权与认证之jwt(一)创建Jwt工具类

JWT的Token要经过加密才能返回给客户端&#xff0c;包括客户端上传的Tokn,后端项目需要验证核 实。于是我们需要一个WT工具类&#xff0c;用来加密Token和验证Token的有效性。 一、导入依赖 <dependency><groupId>com.auth0</groupId><artifactId>jav…...

Kubernetes Service服务发现dns之CoreDNS

文章目录 背景什么是Service、服务发现、Endpoint什么是CoreDNSCoreDNS 的工作原理 常用命令coredns 运行状态根据服务名&#xff0c;判断某个服务dns解析是否正常 背景 Kubernetes 集群内部的服务发现是微服务架构的核心基础&#xff0c;而 DNS 服务则是实现这一机制的关键组…...

Spring Boot 测试:单元、集成与契约测试全解析

一、Spring Boot 分层测试策略 Spring Boot 应用采用经典的分层架构&#xff0c;不同层级的功能模块对应不同的测试策略&#xff0c;以确保代码质量和系统稳定性。 Spring Boot 分层架构&#xff1a; Spring Boot分层架构 A[客户端] -->|HTTP 请求| B[Controller 层] …...

用友NC系列漏洞检测利用工具

声明&#xff01;本文章所有的工具分享仅仅只是供大家学习交流为主&#xff0c;切勿用于非法用途&#xff0c;如有任何触犯法律的行为&#xff0c;均与本人及团队无关&#xff01;&#xff01;&#xff01; 目录标题 YongYouNcTool启动及适配环境核心功能界面预览一键检测命令执…...

PostgreSQL 创建表格

PostgreSQL 创建表格 在数据库管理中&#xff0c;表格&#xff08;Table&#xff09;是数据存储的基础。PostgreSQL作为一款强大的开源对象关系型数据库管理系统&#xff08;ORDBMS&#xff09;&#xff0c;创建表格是其最基本的功能之一。本文将详细讲解如何在PostgreSQL中创…...

一周一个Unity小游戏2D反弹球游戏 - 球的死区及球重生

前言 本文将实现当球弹到球板下方的死亡区域后,球会被重置到球板上发射点,并且重置物理状态的逻辑。 创建球的死亡区 之前创建的在屏幕下方的空气墙碰撞体可以将其Is Trigger勾选上,让其成为一个触发器,用来检测球是否进入该区域,如下。 创建一个脚本名为Deadzone…...

本地部署 DeepSeek:从 Ollama 配置到 Spring Boot 集成

前言 随着人工智能技术的迅猛发展&#xff0c;越来越多的开发者希望在本地环境中部署和调用 AI 模型&#xff0c;以满足特定的业务需求。本文将详细介绍如何在本地环境中使用 Ollama 配置 DeepSeek 模型&#xff0c;并在 IntelliJ IDEA 中创建一个 Spring Boot 项目来调用该模型…...

vue3:三项目增加404页面

一、路由添加 1、官网地址 带参数的动态路由匹配 | Vue Routerhttps://router.vuejs.org/zh/guide/essentials/dynamic-matching.html 2、复制核心语句 { path: /:pathMatch(.*)*, name: NotFound, component: NotFound } 3、粘贴到路由index.js中 4、建立页面 在view文件夹…...

MCAL(Microcontroller Abstraction Layer)介绍

目录 MCAL的核心作用 MCAL的模块组成 1. 微控制器驱动&#xff08;Microcontroller Drivers&#xff09; 2. I/O驱动&#xff08;DIO, PWM, ADC等&#xff09; 3. 通信驱动&#xff08;Communication Drivers&#xff09; 4. 存储驱动&#xff08;Memory Drivers&#xf…...

爬虫:PhantomJS的详细使用和实战案例

文章目录 一、PhantomJS介绍1.1 什么是 PhantomJS1.2 PhantomJS 的特点与优势二、PhantomJS 的安装2.1 在 macOS 上安装 PhantomJS2.2 在 Linux 上安装 PhantomJS2.3 在 Windows 上安装 PhantomJS2.4 验证安装三、PhantomJS 的基本使用3.1 示例 1:打开网页并截图3.2 示例 2:获…...

目标检测——数据处理

1. Mosaic 数据增强 Mosaic 数据增强步骤: (1). 选择四个图像&#xff1a; 从数据集中随机选择四张图像。这四张图像是用来组合成一个新图像的基础。 (2) 确定拼接位置&#xff1a; 设计一个新的画布(输入size的2倍)&#xff0c;在指定范围内找出一个随机点&#xff08;如…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是&#xff1a;将一个 Flask Web 应用生成成纯静态 HTML 文件&#xff0c;从而可以部署到静态网站托管服务上&#xff0c;如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

在Ubuntu24上采用Wine打开SourceInsight

1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...