文章目录
- 本文简略
- doservice方法
- doDispatch(重要)
- HandlerExecutionChain执行链
- 获取HandlerExecutionChain执行链
- 获取处理器适配器HandlerAdapter
- RequestMappingHandlerAdapter执行handle方法
- 调用方法:invokeAndHandle
- 调用方法invokeForRequest
- getMethodArgumentValues获取参数解析
- resolveArgument,调用参数解析器的解析方法
- 扩展
本文简略
这篇文章主要讲doDispatch方法对请求的处理, //实际的处理器处理请求,返回结果视图对象;视图对象的处理下篇再看.这是springmvc处理请求的核心中的核心.建议反复观看.
doservice方法
DispatcherServlet中最主要的核心功能是由doService和doDispatch实现的。
当请求到达后HttpServlet将调用service方法进行处理,由于我们是通过输入网址方式的get方法请求,Servlet将调用doGet方法
此处的doGet方法在FrameworkServlet中实现,doGet方法调用processRequest方法,
processRequest则调用doService方法处理,而doService在DispatcherServlet中实现,
doService再调用了DispatcherServlet的doDispatch方法,该方法则会根据request找到转发对象,并进行请求转发操作,
即dispatcherservlet中无论是通过post方式还是get方式提交的request,最终都会交由doservice()处理,然后交给doDispatch方法执行.
doService方法就如果是include请求然后保存一份快照版本中的域,还有request域中设置一些属性.
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
}
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<String, Object>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
doDispatch(重要)
doDispatch方法是处理请求的核心方法,主要流程就是判断是否上传接口,然后根据请求路径找到封装了handler和interceptors的对象HandlerExecutionChain,得到HandlerExecutionChain之后通过适配器HandlerAdapter处理得到ModelAndView对象,处理器映射器,处理器适配器前面初始化的时候都初始化了,处理器适配器的使用就在这里说.如果发生异常则会被HandlerExceptionResolver接口实现类进行处理;
// 中央控制器,控制请求的转发
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);
// Determine handler for the current request.
// 获取当前骑牛的controller,,这里也称为hanlder,处理器,第一个步骤的意义就在这里体现了.这里并不是直接返回controller,
// 而是返回的HandlerExecutionChain请求处理器链对象,该对象封装了handler和interceptors.
mappedHandler = getHandler(processedRequest);
//handler为空返回404
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
//获取处理request的处理器适配器handler adapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
// 处理 last-modified 请求头
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 拦截器的预处理方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
//实际的处理器处理请求,返回结果视图对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//结果视图对象的处理
applyDefaultViewName(processedRequest, mv);
// 拦截器后处理方法
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);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
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);
}
}
}
}
HandlerExecutionChain执行链
我们先看HandlerExecutionChain执行链,当拿到执行链的时候,就已经完成了request到controller的路由匹配,拦截器链,则是很多个拦截器组成连链,拦截器都知道,就是在执行我们的handler之前之后执行,就是一个aop的简单实现:
获取HandlerExecutionChain执行链
前面讲了初始化handlerMapping,其中最重要的最常用的就是RequestMappingHandlerMapping,就是通过Controller注解配置的类使用RequestMapping注解配置的方法,handlerMappings里面是通过不同方式配置的controller类,需要不同的handlerMapping类处理,前一篇文章也说了:
RequestMappingHandlerAdapter->
通过@Controller配置类@RequestMapping注解配置的方法
SimpleUrlHandlerMapping->
实现Controller类重写handlerRequest方法
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="index">TestController</prop>
</props>
</property>
</bean>
<bean id="TestController" class="com.alipay.web.TestController" />
BeanNameUrlHandlerMapping->
类实现Controller,重写handlerRequest()方法即可
<bean id="/index" class="com.alipay.web.TestController" />
比较重要的就是获取handler对象了,我们看getHandlerInternal方法,这个方法返回了HandlerMethod对象,这个对象就是被@ RequestMapping 注解封装的方法模型类;
通过url找到urlLookup这个map中对应的handler, 然后根据一些匹配规则, 返回一个最优的 (urlLookup这个map中的键值对是在init初始化的时候, 通过反射解析放进去的), 到此为止可以知道: 我们可以通过url获取到具体的handlerMethod对象:
public class HandlerMethod {
/** Logger that is available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
// Object类型,可以是Bean,也可以是个String 的 BeanName
private final Object bean;
//bean工厂
private final BeanFactory beanFactory;
//方法对应的Class类
private final Class<?> beanType;
// 该方法
private final Method method;
// 桥接方法
private final Method bridgedMethod;
//方法参数的入参
private final MethodParameter[] parameters;
private HttpStatus responseStatus;
private String responseStatusReason;
//通过createWithResolvedBean()解析此handlerMethod实例的handlerMethod。
private HandlerMethod resolvedFromHandlerMethod;
lookupHandlerMethod方法:
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<Match>();
//通过url找到对应的handler,然后通过匹配规则,返回最优的
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
Collections.sort(matches, comparator);
if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
lookupPath + "] : " + matches);
}
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
然后根据HandlerMethod对象封装成HandlerExecutionChain对象返回:
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
获取处理器适配器HandlerAdapter
根据handler获取适配器,如果没有匹配到handler,则会执行noHandlerFound返回404,会打印日志No mapping found for HTTP request with URI:
获取适配器就是根据适配器list进行遍历获取合适的适配器,前面适配器也大概讲了一下,跟映射器差不多,对应的解析器也是根据实现方法走不同的适配器,然后通过适配器适配处理过后执行handler方法:
实现controller接口的对应->SimpleControllerHandlerAdapter
实现HttpRequestHandler接口的对应->HttpRequestHandlerAdapter
通过@RequestMapping注解扫描:RequestMappingHandlerAdapter
其他两个就执行对应的方法,我们主要讲通过注解的方式请求处理,获取到适配器就要执行handler方法了:
RequestMappingHandlerAdapter执行handle方法
handler方法就是调用handleInternal方法,强转了一下:handleInternal方法就判断是否是要串行化访问,如果串行化则要进行加锁处理,然后最终都是执行invokeHandlerMethod方法:
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//将request和response包装成ServletWebRequest对象
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
//返回Web数据绑定器工厂
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
//获取模型工厂
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
//返回要调用的方法
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// 设置参数解析
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
//设置返回类型解析
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
//设置web数据绑定工厂
invocableMethod.setDataBinderFactory(binderFactory);
//设置参数发现器,查找方法的参数名称
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
//创建modelandView容器
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
//设置部分属性
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
//初始化模型
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
//设置忽略默认重定向模型
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
//创建异步请求
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
//超时时间
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
//异步管理器
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
//任务线程池
asyncManager.setTaskExecutor(this.taskExecutor);
//异步请求
asyncManager.setAsyncWebRequest(asyncWebRequest);
//拦截器
asyncManager.registerCallableInterceptors(this.callableInterceptors);
//设置Callable任务的带有延迟的拦截器
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
if (logger.isDebugEnabled()) {
logger.debug("Found concurrent result value [" + result + "]");
}
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
//调用
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
//返回modelandView
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
调用方法:invokeAndHandle
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 调用方法获取返回参数
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
//处理返回参数
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
调用方法invokeForRequest
这个方法比较重要,有获取请求参数,getMethodArgumentValues,然后获取了参数就直接调用反射调用对应方法就行了,主要介绍参数解析:
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//获取请求参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"' with arguments " + Arrays.toString(args));
}
// 执行方法
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"] returned [" + returnValue + "]");
}
return returnValue;
}
getMethodArgumentValues获取参数解析
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获取方法参数
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
// 初始化参数名的发现器
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
// 解析,一般为null
args[i] = resolveProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
//查找对应的参数的处理器,主要是遍历所有的参数的处理器,调用处理中的support方法,只要满足就返回true,放到缓存中
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
//调用放到缓存中的参数解析器,然后调用resolveArgument解析对象
args[i] = this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
}
throw ex;
}
}
if (args[i] == null) {
throw new IllegalStateException("Could not resolve method parameter at index " +
parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() +
": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
}
}
return args;
}
supportsParameter验证是否有对应的参数解析器:
获取参数解析器方法getArgumentResolver:
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
//从缓存中取,没有就遍历所有的
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
// 遍历所有参数解析器对参数进行适配,supportsParameter如果返回true,就是适配成功
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
result = resolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
resolveArgument,调用参数解析器的解析方法
我们看最常用的通过@RequestParam注解标注的参数解析,使用的解析器是RequestParamMethodArgumentResolver,我们主要讲这个类,其他都差不多.
然后调用抽象类AbstractNamedValueMethodArgumentResolver的resolveArgument方法:
@Override
public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//获取名称
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
//获取参数类型
MethodParameter nestedParameter = parameter.nestedIfOptional();
//解析字符串值
Object resolvedName = resolveStringValue(namedValueInfo.name);
if (resolvedName == null) {
throw new IllegalArgumentException(
"Specified name must not resolve to null: [" + namedValueInfo.name + "]");
}
//调用子类方法解析参数
Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
if (arg == null) {
//是否有默认值
if (namedValueInfo.defaultValue != null) {
arg = resolveStringValue(namedValueInfo.defaultValue);
}
//是否必填
else if (namedValueInfo.required && !nestedParameter.isOptional()) {
handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
}
//处理空值
arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
}
else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
arg = resolveStringValue(namedValueInfo.defaultValue);
}
//对参数进行转换,一般接收都是String类型,换成对应的类型
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
try {
arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
}
catch (ConversionNotSupportedException ex) {
throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
namedValueInfo.name, parameter, ex.getCause());
}
catch (TypeMismatchException ex) {
throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
namedValueInfo.name, parameter, ex.getCause());
}
}
//空方法
handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
return arg;
}
resolveName调用子类RequestParamMethodArgumentResolver的方法resolveName:
到这,请求参数就都封装完成了,然后就是通过反射调用方法了.
扩展
在获取NamedValueInfo 的时候有个知识点,springmvc不使用注解@RequestParam(“i”)标注的参数,springmvc也能进行封装,而mybatis编写mapper的时候必须要带上@Param接口,springmvc是怎么做到的:
//获取名称
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
然后就会走到LocalVariableTableParameterNameDiscoverer这个类的getParameterNames方法,通过asm框架去解析获取参数:
所以尽量使用注解,这样可以省去通过asm框架重新加载字节码文件,使用jdk1.8包括之后的版本java反射也增加了存储方法名的类,但是需要配置,这里不做过多描述了