大家好,又见面了,我是你们的朋友全栈君。
拦截器Interceptor的使用
自定义拦截器需要实现HandlerInterceptor接口。
代码语言:javascript复制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:
代码语言:javascript复制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的收集工作。
代码语言:javascript复制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
代码语言:javascript复制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();
}
代码语言:javascript复制org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration#addInterceptors
protected void addInterceptors(InterceptorRegistry registry) {
this.configurers.addInterceptors(registry);
}
而MVCConfig实现了WebMvcConfigurer,最终会调到MVCConfig.addInterceptors()方法将我们自定义的Interceptor加入到RequestMappingHandlerMapping的interceptors属性中。
代码语言:javascript复制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;
}
代码语言:javascript复制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()方法。
代码语言:javascript复制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。
代码语言:javascript复制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:
代码语言:javascript复制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:
代码语言:javascript复制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:
代码语言:javascript复制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);
}
}
}
}
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/160950.html原文链接:https://javaforall.cn