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 中。
结尾
以上为本篇分析的全部内容。
关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。