行业知识
Spring Boot 拦截器 HandlerInterceptor的使用以及WebMvcConfigurer简单介绍
当我们使用Spring Boot构建Web应用程序时,HandlerInterceptor 是一个重要的组件,用于拦截请求的处理过程。HandlerInterceptor 接口定义了在请求处理的不同阶段执行的方法,允许我们在请求到达处理程序之前和之后执行自定义逻辑。
HandlerInterceptor
在Spring Boot中,我们通常通过实现HandlerInterceptor 接口来创建自定义的拦截器。以下是HandlerInterceptor 接口定义的主要方法:
- preHandle:在请求到达处理程序之前被调用。可以用于执行一些前置处理逻辑,例如身份验证、日志记录等。如果此方法返回true,则请求继续传递到处理程序;如果返回false,则请求处理终止。
- postHandle:在请求处理程序执行之后,视图渲染之前被调用。可以用于执行一些后置处理逻辑,例如修改模型数据、记录执行时间等。
- afterCompletion:在整个请求完成之后被调用。通常用于清理资源、记录最终日志等。可以在这里获取到处理程序的执行结果和可能的异常信息。
要使用HandlerInterceptor,我们需要在配置类中注册它。例如,在Spring Boot中,我们可以创建一个继承自WebMvcConfigurerAdapter(在Spring 5中使用WebMvcConfigurer)的配置类,并重写addInterceptors 方法。
@Configurationpublic class MyWebMvcConfigurer extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyHandlerInterceptor()).addPathPatterns("/**"); }} 在这个例子中,MyHandlerInterceptor 是我们自定义的拦截器类,它需要实现HandlerInterceptor 接口。
public class MyHandlerInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 在请求处理前执行的逻辑 return true; // 返回 true 允许请求继续,返回 false 则终止请求 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // 在请求处理后、视图渲染前执行的逻辑 } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 在整个请求完成后执行的逻辑 }} 通过使用HandlerInterceptor,我们可以实现对请求处理过程的精细控制,例如添加全局的身份验证、记录请求日志等功能。
HandlerInterceptorAdapter
HandlerInterceptorAdapter 是 Spring 提供的一个适配器类,实现了 HandlerInterceptor 接口,并且提供了默认的空实现。它的存在使得我们在实现自定义拦截器时,只需要关注我们感兴趣的方法,而不需要实现所有方法。
具体来说,HandlerInterceptorAdapter 实现了 HandlerInterceptor 接口的三个方法:preHandle、postHandle、和 afterCompletion。默认情况下,这些方法的实现为空,允许我们只重写需要的方法,而不用关心其他方法。
以下是一个简单的例子,展示了如何使用 HandlerInterceptorAdapter:
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class MyInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 在请求处理前执行的逻辑 return true; // 返回 true 允许请求继续,返回 false 则终止请求 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // 在请求处理后、视图渲染前执行的逻辑 } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 在整个请求完成后执行的逻辑 }} 在这个例子中,MyInterceptor 类继承了 HandlerInterceptorAdapter,并重写了 preHandle、postHandle 和 afterCompletion 方法,实现了自定义的拦截逻辑。
然后,我们可以将这个拦截器注册到 Spring MVC 的配置中,就像之前提到的方式一样:
@Configurationpublic class MyWebMvcConfigurer extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**"); }} 使用 HandlerInterceptorAdapter 可以让拦截器的实现更加简洁,只需关注自己感兴趣的方法即可。
AsyncHandlerInterceptor
AsyncHandlerInterceptor 是 HandlerInterceptor 接口的一种扩展,专门用于处理异步请求。与同步请求不同,异步请求在处理过程中可能涉及到线程的切换,因此需要专门的拦截器来支持这种场景。
与普通的 HandlerInterceptor 相比,AsyncHandlerInterceptor 接口增加了对异步请求的支持,它定义了额外的方法来处理异步场景:
- preHandle:与同步请求的 preHandle 方法类似,在异步请求的开始阶段被调用。可以用于执行一些前置处理逻辑。返回 true 表示请求继续进行,返回 false 则中断异步请求的处理。
- postHandle:与同步请求的 postHandle 方法类似,但是在异步请求的主处理线程完成处理之后调用。可以用于执行一些后置处理逻辑。
- afterCompletion:与同步请求的 afterCompletion 方法类似,但是在整个异步请求完成之后调用。可以用于清理资源、记录最终日志等。
- afterConcurrentHandlingStarted:在异步请求处理开始时被调用。此时,主处理线程已经处理完请求,而异步请求的处理可能在其他线程中进行。可以用于执行一些异步处理开始时的逻辑。
要使用 AsyncHandlerInterceptor,我们可以通过实现该接口并将其注册到配置中,就像使用普通的 HandlerInterceptor 一样。以下是一个简单的例子:
public class MyAsyncHandlerInterceptor implements AsyncHandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 在异步请求开始前执行的逻辑 return true; // 返回 true 允许请求继续,返回 false 则中断异步请求的处理 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // 在异步请求的主处理线程完成处理后执行的逻辑 } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 在整个异步请求完成后执行的逻辑 } @Override public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 在异步请求处理开始时执行的逻辑 }} 然后,将拦截器注册到配置中:
@Configurationpublic class MyWebMvcConfigurer extends WebMvcConfigurerAdapter { @Override public void configureAsyncSupport(AsyncSupportConfigurer configurer) { configurer.registerCallableInterceptors(new MyAsyncHandlerInterceptor()); }} 在这个例子中,MyAsyncHandlerInterceptor 是实现了 AsyncHandlerInterceptor 接口的自定义异步拦截器。
AsyncHandlerInterceptor使用场景
AsyncHandlerInterceptor 主要用于处理异步请求场景,其中异步请求是指在请求处理过程中,主处理线程可能会在处理的不同阶段释放出来,允许其他线程继续处理请求。以下是一些适合使用 AsyncHandlerInterceptor 的场景:
- 长时间任务处理:
- 当应用需要处理长时间运行的任务时,可以使用异步请求,而 AsyncHandlerInterceptor 可以用于处理异步请求的不同阶段。
- 例如,如果某个请求触发了一个需要很长时间才能完成的任务,你可以在异步处理的开始和结束阶段执行一些逻辑,例如记录日志、通知用户等。
- 非阻塞I/O操作:
- 异步请求通常用于处理非阻塞 I/O 操作,例如读取或写入大量数据、调用外部服务等。
- 在异步处理的开始和结束阶段,AsyncHandlerInterceptor 可以用于执行相关的逻辑,例如记录性能指标、处理异常情况等。
- 推送通知:
- 当需要实现服务器端推送通知给客户端时,异步请求是一个常见的选择。
- 使用 AsyncHandlerInterceptor 可以在推送开始和结束的时候执行逻辑,例如记录推送日志、处理异常情况等。
- 资源处理和清理:
- 异步请求在整个处理过程中可能涉及到多个线程,因此可以使用 AsyncHandlerInterceptor 在异步请求的不同阶段进行资源的处理和清理。
- 例如,可以在异步处理开始时分配某些资源,在异步请求结束时进行清理。
- 异步任务执行前后的逻辑:
- 如果应用中使用了异步任务执行框架(如 Spring 的 @Async),AsyncHandlerInterceptor 可以在异步任务开始执行前和执行完成后执行一些逻辑。
- 这可以用于记录任务执行时间、处理异常等。
总的来说,使用 AsyncHandlerInterceptor 的场景通常涉及到异步请求的处理,而这些请求在执行过程中可能涉及到线程的切换和长时间运行的任务。在这些场景中,AsyncHandlerInterceptor 提供了一种机制,允许我们在异步请求的不同阶段执行自定义逻辑,以满足特定需求。
Configurer
WebMvcConfigurer
WebMvcConfigurer 接口是 Spring MVC 提供的用于配置 Web MVC 的接口。通过实现这个接口,可以对 Spring MVC 进行一些自定义配置,例如添加拦截器、修改视图解析器、配置消息转换器等。以下是一些常见的用法:
import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.*;@Configurationpublic class MyWebMvcConfigurer implements WebMvcConfigurer { // 1. 添加拦截器 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**"); } // 这里的 MyInterceptor 是你自定义的拦截器,可以在其中实现需要的拦截逻辑。 // 2. 添加自定义静态资源处理 @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/"); } // 这样配置后,访问路径 /static/** 将会映射到 classpath:/static/ 目录下的资源。 // 3. 修改视图解析器 @Override public void configureViewResolvers(ViewResolverRegistry registry) { // 这里可以进行视图解析器的自定义配置,例如: // registry.jsp("/WEB-INF/views/", ".jsp"); // 表示使用 JSP 视图解析器,视图文件位于 /WEB-INF/views/ 目录下,后缀为 .jsp。 } // 4. 配置消息转换器 @Override public void configureMessageConverters(List> converters) { // 在这里可以配置消息转换器,例如添加自定义的 JSON 转换器。 // converters.add(new MyJsonConverter()); } // 5. 配置跨域资源共享(CORS) @Override protected void addCorsMappings(CorsRegistry registry) { // 配置跨域资源共享,允许 http://localhost:8080 发起的跨域请求访问 /api/** registry.addMapping("/api/**").allowedOrigins("http://localhost:8080"); } // 这是一个简单的例子,允许来自 http://localhost:8080 的请求跨域访问 /api/** 路径。 //------------------------- 其它方法 ----------------------------- // 配置路径匹配 @Override protected void configurePathMatch(PathMatchConfigurer configurer) { // 在这里可以设置路径匹配的行为,例如是否在路径末尾添加斜杠 // configurer.setUseTrailingSlashMatch(false); } // 配置异步请求的支持 @Override protected void configureAsyncSupport(AsyncSupportConfigurer configurer) { // 在这里可以设置异步请求的超时时间、线程池等 // configurer.setDefaultTimeout(30000); } // 配置内容协商策略 @Override protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) { // 在这里可以设置默认的内容类型、请求参数中的内容类型等 // configurer.defaultContentType(MediaType.APPLICATION_JSON); } // 扩展消息转换器 @Override protected void extendMessageConverters(List