servlet
Servlet是运行在Web服务器上的Java类。它们主要用于处理HTTP请求和响应。 Servlet可以接收来自客户端(例如浏览器)的HTTP请求并生成响应,这些响应通常是HTML页面、XML文档或其他格式的数据。Servlet通常被设计用来扮演Web应用的控制器或中心位置。Servlet 是用于创建动态 Web 内容的 Java 程序。在 Java EE(Java Enterprise Edition)平台上,Servlet 是服务器端组件,运行在 Web 服务器或应用服务器上。Servlet 的主要作用是处理客户端(通常是 Web 浏览器)发送的请求,并生成响应。
理解Servlet需要注意以下几点:
- Servlet是Java编写的。
- Servlet 是运行在 Web 服务器中的 Java 类。
- Servlet 继承了 javax.servlet.Servlet 接口并实现了该接口提供的方法。其中最重要的两个方法是 doGet() 和 doPost(),它们分别用于处理 HTTP GET 和 POST 请求。
- Servlet 可以通过对象化地使用 HttpServletRequest 和 HttpServletResponse 对象来访问 Web 客户端的请求信息和响应信息。
- Servlet 执行速度快,比 CGI 要快得多。一个 Servlet 可以为多个客户端请求提供服务,而不必像 CGI 一样每次都重新启动进程。
总之,Servlet是Java编写的Web服务器组件,用于处理HTTP请求和生成响应。Servlet极大地简化了基于Web的应用程序的开发,提高了性能和可扩展性。
下面是一些关于 Servlet 的关键点:
-
运行环境:Servlet 运行在支持 Java 的 Web 服务器或应用服务器上,如 Apache Tomcat、Jetty、GlassFish 等。
-
生命周期:
- 加载和初始化:Servlet 容器(Web 服务器或应用服务器)在首次接收请求时加载 Servlet 类,并调用
init()
方法进行初始化。 - 处理请求:每次接收请求时,容器会创建一个新的线程,并调用 Servlet 的
service()
方法。这个方法会根据请求类型(GET、POST 等)进一步调用doGet()
、doPost()
等方法。 - 销毁:当容器决定卸载 Servlet 时,会调用
destroy()
方法,进行资源清理。
- 加载和初始化:Servlet 容器(Web 服务器或应用服务器)在首次接收请求时加载 Servlet 类,并调用
-
工作流程:
- 客户端发送 HTTP 请求到服务器。
- 服务器将请求转发给对应的 Servlet。
- Servlet 处理请求,执行业务逻辑。
- Servlet 生成响应(如 HTML、JSON 等)并返回给客户端。
-
Servlet API:Java Servlet API 提供了一组接口和类,用于创建 Servlet 应用程序。常用的类和接口包括:
HttpServlet
:所有 HTTP 协议的 Servlet 类都应该扩展自这个类。HttpServletRequest
:封装了客户端请求信息。HttpServletResponse
:用于生成并发送响应给客户端。
-
优点:
- 高效:Servlet 由 Java 编写,具有跨平台特性,并且在性能上通常优于 CGI(Common Gateway Interface)。
- 扩展性和灵活性:由于是基于 Java 编写的,Servlet 可以方便地集成其他 Java 库和技术。
- 安全性:Java 本身提供了一些安全机制,如垃圾回收、类型安全等,使得 Servlet 在安全性方面也有一定优势。
Servlet 通常与 JSP(JavaServer Pages)结合使用,JSP 负责视图层,Servlet 负责控制层和业务逻辑处理。通过这种分层设计,可以更好地组织和维护 Web 应用程序。
servlet和spring中controller的联系
Servlet 和 Spring 中的 Controller 都是用于处理 Web 请求的服务器端组件,但它们有一些关键的区别和联系:
Servlet
- 原理:Servlet 是 Java EE 的基础组件,用于处理 HTTP 请求和响应。每个 Servlet 类都继承自
HttpServlet
类,并重写doGet()
、doPost()
等方法来处理不同类型的 HTTP 请求。 - 使用:直接编写和配置 Servlet 需要编写大量的样板代码和配置,尤其是在大型项目中,手动管理这些 Servlet 会变得复杂。
Spring Controller
- 原理:Spring 中的 Controller 是 Spring MVC 框架的一部分,简化了 Web 应用的开发。Controller 类中定义的处理方法通过注解(如
@RequestMapping
、@GetMapping
、@PostMapping
等)来映射到特定的 HTTP 请求路径。 - 使用:Spring MVC 提供了很多自动化和便利功能,比如依赖注入、自动配置等,使得开发更加简洁和高效。开发者只需专注于业务逻辑,而不用关心底层的 Servlet 配置。
联系
- 底层实现:Spring MVC 的底层仍然依赖于 Servlet。Spring 的
DispatcherServlet
是一个特殊的 Servlet,它作为前端控制器(Front Controller)接收所有请求,然后将这些请求分发给不同的 Controller 方法进行处理。 - 简化开发:Spring MVC 通过抽象和简化 Servlet 的使用,使开发者不必直接处理低层的 Servlet 细节。
DispatcherServlet
帮助处理了许多标准任务,比如请求路由、参数解析、视图解析等。 - 配置:在 Spring 应用中,
web.xml
(或等效的 Java 配置类)中通常会有一个配置DispatcherServlet
的部分,这是 Spring MVC 框架的入口点。
示例代码
Servlet 示例:
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html");PrintWriter out = response.getWriter();out.println("<h1>Hello, Servlet!</h1>");}
}
Spring Controller 示例:
@Controller
public class HelloController {@GetMapping("/hello")public String hello(Model model) {model.addAttribute("message", "Hello, Spring MVC!");return "hello"; // 视图名,视图解析器会处理}
}
在 Spring MVC 中,你定义一个 DispatcherServlet
,它会自动将请求转发到合适的 Controller 方法,并处理响应。通过这种方式,Spring MVC 简化了 Web 应用的开发,使得代码更加简洁和可维护。
filter、interceptor、controller之间的关系
在 Spring 框架中,Filter
、Interceptor
和 Controller
是处理 HTTP 请求的三个不同层次的组件,它们各自的职责和使用场景如下:
Filter
- 位置:位于最外层,属于 Servlet 规范的一部分,在 Servlet 容器中配置。
- 作用:对进入应用的所有 HTTP 请求和响应进行预处理和后处理。
- 典型用途:用于处理与请求和响应相关的通用任务,如日志记录、认证、跨域处理、请求压缩等。
- 执行时机:在
DispatcherServlet
之前和之后执行。
示例:
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {// 预处理System.out.println("Filter is invoked before");chain.doFilter(request, response);// 后处理System.out.println("Filter is invoked after");}
}
Interceptor
- 位置:位于 Spring MVC 的中间层,在
DispatcherServlet
之后,Controller
之前和之后。 - 作用:拦截并处理具体的请求,在处理请求之前、请求处理之后以及视图渲染之前进行操作。
- 典型用途:用于检查用户会话、处理权限验证、记录性能日志等。
- 执行时机:在
Controller
方法调用之前和之后,以及视图渲染之前。
示例:
public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {System.out.println("Interceptor: preHandle");return true; // 返回 true 继续处理,返回 false 中断请求}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {System.out.println("Interceptor: postHandle");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {System.out.println("Interceptor: afterCompletion");}
}
配置:
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");}
}
Controller
- 位置:位于请求处理的核心层,具体处理业务逻辑。
- 作用:接收请求并返回响应,通常与服务层和数据层交互以处理业务逻辑和数据。
- 典型用途:处理 HTTP 请求、调用业务逻辑、返回视图或数据。
- 执行时机:在
Interceptor
之后执行。
示例:
@Controller
public class MyController {@GetMapping("/hello")public String hello(Model model) {model.addAttribute("message", "Hello, Spring MVC!");return "hello"; // 视图名,视图解析器会处理}
}
总结关系
- Filter:最外层,用于通用的请求和响应处理,在
DispatcherServlet
之前执行。 - Interceptor:中间层,特定于 Spring MVC,用于对特定请求进行预处理和后处理,在
DispatcherServlet
之后,Controller
之前和之后执行。 - Controller:核心层,负责具体的业务逻辑处理和响应生成。
整个请求处理流程可以总结为:
- 客户端请求发送到服务器。
- Filter进行预处理。
- DispatcherServlet分发请求。
- Interceptor进行预处理。
- Controller处理请求并返回数据或视图。
- Interceptor进行后处理。
- Filter进行后处理。
- 服务器响应发送到客户端。
为什么有了filter,还需要interceptor?两者有什么区别?
Filter 和 Interceptor 虽然都可以用于拦截和处理 HTTP 请求,但它们在设计目的、使用场景和实现细节上有一些重要的区别。下面详细说明两者的区别及各自的优势。
Filter
- 标准:属于 Java Servlet 规范的一部分,不依赖于 Spring 框架。
- 作用范围:可以拦截所有进入应用的 HTTP 请求和响应,包括静态资源请求。
- 典型用途:用于处理与请求和响应相关的通用任务,如日志记录、认证、跨域处理、请求压缩等。
- 执行时机:在
DispatcherServlet
之前和之后执行。 - 配置方式:通过
web.xml
文件或使用注解@WebFilter
进行配置。
示例:
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {// 预处理System.out.println("Filter is invoked before");chain.doFilter(request, response);// 后处理System.out.println("Filter is invoked after");}
}
Interceptor
- 标准:属于 Spring 框架的一部分,特定于 Spring MVC。
- 作用范围:仅拦截由 Spring MVC 处理的请求,不包括静态资源请求。
- 典型用途:用于处理与业务逻辑相关的任务,如检查用户会话、权限验证、记录性能日志等。
- 执行时机:在
DispatcherServlet
之后,Controller
之前和之后,以及视图渲染之前执行。 - 配置方式:通过 Spring 配置类或 XML 文件进行配置。
示例:
public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {System.out.println("Interceptor: preHandle");return true; // 返回 true 继续处理,返回 false 中断请求}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {System.out.println("Interceptor: postHandle");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {System.out.println("Interceptor: afterCompletion");}
}
配置:
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");}
}
主要区别
-
依赖框架:
- Filter:属于 Java EE 规范的一部分,可以在任何支持 Servlet 的容器中使用。
- Interceptor:属于 Spring 框架的一部分,仅在 Spring MVC 环境中使用。
-
拦截范围:
- Filter:拦截所有 HTTP 请求和响应,包括静态资源。
- Interceptor:仅拦截由 Spring MVC 处理的请求,不包括静态资源。
-
配置方式:
- Filter:通过
web.xml
文件或@WebFilter
注解配置。 - Interceptor:通过 Spring 配置类或 XML 文件配置。
- Filter:通过
-
执行时机:
- Filter:在
DispatcherServlet
之前和之后执行。 - Interceptor:在
DispatcherServlet
之后,Controller
之前和之后,以及视图渲染之前执行。
- Filter:在
为什么需要 Interceptor
- Spring 集成:Interceptor 深度集成在 Spring MVC 框架中,可以直接访问 Spring 容器中的 bean 和其他组件,更加方便与业务逻辑和 Spring 特有功能的结合。
- 灵活性:Interceptor 可以更细粒度地控制请求处理流程,比如在请求处理前、请求处理后、视图渲染前进行操作。
- 方便配置:通过 Spring 的配置文件或注解,可以更方便地管理和配置拦截器,支持更复杂的拦截规则和条件。
总结
虽然 Filter 和 Interceptor 都可以用于拦截和处理 HTTP 请求,但它们各自有特定的使用场景和优势。Filter 更适合处理与请求和响应相关的通用任务,而 Interceptor 更适合与业务逻辑相关的任务,特别是在使用 Spring MVC 框架时。两者可以互补使用,以实现更灵活和强大的请求处理机制。
spring中实现filter
在 Spring 中也可以实现 Filter。Spring 提供了对 Servlet Filter 的支持,并且可以通过 Spring 配置进行管理和注入依赖。下面是如何在 Spring 应用中实现和配置 Filter 的详细说明。
实现 Filter
实现 Filter 与在标准 Servlet 容器中实现是相同的,都是通过实现 javax.servlet.Filter
接口来完成。
示例:
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化代码}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {// 预处理System.out.println("Filter is invoked before");chain.doFilter(request, response);// 后处理System.out.println("Filter is invoked after");}@Overridepublic void destroy() {// 销毁代码}
}
在 Spring 中配置 Filter
有几种方法可以在 Spring 中配置 Filter:使用注解、在 web.xml
中配置,或者通过 Spring Boot 的 FilterRegistrationBean
。
方法一:使用注解
可以直接在 Filter 类上使用 @WebFilter
注解,如上示例。
方法二:使用 web.xml
在传统的 web 应用中,可以通过 web.xml
文件进行配置。
web.xml:
<filter><filter-name>myFilter</filter-name><filter-class>com.example.MyFilter</filter-class>
</filter>
<filter-mapping><filter-name>myFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
方法三:使用 Spring Boot 的 FilterRegistrationBean
如果使用 Spring Boot,可以通过 FilterRegistrationBean
来注册 Filter。
示例:
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class FilterConfig {@Beanpublic FilterRegistrationBean<MyFilter> loggingFilter() {FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new MyFilter());registrationBean.addUrlPatterns("/*");return registrationBean;}
}
总结
- Filter 实现:通过实现
javax.servlet.Filter
接口,可以在 Spring 中创建自定义的 Filter。 - 配置方式:可以通过注解
@WebFilter
、web.xml
配置文件,或者 Spring Boot 提供的FilterRegistrationBean
进行配置。 - 作用范围:无论通过哪种方式配置,Filter 都是在
DispatcherServlet
之前和之后执行,拦截所有进入应用的 HTTP 请求和响应。
在 Spring 中实现和配置 Filter 可以灵活地处理通用的请求和响应任务,同时还可以结合 Spring 的依赖注入和其他功能,使得 Filter 的开发和管理更加便捷。
传统模式-spring之前
在 Spring 出现之前,Java EE(现在称为 Jakarta EE)环境中的请求处理流程主要依赖于 Servlet 和 Filter。整个流程通常如下:
请求处理流程(没有 Spring 的情况下)
-
客户端请求:
- 客户端(通常是浏览器)发送一个 HTTP 请求到服务器。
-
Web 服务器接收请求:
- Web 服务器(如 Apache Tomcat)接收到这个请求,并根据 URL 路径确定如何处理这个请求。
-
Filter 链处理:
- 服务器首先将请求传递给一系列配置的 Filter。这些 Filter 可以对请求进行预处理(如认证、日志记录、压缩等)。
- 每个 Filter 都实现了
javax.servlet.Filter
接口,并在doFilter
方法中处理请求。 - Filter 链中的每个 Filter 按照配置的顺序依次执行。每个 Filter 可以选择继续将请求传递给链中的下一个 Filter,或者在某些条件下阻止请求的进一步处理。
Filter 示例:
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {// 预处理System.out.println("Filter is invoked before");chain.doFilter(request, response);// 后处理System.out.println("Filter is invoked after");}
}
- 请求到达 Servlet:
- 经过所有 Filter 之后,请求最终到达指定的 Servlet。
- Servlet 根据请求的路径和类型(如 GET、POST)选择合适的方法进行处理(如
doGet
、doPost
)。
Servlet 示例:
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.setContentType("text/html");PrintWriter out = response.getWriter();out.println("<h1>Hello, Servlet!</h1>");}
}
-
Servlet 处理请求:
- Servlet 执行业务逻辑,比如读取请求参数、查询数据库、调用其他服务等。
- 处理完请求后,Servlet 生成响应数据,通常是 HTML、JSON 或 XML 格式。
-
响应通过 Filter 链返回:
- Servlet 生成的响应通过 Filter 链返回。每个 Filter 还可以对响应进行后处理(如压缩响应内容、添加响应头等)。
-
服务器返回响应给客户端:
- 处理完成的响应通过 Web 服务器返回给客户端,客户端(浏览器)显示或处理响应内容。
流程图示
[Client]|v
[Web Server]|v
[Filter 1] --> [Filter 2] --> ... --> [Filter N]| |v v
[Servlet]|v
[Filter N] --> ... --> [Filter 2] --> [Filter 1]|v
[Web Server]|v
[Client]
总结
- 客户端请求:发送到 Web 服务器。
- Web 服务器接收请求:并决定交给哪个 Servlet 处理。
- Filter 链处理:请求先经过一系列 Filter 进行预处理。
- Servlet 处理请求:请求到达指定的 Servlet 进行业务逻辑处理。
- 响应通过 Filter 链返回:处理后的响应通过 Filter 链返回给客户端。
- 服务器返回响应给客户端:客户端接收到响应并进行显示或处理。
这种设计模式确保了请求和响应在到达和离开 Servlet 之前可以进行各种通用的处理任务,提供了一个灵活的机制来实现横切关注点(如安全、日志等)。
spring之后
在引入 Spring 之后,尤其是 Spring MVC 框架,这个请求处理流程变得更加结构化和模块化。Spring 提供了更高级的抽象和便利功能来处理 Web 请求。下面是有了 Spring 之后的请求处理流程。
请求处理流程(使用 Spring 后)
-
客户端请求:
- 客户端(通常是浏览器)发送一个 HTTP 请求到服务器。
-
Web 服务器接收请求:
- Web 服务器(如 Apache Tomcat)接收到请求,并根据 URL 路径确定如何处理这个请求。
-
Filter 链处理:
- 请求首先传递给配置的 Servlet Filter,这部分与之前的流程类似,Filter 可以进行预处理。
- 如果使用 Spring Boot,可以通过
FilterRegistrationBean
来注册 Filter。
Filter 示例:
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {// 预处理System.out.println("Filter is invoked before");chain.doFilter(request, response);// 后处理System.out.println("Filter is invoked after");}
}
- 请求到达
DispatcherServlet
:DispatcherServlet
是 Spring MVC 框架的前端控制器,负责接收所有进入应用的 HTTP 请求。- 在
web.xml
或 Spring Boot 配置中,所有请求路径通常会映射到DispatcherServlet
。
Spring Boot 配置示例:
@SpringBootApplication
public class MySpringBootApplication {public static void main(String[] args) {SpringApplication.run(MySpringBootApplication.class, args);}
}
-
HandlerMapping:
DispatcherServlet
使用HandlerMapping
根据请求 URL 找到合适的处理器(通常是一个Controller
方法)。
-
HandlerInterceptor 链处理:
- 在找到具体的处理器之前,请求会经过一系列配置的
HandlerInterceptor
进行预处理。 - Interceptor 可以在处理请求之前、处理请求之后以及视图渲染之前执行。
- 在找到具体的处理器之前,请求会经过一系列配置的
Interceptor 示例:
public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {System.out.println("Interceptor: preHandle");return true; // 返回 true 继续处理,返回 false 中断请求}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {System.out.println("Interceptor: postHandle");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {System.out.println("Interceptor: afterCompletion");}
}
配置 Interceptor:
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");}
}
- 处理请求(Controller):
- 找到具体的处理器后,
DispatcherServlet
调用对应的Controller
方法来处理请求。 Controller
方法执行具体的业务逻辑,通常与服务层和数据层交互,并生成视图或数据响应。
- 找到具体的处理器后,
Controller 示例:
@Controller
public class MyController {@GetMapping("/hello")public String hello(Model model) {model.addAttribute("message", "Hello, Spring MVC!");return "hello"; // 视图名,视图解析器会处理}
}
-
视图解析与渲染:
- 如果
Controller
方法返回的是视图名,DispatcherServlet
使用ViewResolver
解析视图,并渲染最终的视图(通常是 JSP、Thymeleaf 等)。
- 如果
-
响应通过 Interceptor 链返回:
- 在视图渲染之前和之后,
HandlerInterceptor
也可以进行后处理。
- 在视图渲染之前和之后,
-
响应通过 Filter 链返回:
- 处理完成的响应通过 Filter 链返回到客户端。
- 服务器返回响应给客户端:
- 客户端接收到响应并进行显示或处理。
流程图示
[Client]|v
[Web Server]|v
[Filter 1] --> [Filter 2] --> ... --> [Filter N]| |v v
[DispatcherServlet] --> [Interceptor 1] --> [Interceptor 2] --> ... --> [Interceptor N]| |v v
[Controller]|v
[Interceptor N] --> ... --> [Interceptor 2] --> [Interceptor 1]|v
[Filter N] --> ... --> [Filter 2] --> [Filter 1]|v
[Web Server]|v
[Client]
总结
在 Spring 出现之后,请求处理流程变得更加模块化和结构化。DispatcherServlet
作为前端控制器,简化了请求的分发和处理逻辑。Filter 和 Interceptor 提供了强大的预处理和后处理能力,使得请求和响应的处理更加灵活和可扩展。通过这种架构,Spring MVC 提供了一个高效且易于维护的 Web 应用开发框架。
DispatcherServlet 作用
DispatcherServlet
是 Spring MVC 框架中的核心组件,被称为前端控制器(Front Controller)。它负责将所有进入应用的 HTTP 请求分发到合适的处理器(通常是控制器方法)。DispatcherServlet
提供了一个统一的请求处理入口,简化了请求分发和处理逻辑。它的作用和工作原理可以总结如下:
DispatcherServlet 的主要作用
-
统一入口:所有的 HTTP 请求首先由
DispatcherServlet
接收。它充当了 Web 应用的入口点,集中管理和处理所有请求。 -
请求分发:根据请求 URL 和 HTTP 方法,
DispatcherServlet
使用HandlerMapping
将请求分发给适当的处理器(控制器方法)。 -
处理链管理:
DispatcherServlet
调用配置的HandlerInterceptor
进行预处理和后处理,类似于拦截器。 -
视图解析:在控制器处理完请求后,
DispatcherServlet
使用ViewResolver
解析视图,并进行渲染。 -
异常处理:统一处理应用程序中的异常,可以配置全局异常处理机制。
DispatcherServlet 的工作流程
-
接收请求:
- 客户端请求到达 Web 服务器后,服务器将请求转发给
DispatcherServlet
。
- 客户端请求到达 Web 服务器后,服务器将请求转发给
-
HandlerMapping:
DispatcherServlet
使用HandlerMapping
查找与请求路径和方法匹配的处理器(控制器方法)。
-
HandlerAdapter:
DispatcherServlet
使用HandlerAdapter
来执行找到的处理器。这使得处理器可以是多种类型(例如,控制器方法、注解方法等)。
-
执行拦截器:
- 在处理器执行前,调用配置的
HandlerInterceptor
的preHandle
方法进行预处理。 - 如果
preHandle
返回true
,则继续执行处理器;否则,处理被中断。
- 在处理器执行前,调用配置的
-
调用处理器:
- 执行找到的处理器(通常是控制器方法),处理请求并返回模型和视图(
ModelAndView
)。
- 执行找到的处理器(通常是控制器方法),处理请求并返回模型和视图(
-
执行拦截器后处理:
- 在处理器执行后,调用
HandlerInterceptor
的postHandle
方法进行后处理。
- 在处理器执行后,调用
-
视图解析与渲染:
- 使用
ViewResolver
解析处理器返回的视图名,将其转换为实际的视图对象。 - 渲染视图,将处理结果(通常是 HTML 内容)写入响应。
- 使用
-
完成请求:
- 调用
HandlerInterceptor
的afterCompletion
方法进行清理工作。 - 将响应返回给客户端。
- 调用
DispatcherServlet 的配置
在 Spring Boot 中,DispatcherServlet
自动配置并注册为应用的前端控制器,处理所有路径(/
)。在传统的 Spring MVC 应用中,可以在 web.xml
文件中配置 DispatcherServlet
:
web.xml:
<web-app><servlet><servlet-name>dispatcher</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>dispatcher</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
</web-app>
在 Spring Boot 中,DispatcherServlet
的配置可以通过属性文件进行定制,例如:
application.properties:
spring.mvc.servlet.path=/api
总结
DispatcherServlet
是 Spring MVC 的核心组件,提供了一个统一的请求处理机制。通过集中管理请求分发、拦截器处理、视图解析和异常处理,它简化了 Web 应用的架构,使开发者能够专注于业务逻辑的实现。
多个filter和interceptor的执行顺序
在 Spring 应用中,多个 Filter
和多个 Interceptor
之间的执行顺序是可以通过配置进行控制的。下面分别介绍它们的执行顺序及如何配置。
多个 Filter 的执行顺序
多个 Filter
的执行顺序取决于它们的注册顺序。以下是几种常见的配置方法:
使用 web.xml
配置
web.xml
中 Filter
的定义顺序决定了它们的执行顺序,先定义的 Filter
先执行。
<filter><filter-name>Filter1</filter-name><filter-class>com.example.Filter1</filter-class>
</filter>
<filter><filter-name>Filter2</filter-name><filter-class>com.example.Filter2</filter-class>
</filter>
<filter-mapping><filter-name>Filter1</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping><filter-name>Filter2</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
使用 Spring Boot 的 FilterRegistrationBean
通过 FilterRegistrationBean
注册 Filter
时,可以设置优先级来控制执行顺序。
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class FilterConfig {@Beanpublic FilterRegistrationBean<Filter1> filter1() {FilterRegistrationBean<Filter1> registrationBean = new FilterRegistrationBean<>(new Filter1());registrationBean.setOrder(1); // 优先级,值越小越先执行return registrationBean;}@Beanpublic FilterRegistrationBean<Filter2> filter2() {FilterRegistrationBean<Filter2> registrationBean = new FilterRegistrationBean<>(new Filter2());registrationBean.setOrder(2);return registrationBean;}
}
多个 Interceptor 的执行顺序
多个 Interceptor
的执行顺序由它们在 WebMvcConfigurer
中注册的顺序决定。注册顺序即执行顺序。
配置 Interceptor 的顺序
在 Spring 配置类中,通过实现 WebMvcConfigurer
接口并在 addInterceptors
方法中注册 Interceptor
,顺序即为执行顺序。
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new Interceptor1()).addPathPatterns("/**");registry.addInterceptor(new Interceptor2()).addPathPatterns("/**");}
}
在上述例子中,Interceptor1
会先于 Interceptor2
执行。
执行顺序总结
-
Filter 执行顺序:
doFilter
方法按照注册顺序执行,先注册的Filter
先执行。- 在
doFilter
方法中调用chain.doFilter(request, response)
,表示传递给下一个Filter
或Servlet
。
-
Interceptor 执行顺序:
preHandle
方法按照注册顺序执行,先注册的Interceptor
先执行。postHandle
和afterCompletion
方法按照注册顺序的逆序执行,即最后注册的Interceptor
最先执行它们的postHandle
和afterCompletion
方法。
执行顺序示例
假设有两个 Filter
(Filter1
和 Filter2
) 和两个 Interceptor
(Interceptor1
和 Interceptor2
),它们的执行顺序如下:
-
Filters:
Filter1
的doFilter
方法前半部分Filter2
的doFilter
方法前半部分Servlet
或DispatcherServlet
处理请求Filter2
的doFilter
方法后半部分Filter1
的doFilter
方法后半部分
-
Interceptors:
Interceptor1
的preHandle
方法Interceptor2
的preHandle
方法Controller
处理请求Interceptor2
的postHandle
方法Interceptor1
的postHandle
方法Interceptor2
的afterCompletion
方法Interceptor1
的afterCompletion
方法
通过合理配置和理解 Filter
和 Interceptor
的执行顺序,可以更有效地管理和处理 HTTP 请求及其生命周期中的各个环节。
默认的filter和interceptor执行顺序
如果没有显式定义执行顺序,Filter
和 Interceptor
的执行顺序将取决于框架的默认行为和它们的加载顺序。
默认情况下的 Filter 执行顺序
-
在 web.xml 中定义:
Filter
的执行顺序由它们在web.xml
文件中的定义顺序决定。先定义的Filter
会先执行。- 如果
web.xml
中的Filter
顺序如下:<filter><filter-name>Filter1</filter-name><filter-class>com.example.Filter1</filter-class> </filter> <filter><filter-name>Filter2</filter-name><filter-class>com.example.Filter2</filter-class> </filter> <filter-mapping><filter-name>Filter1</filter-name><url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping><filter-name>Filter2</filter-name><url-pattern>/*</url-pattern> </filter-mapping>
- 执行顺序为:
Filter1
->Filter2
->Servlet
->Filter2
->Filter1
。
-
在 Spring Boot 中未定义顺序:
- 如果使用 Spring Boot 并通过
FilterRegistrationBean
注册多个Filter
,且没有设置顺序,Filter
的执行顺序由 Spring Boot 自动确定,通常是按声明的顺序执行。 - 如果顺序没有显式设置,可能会出现意外的执行顺序,因此建议总是显式设置顺序。
- 如果使用 Spring Boot 并通过
默认情况下的 Interceptor 执行顺序
-
在 WebMvcConfigurer 中定义:
Interceptor
的执行顺序由它们在WebMvcConfigurer
中注册的顺序决定。先注册的Interceptor
先执行其preHandle
方法,postHandle
和afterCompletion
方法按相反的顺序执行。- 如果顺序如下:
@Configuration public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new Interceptor1()).addPathPatterns("/**");registry.addInterceptor(new Interceptor2()).addPathPatterns("/**");} }
- 执行顺序为:
Interceptor1
的preHandle
Interceptor2
的preHandle
- 控制器方法执行
Interceptor2
的postHandle
Interceptor1
的postHandle
Interceptor2
的afterCompletion
Interceptor1
的afterCompletion
-
Spring Boot 默认配置:
- Spring Boot 默认使用
Ordered
接口或@Order
注解来确定组件的顺序。如果没有显式设置,顺序取决于组件的加载顺序和自动配置顺序。
- Spring Boot 默认使用
没有显式定义顺序时的潜在问题
没有显式定义顺序可能会导致 Filter
或 Interceptor
按不可预期的顺序执行,从而引发难以调试的问题。因此,明确设置执行顺序是一个最佳实践。
设置顺序的推荐方式
-
显式设置 Filter 顺序:
- 在 Spring Boot 中使用
FilterRegistrationBean
设置顺序。@Bean public FilterRegistrationBean<Filter1> filter1() {FilterRegistrationBean<Filter1> registrationBean = new FilterRegistrationBean<>(new Filter1());registrationBean.setOrder(1); // 优先级,值越小越先执行return registrationBean; }@Bean public FilterRegistrationBean<Filter2> filter2() {FilterRegistrationBean<Filter2> registrationBean = new FilterRegistrationBean<>(new Filter2());registrationBean.setOrder(2);return registrationBean; }
- 在 Spring Boot 中使用
-
显式设置 Interceptor 顺序:
- 在
WebMvcConfigurer
中注册时按照期望的顺序进行注册。@Configuration public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new Interceptor1()).addPathPatterns("/**");registry.addInterceptor(new Interceptor2()).addPathPatterns("/**");} }
- 在
通过明确设置 Filter
和 Interceptor
的顺序,可以确保请求处理的预期行为,减少潜在的错误和调试难度。