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

SpringMVC 执行原理

Servlet 介绍

1.1 Servlet 规范

Servlet(Server Applet)是由 Sun 公司(现 Oracle)制定的 Java Web 应用程序组件规范,定义了 Java Web 服务器与 Java 应用程序之间的通信协议,是 Java EE 平台的核心规范之一。最新版本为 Servlet 6.0(JSR 378),于 2021 年发布,主要增强了对 HTTP/2、WebSocket 和异步处理的支持。

规范定义了 Servlet 组件的设计标准、API 接口、生命周期规则 以及 Servlet 与 Web 容器的交互方式

1.2 Servlet 容器

Servlet 规范规定了 Servlet 容器如何加载 Servlet、映射 URL、传递请求等细节,也称为 Web 容器 或 Servlet 引擎,是 Java Web 应用的运行环境。

Servlet 容器是 Java Web 技术的基石,它将底层网络通信、协议解析和组件生命周期管理抽象为标准化接口,使开发者只需关注业务逻辑。从轻量级的 Tomcat 到企业级的 WildFly,不同容器针对性能、功能和场景做了优化。

1.3 Servlet 接口

Java Servlet(Java服务器小程序)是 遵循 Servlet 规范的具体实现类,基于Java技术的Web组件,运行在服务器端,它由 Servlet 容器所管理,用于生成动态的内容。

1.3.1 Servlet 接口生命周期

1)实例化:Servlet容器实例化servlet,每个Servlet类只有一个实例

2)init():容器启动时初始化 Servlet(仅初始化一次);

3)service():是Servlet的核心,客户端请求时,Servlet 对象的service()方法会被调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数;

默认的服务功能是调用与HTTP请求的方法相应的do功能。每次请求Servlet容器都会将service放入线程池中执行。连接池是在Web容器(Tomcat)中配置和管理处理请求时调用,根据请求方法(GET/POST 等)分发到具体方法;

4)destroy():容器关闭时销毁 Servlet 时调用,释放资源;

1.3.2 Servlet 接口使用

在 Servlet 3.0 规范之前,Servlet 通过 web.xml 中进行配置。在 Servlet 3.0 规范中,引入了 ServletContainerInitializer,用于在 Servlet 容器启动时动态注册 Servlet、Filter、Listener 等组件,无需在 web.xml 中进行硬编码配置。

Servlet 容器通过 Java 的 SPI 机制发现 ServletContainerInitializer 的实现类。

实现类需在 META-INF/services/javax.servlet.ServletContainerInitializer 文件中声明全限定名。

1)ServletContainerInitializer 的代码如下:

public interface ServletContainerInitializer {/*** @param c:实现该接口的类中添加的 @HandlesTypes 注解指定的类的集合(若未指定则为 null)* @param ctx:ServletContext 对象提供了 addServlet()、addListener()、addFilter() 等方法*/public void onStartup(Set<Class<?>> c, ServletContext ctx)throws ServletException; 
}

2)示例

@HandlesTypes(MyWebServlet.class)
public class MyContainerInitializer implements ServletContainerInitializer {@Overridepublic void onStartup(Set<Class<?>> classes, ServletContext ctx) {// classes 为 MyWebServlet 类集合// 使用 ctx 动态添加 Servlet、Listener、Filter 等}
}

1.4 过滤器 Filter

1.4.1 Filter 简介

Filter 是 Servlet 规范中的组件,用于拦截请求和响应,在请求到达 Servlet 之前或响应返回客户端之前进行预处理或后处理。可用于字符编码转换、权限验证、日志记录、请求限流、敏感信息过滤等。

1.4.2 Filter生命周期

1)init():初始化参数,在创建Filter时自动调用。如果需要设置初始化参数的时候,可以写到该方法中;

2)doFilter():请求先经过 Filter 的doFilter() 方法,该方法传入 FilterChain 参数。预处理后,调用 FilterChain 的 doFilter() 方法,执行下一个 Filter 或执行 Servlet。如果需要后处理,在执行 FilterChain.doFilter() 方法之后执行;

