【springmvc】拦截器Interceptor的使用与源码分析

【springmvc】拦截器Interceptor的使用与源码分析拦截器Interceptor的使用自定义拦截器需要实现HandlerInterceptor接口。packagecom.morris.spring.mvc.interceptor;importorg.springframework.web.servlet.HandlerInterceptor;importorg.springframework.web.servlet.ModelAndView;importjavax.servlet.http.HttpServletRequest;imp

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

拦截器Interceptor的使用

自定义拦截器需要实现HandlerInterceptor接口。

package com.morris.spring.mvc.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor { 
   

    // 目标方法运行之前执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 
   
        System.out.println("preHandle" + request.getRequestURI());
        return true;
    }

    // 目标方法运行之后执行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 
   
        System.out.println("postHandle");
    }

    // 页面响应后执行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 
   
        System.out.println("afterCompletion");
    }
}

配置拦截器以及要匹配的url:

com.morris.spring.mvc.config.MVCConfig#addInterceptors

// 添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) { 
   
	registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**"); // /**拦截任意路径
	registry.addInterceptor(new LocaleChangeInterceptor()); // 不设置path就会拦截所有请求
}

源码分析

Interceptor的收集过程

RequestMappingHandlerMapping的实例化过程中,会完成所有的Interceptor的收集工作。

org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#requestMappingHandlerMapping

@Bean
@SuppressWarnings("deprecation")
public RequestMappingHandlerMapping requestMappingHandlerMapping(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) { 

RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
// 设置拦截器
mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
mapping.setContentNegotiationManager(contentNegotiationManager);
mapping.setCorsConfigurations(getCorsConfigurations());
PathMatchConfigurer configurer = getPathMatchConfigurer();
Boolean useSuffixPatternMatch = configurer.isUseSuffixPatternMatch();
if (useSuffixPatternMatch != null) { 

mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
}
Boolean useRegisteredSuffixPatternMatch = configurer.isUseRegisteredSuffixPatternMatch();
if (useRegisteredSuffixPatternMatch != null) { 

mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
}
Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
if (useTrailingSlashMatch != null) { 

mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
}
UrlPathHelper pathHelper = configurer.getUrlPathHelper();
if (pathHelper != null) { 

mapping.setUrlPathHelper(pathHelper);
}
PathMatcher pathMatcher = configurer.getPathMatcher();
if (pathMatcher != null) { 

mapping.setPathMatcher(pathMatcher);
}
Map<String, Predicate<Class<?>>> pathPrefixes = configurer.getPathPrefixes();
if (pathPrefixes != null) { 

mapping.setPathPrefixes(pathPrefixes);
}
return mapping;
}

org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#getInterceptors

protected final Object[] getInterceptors(
FormattingConversionService mvcConversionService,
ResourceUrlProvider mvcResourceUrlProvider) { 

if (this.interceptors == null) { 

// interceptors默认为空
InterceptorRegistry registry = new InterceptorRegistry();
/** * @see DelegatingWebMvcConfiguration#addInterceptors(org.springframework.web.servlet.config.annotation.InterceptorRegistry) */
addInterceptors(registry);
// 添加两个默认的Interceptor
registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService));
registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider));
this.interceptors = registry.getInterceptors();
}
return this.interceptors.toArray();
}

org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration#addInterceptors

protected void addInterceptors(InterceptorRegistry registry) { 

this.configurers.addInterceptors(registry);
}

而MVCConfig实现了WebMvcConfigurer,最终会调到MVCConfig.addInterceptors()方法将我们自定义的Interceptor加入到RequestMappingHandlerMapping的interceptors属性中。

org.springframework.web.servlet.config.annotation.InterceptorRegistration#getInterceptor

protected Object getInterceptor() { 

if (this.includePatterns.isEmpty() && this.excludePatterns.isEmpty()) { 

return this.interceptor;
}
String[] include = StringUtils.toStringArray(this.includePatterns);
String[] exclude = StringUtils.toStringArray(this.excludePatterns);
// 包装为MappedInterceptor
MappedInterceptor mappedInterceptor = new MappedInterceptor(include, exclude, this.interceptor);
if (this.pathMatcher != null) { 

mappedInterceptor.setPathMatcher(this.pathMatcher);
}
return mappedInterceptor;
}

org.springframework.web.servlet.handler.AbstractHandlerMapping#initApplicationContext

protected void initApplicationContext() throws BeansException { 

extendInterceptors(this.interceptors);
// 从spring mvc容器中获取所有的MappedInterceptor
// 从这里可以看出,我们可以通过向spring mvc容器中注入MappedInterceptor来实现注入Interceptor
detectMappedInterceptors(this.adaptedInterceptors);
// 初始化interceptor
// 将interceptors添加到adaptedInterceptors
initInterceptors();
}
protected void initInterceptors() { 

if (!this.interceptors.isEmpty()) { 

for (int i = 0; i < this.interceptors.size(); i++) { 

Object interceptor = this.interceptors.get(i);
if (interceptor == null) { 

throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
}
this.adaptedInterceptors.add(adaptInterceptor(interceptor));
}
}
}

最后所有的Intercepor位于RequestMappingHandlerMapping的adaptedInterceptors属性。

Interceptor的执行过程

所有的请求都会经过DispatcherServlet的doDispatch()方法。

