【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);
			}
		}
	}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 老电脑玩游戏又卡又慢,怎么办?

    老电脑玩游戏又卡又慢,怎么办?电脑玩游戏反应慢,这里收集了网上网友们提供的方法。如果您在电脑玩游戏时也遇到反应慢的问题,可以尝试用这些办法解决。网友方案一如果电脑玩游戏反应慢,可以通过将电脑的独显打开、更改电池模式或是调整画面分辨率等方法来解决,具体的操作方法可以参考下面的内容。1、将电脑的独显打开,打开控制面板,选择左侧的管理3D设置,在全局设置界面中将自动选择改为你的NVIDIA显卡。然后选择程序设置界面将你…

    2022年6月9日
    56
  • PHP中文字符串的查找与替换「建议收藏」

    PHP中文字符串的查找与替换「建议收藏」查找字符串中是否包含某个词组&amp;amp;amp;lt;?phpechostrpos(&amp;amp;quot;一二三四五&amp;amp;quot;,&amp;amp;quot;一&amp;amp;quot;);echo&amp;amp;quot;&amp;amp;amp;lt;br&amp;amp;amp;gt;&amp;amp;quot;;echostrpos(&amp;amp;quot;一二三

    2022年5月23日
    43
  • java中getclassloader,ClassLoader getClassLoader()

    java中getclassloader,ClassLoader getClassLoader()ClassLoadergetClassLoader()描述(Description)java.lang.Class.getClassLoader()方法返回类的类加载器。某些实现可能使用null来表示引导类加载器。如果此类由引导类加载器加载,则此方法将在此类实现中返回null。声明(Declaration)以下是java.lang.Class.getClassLoader()方法的声…

    2022年4月30日
    73
  • 社会治理大数据平台怎么建_平度市社会治理大数据平台建设有序推进

    社会治理大数据平台怎么建_平度市社会治理大数据平台建设有序推进6月1日,市委常委、政法委书记陈勇调度了全市社会治理大数据平台建设进展情况。陈勇首先实地查看了市级社会治理指挥中心建设情况,详细询问了施工人员工程进展、需要协调解决的问题和困难。下午,陈勇听取了青岛城市大数据运营有限公司关于社会治理大数据平台建设推进情况汇报,指出要按照“全省最优、全国一流”的目标,加快智慧城市创新软件版块的开发和基础数据的导入,同步做好信息安全保障工作,强化实战应用,确保7月1日…

    2022年6月1日
    39
  • id门禁卡复制到手机_门禁卡复制到苹果手机

    id门禁卡复制到手机_门禁卡复制到苹果手机大家好,我是时间财富网智能客服时间君,上述问题将由我为大家进行解答。门禁卡复制到苹果手机的步骤如下:1、首先读取卡的ID,并安装“NFCTagInfo”,打开手机的NFC设置,门禁卡贴到手机后盖NFC部分,“NFCTagInfo”读取校园卡ID。可以看到“我的卡”ID号码。2、其次修改手机NFC的ID。随即打开R.E.管理器,根目录etc,找到etc文件夹中的“libnfc-nxp.conf”…

    2022年5月1日
    173
  • python-列表基本操作

    python-列表基本操作本文讲解python列表的常用操作:1.list函数,可以将任何序列作为list的参数names=['lilei','tom','mackle',&

    2022年7月5日
    22

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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