博客索引web
HandlerInterceptor
至于为何要继承这个类,下面讲解原理的时候会提到。 咱们写一个简单的HelloInterceptor
拦截器,输出hellospring
public class HelloInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("hello,i am HelloInterceptor");
return true;
}
}
复制代码
WebConfiguration
来继承WebMvcConfigurer
,以下:@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Bean
HelloInterceptor interceptor() {
return new HelloInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册拦截器HelloInterceptor,拦截全部请求,除了/test
registry.addInterceptor(interceptor()).addPathPatterns("/**").excludePathPatterns("/test");
}
}
复制代码
@RestController
public class MvcController {
@GetMapping("/test")
private String test() {
System.out.println("i am test ......");
return "test";
}
@GetMapping("/test1")
private String test1() {
System.out.println("i am test1 ......");
return "test1";
}
}
复制代码
访问localhost:8080/test 输出i am test ...... 访问localhost:8080/test1 输出 i am HelloInterceptor i am test ......数组
直接看配置类中的方法。bash
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册拦截器HelloInterceptor,拦截全部请求,除了/test
registry.addInterceptor(interceptor()).addPathPatterns("/**").excludePathPatterns("/test");
}
复制代码
点进去发现。InterceptorRegistry
里面有个registrations对象是一个InterceptorRegistration
类型的拦截器列表,addInterceptor(HandlerInterceptor)方法将拦截器包装成InterceptorRegistration
对象并添加到registrations对象。而后还会发现里面有个getInterceptors()方法返回全部的拦截器。咱们用idea搜索一下,看那些地方调用这个方法。mvc
public class InterceptorRegistry {
private final List<InterceptorRegistration> registrations = new ArrayList<>();
public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor) {
InterceptorRegistration registration = new InterceptorRegistration(interceptor);
this.registrations.add(registration);
return registration;
}
public InterceptorRegistration addWebRequestInterceptor(WebRequestInterceptor interceptor) {
WebRequestHandlerInterceptorAdapter adapted = new WebRequestHandlerInterceptorAdapter(interceptor);
InterceptorRegistration registration = new InterceptorRegistration(adapted);
this.registrations.add(registration);
return registration;
}
/**
* 返回全部注册的拦截器
*/
protected List<Object> getInterceptors() {
return this.registrations.stream()
.sorted(INTERCEPTOR_ORDER_COMPARATOR)
// 这里很关键,类型是MappedInterceptor
.map(InterceptorRegistration::getInterceptor)
.collect(Collectors.toList());
}
private static final Comparator<Object> INTERCEPTOR_ORDER_COMPARATOR =
OrderComparator.INSTANCE.withSourceProvider(object -> {
if (object instanceof InterceptorRegistration) {
return (Ordered) ((InterceptorRegistration) object)::getOrder;
}
return null;
});
}
复制代码
org.springframework.web.servlet.config.annotation.InterceptorRegistration#getInterceptor()
: 返回MappedInterceptor类型的拦截器,返回值yongObject接收,也就是说咱们自定义的拦截器会被包装成MappedInterceptor
类型,而MappedInterceptor
又继承了HandlerInterceptor
,还提了匹配URL的功能,便于各类自定义开发。app
protected Object getInterceptor() {
if (this.includePatterns.isEmpty() && this.excludePatterns.isEmpty()) {
return this.interceptor;
}
// 拦截路径的数组,好比咱们自定义的HelloInterceptor,那么这里的include=["/**"]
String[] include = StringUtils.toStringArray(this.includePatterns);
// 排除路径的数组,这里的exclude=["/test"]
String[] exclude = StringUtils.toStringArray(this.excludePatterns);
MappedInterceptor mappedInterceptor = new MappedInterceptor(include, exclude, this.interceptor);
if (this.pathMatcher != null) {
mappedInterceptor.setPathMatcher(this.pathMatcher);
}
return mappedInterceptor;
}
复制代码
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#getInterceptors()
调用了以前的
protected final Object[] getInterceptors(
FormattingConversionService mvcConversionService,
ResourceUrlProvider mvcResourceUrlProvider) {
if (this.interceptors == null) {
InterceptorRegistry registry = new InterceptorRegistry();
addInterceptors(registry);
registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService));
registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider));
// 获取全部注册过的拦截器
this.interceptors = registry.getInterceptors();
}
return this.interceptors.toArray();
}
复制代码
继续搜索,看哪一个地方调用这个getInterceptors()方法。cors
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#requestMappingHandlerMapping
: 建立
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);
// 给RequestMappingHandlerMapping设置拦截器
mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
···省略其余
return mapping;
}
复制代码
org.springframework.web.servlet.handler.AbstractHandlerMapping#setInterceptors(Object... interceptors)
:抽象类,封装了RequestMappingHandlerMapping
大部分方法,能够理解成是一种模板模式,其中几个重要的方法。async
HandlerInterceptor
类型或者WebRequestInterceptor
,要否则就会抛出异常。这就解答了咱们自定义异常为何要继承HandlerInterceptor
。public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
implements HandlerMapping, Ordered, BeanNameAware {
@Nullable
private Object defaultHandler;
private UrlPathHelper urlPathHelper = new UrlPathHelper();
private PathMatcher pathMatcher = new AntPathMatcher();
private final List<Object> interceptors = new ArrayList<>();
private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<>();
public void setInterceptors(Object... interceptors) {
this.interceptors.addAll(Arrays.asList(interceptors));
}
// 适配拦截器
protected HandlerInterceptor adaptInterceptor(Object interceptor) {
if (interceptor instanceof HandlerInterceptor) {
return (HandlerInterceptor) interceptor;
}
else if (interceptor instanceof WebRequestInterceptor) {
return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
}
else {
throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());
}
}
// 初始化拦截器
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));
}
}
}
复制代码
因此看到这里,就能够知道咱们自动定义的拦截器最后被添加到了AbstractHandlerMapping
中。分析到这里差很少快结束了。ide
HandlerExecutionChain
在最后分析以前,要先了解一下这个类HandlerExecutionChain
拦截器链,这是由handle与一系列的拦截器组成的,也就是咱们自定义的拦截器会被放入这个类中,进行执行,话很少说,直接debug。post
public class HandlerExecutionChain {
private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
private final Object handler;
@Nullable
private HandlerInterceptor[] interceptors;
@Nullable
private List<HandlerInterceptor> interceptorList;
private int interceptorIndex = -1;
}
复制代码
在org.springframework.web.servlet.DispatcherServlet#doDispatch
中打上断点,请求http://localhost:8080/test,
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 {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 获取HandlerExecutionChain,核心地方,其余地方先略过
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
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;
}
}
// 执行拦截器中的preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// handle真正执行
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
applyDefaultViewName(processedRequest, mv);
// 执行拦截器中的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
复制代码
咱们发现返回HandlerExecutionChain
的方法getHandler(processedRequest)
,咱们知道HandlerMapping
接口中只有一个方法返回HandlerExecutionChain
,而它的实现类刚好是咱们上面分析的AbstractHandlerMapping
。
public interface HandlerMapping {
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
复制代码
org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 获取handle,有兴趣的能够深刻了解这里
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 本文的关注点,获取HandlerExecutionChain
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 获取请求路径,好比咱们的URL是localhost:8080/test 这里获得的lookupPath就是/test
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
// 遍历拦截器,判断是否是MappedInterceptor,若是是的话,则判断路径是否知足自定义的路径
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
// MappedInterceptor也就是咱们自定义的拦截器,而后将路径/test与MappedInterceptor里面的excludePatterns和includePatterns进行匹配
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
复制代码
org.springframework.web.servlet.handler.MappedInterceptor#matches(String ,PathMatcher)
:
public final class MappedInterceptor implements HandlerInterceptor {
@Nullable
private final String[] includePatterns;
@Nullable
private final String[] excludePatterns;
private final HandlerInterceptor interceptor;
@Nullable
private PathMatcher pathMatcher;
// 由于excludePatterns数组里面包含"/test",因此不匹配,返回false,这个请求中的拦截器连中就没有咱们自定义的HelloInterceptor
public boolean matches(String lookupPath, PathMatcher pathMatcher) {
PathMatcher pathMatcherToUse = (this.pathMatcher != null ? this.pathMatcher : pathMatcher);
if (!ObjectUtils.isEmpty(this.excludePatterns)) {
for (String pattern : this.excludePatterns) {
if (pathMatcherToUse.match(pattern, lookupPath)) {
return false;
}
}
}
if (ObjectUtils.isEmpty(this.includePatterns)) {
return true;
}
for (String pattern : this.includePatterns) {
if (pathMatcherToUse.match(pattern, lookupPath)) {
return true;
}
}
return false;
}
}
复制代码
到此拦截器的原理就介绍完了,若是文章有错误或者你有什么疑问,请留言或者经过邮箱联系我creazycoder@sina.com