org.springframework.web.servlet.DispatcherServlet#doDispatch

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { 

HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try { 

ModelAndView mv = null;
Exception dispatchException = null;
try { 

// 判断请求头中是否有文件,如果有会将请求包装为MultipartHttpServletRequest
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
// HandlerExecutionChain,获取Handler
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) { 

noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 获取HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) { 

long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { 

return;
}
}
// 调用拦截器的HandlerInterceptor.preHandle()
if (!mappedHandler.applyPreHandle(processedRequest, response)) { 

return;
}
// Actually invoke the handler.
/** * @see AbstractHandlerMethodAdapter#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object) */
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) { 

return;
}
applyDefaultViewName(processedRequest, mv);
// 调用拦截器的HandlerInterceptor.postHandle()
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) { 

dispatchException = ex;
}
catch (Throwable err) { 

// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 进行异常处理
// 视图渲染
// 调用拦截器的HandlerInterceptor.afterCompletion()
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) { 

// 调用拦截器的HandlerInterceptor.afterCompletion()
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) { 

// 调用拦截器的HandlerInterceptor.afterCompletion()
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally { 

if (asyncManager.isConcurrentHandlingStarted()) { 

// Instead of postHandle and afterCompletion
if (mappedHandler != null) { 

mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else { 

// Clean up any resources used by a multipart request.
if (multipartRequestParsed) { 

cleanupMultipart(processedRequest);
}
}
}
}

将handler与interceptors封装为HandlerExecutionChain。

org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandlerExecutionChain

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { 

HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 获取url
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) { 

if (interceptor instanceof MappedInterceptor) { 

MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
// 将url与interceptor配置的url进行匹配
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { 

// 能匹配上的interceptor加入到HandlerExecutionChain中
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else { 

// 直接向容器中注入的MappedInterceptor
// 没配置path的直接加入到HandlerExecutionChain中
chain.addInterceptor(interceptor);
}
}
return chain;
}

在handler执行之前HandlerInterceptor.interceptor:

org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { 

HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) { 

for (int i = 0; i < interceptors.length; i++) { 

HandlerInterceptor interceptor = interceptors[i];
// 调用HandlerInterceptor.preHandle
if (!interceptor.preHandle(request, response, this.handler)) { 

// 调用HandlerInterceptor.afterCompletion
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}

这里要注意的是调用了HandlerInterceptor的preHandle()方法就一定会调用HandlerInterceptor的afterCompletion(),假如目前有A、B、C三个Interceptor,执行了A和B的preHandle(),在执行C的preHandle()方法时返回false,那么还是执行A和B的afterCompletion(),而且是先执行B.afterCompletion(),再执行A.afterCompletion()。

在handler执行之后,视图解析之前执行HandlerInterceptor.postHandle:

org.springframework.web.servlet.HandlerExecutionChain#applyPostHandle

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception { 

HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) { 

// i在这里是从大到小,也就是按interceptors的逆序执行
for (int i = interceptors.length - 1; i >= 0; i--) { 

HandlerInterceptor interceptor = interceptors[i];
// 调用HandlerInterceptor.postHandle
interceptor.postHandle(request, response, this.handler, mv);
}
}
}

在视图渲染之后执行HandlerInterceptor.afterCompletion:

org.springframework.web.servlet.HandlerExecutionChain#triggerAfterCompletion

void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
throws Exception { 

HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) { 

// i在这里是从大到小,也就是按interceptors的逆序执行
for (int i = this.interceptorIndex; i >= 0; i--) { 

HandlerInterceptor interceptor = interceptors[i];
try { 

// 调用HandlerInterceptor.afterCompletion
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) { 

logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/160950.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Class类的getClassLoader()方法

    Class类的getClassLoader()方法packageminglu;importjava.lang.reflect.InvocationTargetException;importjava.lang.reflect.Method;publicclassHelloWorld{ publicstaticvoidmain(String[]args)throwsInstantiationException,

  • android 关于提高第三方app的service优先级

    android 关于提高第三方app的service优先级

  • java web的动静分离_Nginx+Tomcat动静分离架构

    java web的动静分离_Nginx+Tomcat动静分离架构Nginx+Tomcat动静分离架构Nginx+tomcat是目前主流的javaweb架构,Nginx动静分离简单来说就是把动态跟静态请求分开,不能理解成只是单纯的把动态页面和静态页面物理分离。严格意义上说应该是动态请求跟静态请求分开,可以理解成使用Nginx处理静态页面,Tomcat、Resin出来动态页面。动静分离从目前实现角度来讲大致分为两种,一种是纯粹的把静态文件独立成单独的域名,放在独…

  • 10分钟就能学会,Linux操作系统21个shell常用命令

    10分钟就能学会,Linux操作系统21个shell常用命令目录一、shell的基本形式1.shell的种类:sh、bash、csh、tcsh、ash等。(1).shshell(2).cshshell(3).tcshshell(4).ashshell(5).bashshell2.shell命令的基本格式3.注意1.Linux严格区分大小写,aA不同2.使用分号(;)一行中输入多个命令。3.按下Table键,自动补齐命令、目录或文

    2022年10月17日
  • 关于模板函数声明与定义的问题[通俗易懂]

    c++primer上说:c++模板函数的声明与定义通常放在头文件中,而普通的函数通常是声明放在头文件中,定义放在源文件中,为什么会有这样的区别呢?模板函数与普通成员函数到底有什么区别?测试代码:tem.h#ifndef_TEM_H#define_TEM_HtemplateTadd(Ta,Tb);//{//returna+b;//}

  • idea21.1 激活码-激活码分享

    (idea21.1 激活码)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.html…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号