3)destory():Filter 销毁时调用;

1.5 监听器 Listener

Listener 是 Servlet 规范中的组件,用于监听 Servlet 容器中的事件(如对象创建 / 销毁、属性变更等),并在事件发生时执行相应逻辑。可用于应用初始化(如加载配置文件)、在线用户统计、资源释放、性能监控等。

Servlet 规范中提供了三大类对象的变化的监听:

1)ServletContext(应用上下文):监听应用上下文的生命周期和属性变化

a)ServletContextListener:监听 ServletContext 的创建和销毁。如:加载配置文件、初始化数据库连接池、启动定时任务;

b)ServletContextAttributeListener:监听 ServletContext 属性的添加、删除和修改。如全局变量变更监控、应用状态统计;

2)HttpSession(会话):监听会话的生命周期和属性变化

a)HttpSessionListener:监听 HttpSession 的创建和销毁。如在线用户统计、会话持久化;
b)HttpSessionAttributeListener:监听 HttpSession 属性的添加、删除和修改。如用户权限变更监听、敏感数据访问审计;

c)HttpSessionIdListener(Servlet 3.1+):监听 Session ID 的变更(如防止 Session 固定攻击);
d)HttpSessionActivationListener:监听 HttpSession 的钝化(Passivate)和活化(Activate)。如分布式会话管理、会话持久化;

3)ServletRequest(请求):监听请求的生命周期和属性变化

a)ServletRequestListener:监听 ServletRequest 的创建和销毁。如请求耗时统计、请求日志记录;
b)ServletRequestAttributeListener:监听 ServletRequest 属性的添加、删除和修改。如请求范围内的变量监控;

4)特殊监听器

a)AsyncListener(Servlet 3.0+):监听异步请求的生命周期。如异步请求的异常处理、资源释放;
b)HttpSessionBindingListener:监听对象与 Session 的绑定和解绑。如资源自动释放(如对象从 Session 移除时关闭数据库连接);

Spring MVC 原理

Spring MVC 是基于 Servlet API 的强大 Web 框架,采用 MVC(Model-View-Controller)架构模式,通过 DispatcherServlet 统一处理请求,并利用组件化设计实现了请求映射、参数解析、视图渲染等功能的解耦。

2.1 DispatcherServlet 的结构树:

DispatcherServlet 实现了 Serlvet 接口。

2.2 DispatcherServlet 请求执行的流程

在 Spring MVC 中,DispatcherServlet 的映射路径配置为“/”,即映射所有的请求。当客户端有请求到服务端时,先通过 DispatcherServlet,通过 DispatherServlet 再进行分发。执行流程如下:

2.3 DispatcherServlet 注册到容器

2.3.1 通过 web.xml 配置

对于外部 Servlet 容器或早期的 Web 项目,更多采用 web.xml 配置的方式将 DispatcherServlet 添加到容器中。

核心代码如下:

    <servlet><!--servlet名字,随意 --><servlet-name>spring</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><load-on-startup>1</load-on-startup></servlet><servlet-mapping><!--servlet名字 --><servlet-name>spring</servlet-name><!--拦截所有请求,对静态文件会有问题,在spring-servlet.xml中解决 --><url-pattern>/</url-pattern></servlet-mapping>

2.3.2 通过 SpringServletContainerInitializer 加入

Spring MVC 也可通过 SpringServletContainerInitializer,实现在 Servlet 容器启动时动态注册 DispatcherServlet。

以下源码版本为 Spring-framework 5.x 

1)SpringServletContainerInitializer 源码如下:

/*** Spring Servlet容器初始化器*/
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {@Overridepublic void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)throws ServletException {// 获取所有实现WebApplicationInitializer的类对象List<WebApplicationInitializer> initializers = new LinkedList<>();if (webAppInitializerClasses != null) {for (Class<?> waiClass : webAppInitializerClasses) {// Be defensive: Some servlet containers provide us with invalid classes,// no matter what @HandlesTypes says...if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&WebApplicationInitializer.class.isAssignableFrom(waiClass)) {try {// 反射,创建实例initializers.add((WebApplicationInitializer)ReflectionUtils.accessibleConstructor(waiClass).newInstance());}catch (Throwable ex) {throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);}}}}if (initializers.isEmpty()) {servletContext.log("No Spring WebApplicationInitializer types detected on classpath");return;}servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");// 进行排序AnnotationAwareOrderComparator.sort(initializers);// 遍历执行初始化器for (WebApplicationInitializer initializer : initializers) {initializer.onStartup(servletContext);}}}

在 onStartup() 方法中,实例化 WebApplicationInitializer 实例,执行 WebApplicationInitializer 的 onStartup() 方法。Spring 源码中有实现该接口的抽象类 AbstractAnnotationConfigDispatcherServletInitializer。

此种实现方式,需要项目中自定义实现 WebApplicationInitializer 的类。

示例:Spring Boot项目采用外置 War 包部署的实现。

1)自定义类,继承 SpringBootServletInitializer。

public class MyServletInitializer extends SpringBootServletInitializer {@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {return application.sources(MyApplication.class);}
}

2)创建 MyApplication 类。该类为 SpringBoot 的启动类

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}

原理:SpringBootServletInitializer 实现了 WebApplicationInitializer 接口

public abstract class SpringBootServletInitializer implements WebApplicationInitializer {}

2.3.3 SpringBoot 自动装载

在 SpringBoot 中,通过 DispatcherServletAutoConfiguration 自动配置类,如果系统中没有定义 DispatcherServlet 类,则创建一个 DispatcherServlet 。同时,会自动创建 DispatcherServletRegistrationBean 对象。该对象实现了 ServletContextInitializer。在onStatrup() 方法中,将 DispatcherServlet 添加到 ServletContext 中。

结尾

以上为本篇分析的全部内容。

关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。

http://www.dtcms.com/a/284288.html

相关文章:

  • 79、【OS】【Nuttx】【启动】caller-saved 和 callee-saved 示例:r7 寄存器
  • Modbus
  • PyCharm2024安装包社区版和专业版
  • TESOLLO五指灵巧手遥操作解决方案
  • 使用 .NET Core 的原始 WebSocket
  • Spring整合MyBatis详解
  • 概率论与数理统计(四)
  • WCDB soci 查询语句
  • 缓存雪崩、缓存穿透,缓存击穿
  • 使用IntelliJ IDEA和Maven搭建SpringBoot集成Fastjson项目
  • 【git】使用教程
  • CommonJS和ES模块区别对比
  • API开发提速新方案:SmartBear API Hub与ReadyAPI虚拟化整合实践
  • ESP8266服务器建立TCP连接失败AT+CIPSTART=“TCP“,“192.168.124.1“,8080 ERROR CLOSED
  • JAVA后端开发——success(data) vs toAjax(rows): 何时用
  • 美拍sig逆向
  • 神经网络:模拟人脑的 AI 信息处理系统
  • 代码随想录打卡第十二天
  • Unity | AmplifyShaderEditor插件基础(第十集:噪声的种类+火焰制作-下)
  • 透过结构看时间——若思考清洗则表达有力
  • 开源Agent平台Dify源码剖析系列(六)核心模块core/agent之CotCompletionAgentRunner
  • Web开发 01
  • Vue.js 的 Composition API 深度解析:构建高效可维护的前端逻辑
  • 让大模型输出更加规范化——指定插件
  • LVS部署DR模式集群
  • @Linux搭建DNS-主从服务器
  • Spring原理揭秘--Spring的AOP
  • cuda编程笔记(8)--线程束warp
  • Cookie 与 Session概述
  • AI编程实战:如何让AI生成带参数和返回值的Python函数——以PDF文本提取为例