概述
ConversionServiceExposingInterceptor
是Spring MVC
的一个HandlerInterceptor
,用于向请求添加一个属性,属性名称为ConversionService.class.getName()
,值是Spring MVC
配置定义的一个类型转换服务。该类型转换服务会在请求处理过程中用于请求参数或者返回值的类型转换。
缺省情况下,Spring MVC
配置机制会主动构建一个ConversionServiceExposingInterceptor
应用于所有的请求。
关于应用
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()));
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.handler;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.convert.ConversionService;
import org.springframework.util.Assert;
/**
* Interceptor that places the configured {@link ConversionService} in request scope
* so it's available during request processing. The request attribute name is
* "org.springframework.core.convert.ConversionService", the value of
* {@code ConversionService.class.getName()}.
*
* <p>Mainly for use within JSP tags such as the spring:eval tag.
*
* @author Keith Donald
* @since 3.0.1
*/
public class ConversionServiceExposingInterceptor extends HandlerInterceptorAdapter {
private final ConversionService conversionService;
/**
* Creates a new {@link ConversionServiceExposingInterceptor}.
* @param conversionService the conversion service to export to request scope when this interceptor is invoked
*/
public ConversionServiceExposingInterceptor(ConversionService conversionService) {
Assert.notNull(conversionService, "The ConversionService may not be null");
this.conversionService = conversionService;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws ServletException, IOException {
// 请求处理前向请求添加属性
// 属性名称使用 ConversionService.class.getName()
request.setAttribute(ConversionService.class.getName(), this.conversionService);
return true;
}
}