概述
ResourceUrlProviderExposingInterceptor
是Spring MVC
的一个HandlerInterceptor
,用于向请求添加一个属性,属性名称为ResourceUrlProvider.class.getName()
,值是Spring MVC
配置定义的一个资源URL
提供者对象ResourceUrlProvider
。
缺省情况下,Spring MVC
配置机制会主动构建一个ResourceUrlProviderExposingInterceptor
应用于所有的请求。
关于应用
1. 引入
缺省被WebMvcConfigurationSupport
启用:
// WebMvcConfigurationSupport 代码片段
//
/**
* Provide access to the shared handler interceptors used to configure
* {@link HandlerMapping} instances with.
* <p>This method cannot be overridden; use {@link #addInterceptors} instead.
*/
protected final Object[] getInterceptors() {
if (this.interceptors == null) {
InterceptorRegistry registry = new InterceptorRegistry();
addInterceptors(registry);
registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService()));
// 这里创建 ResourceUrlProviderExposingInterceptor,使用的 ResourceUrlProvider
// 由另外一个 bean 定义方法 #mvcResourceUrlProvider 提供
registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));
this.interceptors = registry.getInterceptors();
}
return this.interceptors.toArray();
}
// requestMappingHandlerMapping() bean 定义中使用所有 getInterceptors() 定义的通用拦截器
// mapping.setInterceptors(getInterceptors());
// viewControllerHandlerMapping() bean 定义中使用所有 getInterceptors() 定义的通用拦截器
// handlerMapping.setInterceptors(getInterceptors());
// beanNameHandlerMapping() bean 定义中使用所有 getInterceptors() 定义的通用拦截器
// mapping.setInterceptors(getInterceptors());
// resourceHandlerMapping() bean 定义中使用所有 getInterceptors() 定义的通用拦截器
// handlerMapping.setInterceptors(getInterceptors());
2. 使用
DispatcherServlet#doDispatch
请求处理主流程会先找到能处理该请求的Handler
,以HandlerExecutionChain
形式包装存在。这些HandlerExecutionChain
来自某个HandlerMapping
,而这些HandlerMapping
就是Spring MVC
配置中定义的那些HandlerMapping
,它们在DispatcherServlet
初始化阶段#initHandlerMappings
执行时被从容器中获取。
DispatcherServlet#doDispatch
得到HandlerExecutionChain
之后,会调用其方法applyPreHandle
以应用各个HandlerInterceptor
对请求的前置处理逻辑。这其中就有ConversionServiceExposingInterceptor
。
// HandlerExecutionChain 代码片段
/**
* Apply preHandle methods of registered interceptors.
* @return {@code true} if the execution chain should proceed with the
* next interceptor or the handler itself. Else, DispatcherServlet assumes
* that this interceptor has already dealt with the response itself.
*/
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];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
源代码解析
源代码版本 :
spring-webmvc-5.1.5.RELEASE
package org.springframework.web.servlet.resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.util.Assert;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
/**
* An interceptor that exposes the {@link ResourceUrlProvider} instance it
* is configured with as a request attribute.
*
* @author Rossen Stoyanchev
* @since 4.1
*/
public class ResourceUrlProviderExposingInterceptor extends HandlerInterceptorAdapter {
/**
* Name of the request attribute that holds the {@link ResourceUrlProvider}.
*/
public static final String RESOURCE_URL_PROVIDER_ATTR = ResourceUrlProvider.class.getName();
private final ResourceUrlProvider resourceUrlProvider;
public ResourceUrlProviderExposingInterceptor(ResourceUrlProvider resourceUrlProvider) {
Assert.notNull(resourceUrlProvider, "ResourceUrlProvider is required");
this.resourceUrlProvider = resourceUrlProvider;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
request.setAttribute(RESOURCE_URL_PROVIDER_ATTR, this.resourceUrlProvider);
return true;
}
}