码迷,mamicode.com
首页 > 编程语言 > 详细

springmvc 的请求处理过程(精编)

时间:2019-01-21 19:09:59      阅读:241      评论:0      收藏:0      [点我收藏+]

标签:代码   http   保存   一个   abi   def   工作   接下来   contain   

 

技术分享图片 

1. DispacherServlet 前端控制器接受发送过来的请求,交给HandlerMapping 处理映射器,

2. HandlerMapping 处理映射器, 根据请求找到相应的HandlerAdapter 处理适配器(处理适配器就是那些拦截器活着吧Controller)

3. HandlerAdapter处理器适配器,处理一些功能请求, 返回一个ModleAndView 对象,包括模型数据、逻辑视图名。

ViewResolver视图解析器 ,先根据ModleAndView 中设置的view 解析具体视图

5. 然后将Modle模型中得数据渲染到View中。

这些过程都是以DispatchServlet 为中轴线进行的。

 

首先说说:HandlerMapping 视图解析器的接口

作用是根据当前请求的找到对应的Handler 并将Handler(执行程序) 与一对HandlerInterceptor(拦截器)封装到HandlerExecutionChain 对象中。在HandlerMapping接口的内部只有一个方法,如下

  • HandlerExecutionChain getHandler(HttpServletRequest request);

HandlerMapping 是由 DispatcherServlet 调用,DispatcherServlet 会从容器中取出所有 HandlerMapping 实例并遍历,让 HandlerMapping 实例根据自己实现类的方式去尝试查找 Handler,而 HandlerMapping 具体有哪些实现类下面就会详细分析。

 

 HandlerMapping 实现类有两个分支,分别继承自 AbstractHandlerMethodMapping(得到 HandlerMethod)和 AbstractUrlHandlerMapping(得到 HttpRequestHandler、Controller 或 Servlet),它们又统一继承于AbstractHandlerMapping

 

 

先来看一下 AbstractHandlerMapping,它实现了 HandlerMapping 接口中的 getHandler() 方法,源码如下所示:

@Override

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

// 根据请求获取执行程序,具体的获取方式由子类决定,getHandlerInternal() 是抽象方法

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 = getApplicationContext().getBean(handlerName);

}

// 将 Handler 与一堆拦截器包装到 HandlerExecutionChain 对象中

return getHandlerExecutionChain(handler, request);

}

//  Handler 与一堆拦截器包装到 HandlerExecutionChain 对象中

 

可以看到在这个方法中又调用了 getHandlerInternal() 方法获取到了 Handler 对象,而 Handler 对象具体内容是由它的子类去定义的。下面就来一看下 AbstractHandlerMapping 的两个分支子类。

 

2):AbstractHandlerMethodMapping

AbstractHandlerMethodMapping 这个分支获取的 Handler 的类型是 HandlerMethod,即这个 Handler 是一个方法,它保存了方法的信息(如Method),这样一个 Controller 就可以处理多个请求了,源码如下所示:

 

@Override

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {

// 根据当前请求获取“查找路径” 从 HttpServletRequest中获取请求的路径。

String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);

// 获取当前请求最佳匹配的处理方法(即Controller类的方法中)(获取请求中的方法)

HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);

return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);

}

 

 

 

下面的是 lookupHandlerMethod(lookupPath, request); 的方法体:

@Nullable

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {

List<AbstractHandlerMethodMapping<T>.Match> matches = new ArrayList();

//根据请的路径找到 直接访问的路径。

List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);

if (directPathMatches != null) {

this.addMatchingMappings(directPathMatches, matches, request);

}

 

if (matches.isEmpty()) {

this.addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);

}

 

if (!matches.isEmpty()) {

Comparator<AbstractHandlerMethodMapping<T>.Match> comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));

Collections.sort(matches, comparator);

if (this.logger.isTraceEnabled()) {

this.logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);

}

 

AbstractHandlerMethodMapping<T>.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);

if (matches.size() > 1) {

if (CorsUtils.isPreFlightRequest(request)) {

return PREFLIGHT_AMBIGUOUS_MATCH;

}

 

AbstractHandlerMethodMapping<T>.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)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 + "}");

}

}

 

this.handleMatch(bestMatch.mapping, lookupPath, request);

return bestMatch.handlerMethod;

else {

return this.handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);

}

}

上述代码中 lookupHandlerMethod() 方法主要工作是在 Map<T, HandlerMethod> handlerMethods 中找到 HandlerMethod,这里的 T 是 HandlerMappingInfo,它封装了 @RequestMapping 注解中的信息。那 HandlerMethod 是怎么创建的(即怎么把 Controller 的方法变成了它),

即: mapping 与handlerMethod(处理方法的)关系;

继续看一下源码找到 initHandlerMethods() 方法,这个方法是在这个类创建后调用的,如下所示是它的源码:

 

protected void initHandlerMethods() {

// 从容器中获取所有 Bean 的名称,detectHandlerMethodsInAncestorContexts 默认false,不从父容器中查找

//即默认只查找 SpringMVC 的 IOC 容器,不查找它的父容器 Spring 的 IOC 容器

String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?

BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :

getApplicationContext().getBeanNamesForType(Object.class));

for (String beanName : beanNames) {

// 这里的 isHandler()方法由子类实现,判断是否拥有 @Controller 注解或 @RequestMapping 注解

if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) && isHandler(getApplicationContext().getType(beanName))){

// 利用反射得到 Bean 中的 Method 并包装成 HandlerMethod,然后放入 Map 中

detectHandlerMethods(beanName);

}

}

handlerMethodsInitialized(getHandlerMethods());

}

看完上述代码后,可以知道是在 detectHandlerMethods() 方法中将 Bean 的方法转换为 HandlerMethod 对象,具体实现如下

 

protected void detectHandlerMethods(final Object handler) {

// 获取这个 Bean 的 Class 对象

Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());

// 避免重复调用 getMappingForMethod(),getMappingForMethod() 将重新构建 RequestMappingInfo 实例

final Map<Method, T> mappings = new IdentityHashMap<Method, T>();

// 获取被代理前的原始类型

final Class<?> userType = ClassUtils.getUserClass(handlerType);

// 获取 Method

Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {

@Override

public boolean matches(Method method) {

// 根据 Method 和它的 @RequestMapping 注解,创建 RequestMappingInfo 对象。

// 这里的 T 就是 RequestMappingInfo,它封装了 @RequestMapping 信息

T mapping = getMappingForMethod(method, userType);

if (mapping != null) {

mappings.put(method, mapping);

return true;

} else {

return false;

}

}

});

for (Method method : methods) {

// 注册 Method 和它的映射,RequestMappingInfo 储存着映射信息

registerHandlerMethod(handler, method, mappings.get(method));

}

}

 

最后在 registerHandlerMethod() 方法中,将 RequestMappingInfo 作为 key,把 Method 包装成HandlerMethod 作为 value 添加到了 Map<T, HandlerMethod> handlerMethods 中。

 

protected void registerHandlerMethod(Object handler, Method method, T mapping) {

HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);

HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping);

if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) {

throw new IllegalStateException("");

}

this.handlerMethods.put(mapping, newHandlerMethod);

Set<String> patterns = getMappingPathPatterns(mapping);

for (String pattern : patterns) {

if (!getPathMatcher().isPattern(pattern)) {

this.urlMap.add(pattern, mapping);

}

}

}

 

 

接下来我们接着看看:HandlerAdapter

根据 Handler 来找到支持它的 HandlerAdapter,通过 HandlerAdapter 执行这个 Handler 得到 ModelAndView 对象。HandlerAdapter 接口中的方法如下:

 

HandlerAdapter的接口的方法:

public interface HandlerAdapter {

boolean supports(Object var1);

ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;

 

long getLastModified(HttpServletRequest var1, Object var2);

}

 

该接口的具体的实现类有:

HttpRequestHandlerAdapterSimpleControllerHandlerAdapterAnnotationMethodHandlerAdapter,这个三个类是具体实现HandlerAdapter这个接口的三个类;

1 RequestMappingHandlerAdapter

从上面的文章中可以知道,利用 RequestMappingHandlerMapping 获取的 Handler 是 HadnlerMethod 类型,它代表 Controller 里要执行的方法,而 RequestMappingHandlerAdapter 可以执行 HadnlerMethod 对象。

RequestMappingHandlerAdapter 的 handle()方法是在它的父类 AbstractHandlerMethodAdapter 类中实现的,源码如下所示

 

@Override public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler); }

 

handleInternal() 方法是由 RequestMappingHandlerAdapter 自己来实现的,源码如下所示

 

@Override

protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

// 是否通过 @SessionAttributes 注释声明了 session 属性。

if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {

checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);

} else {

checkAndPrepare(request, response, true);

}

// 是否需要在 synchronize 块中执行

if (this.synchronizeOnSession) {

HttpSession session = request.getSession(false);

if (session != null) {

Object mutex = WebUtils.getSessionMutex(session);

synchronized (mutex) {

// 执行 HandlerMethod

return invokeHandleMethod(request, response, handlerMethod);

}

}

}

// 执行 HandlerMethod,得到 ModelAndView

return invokeHandleMethod(request, response, handlerMethod);

}

 

继续再来看一下如何得到 ModelAndViewinvokeHandlerMethod() 方法如下

 

private ModelAndView invokeHandleMethod(HttpServletRequest request,

HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

//

ServletWebRequest webRequest = new ServletWebRequest(request, response);

// 数据绑定

WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);

ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

// 绑定参数,执行方法

ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);

// 创建模型和视图容器

ModelAndViewContainer mavContainer = new ModelAndViewContainer();

// 设置FlasgMap中的值

mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));

// 初始化模型

modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);

mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

 

AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);

asyncWebRequest.setTimeout(this.asyncRequestTimeout);

 

final WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

asyncManager.setTaskExecutor(this.taskExecutor);

asyncManager.setAsyncWebRequest(asyncWebRequest);

asyncManager.registerCallableInterceptors(this.callableInterceptors);

asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

if (asyncManager.hasConcurrentResult()) {

Object result = asyncManager.getConcurrentResult();

mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];

asyncManager.clearConcurrentResult();

requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);

}

requestMappingMethod.invokeAndHandle(webRequest, mavContainer);

if (asyncManager.isConcurrentHandlingStarted()) {

return null;

}

return getModelAndView(mavContainer, modelFactory, webRequest);

}

 

 

2 HttpRequestHandlerAdapter

HttpRequestHandlerAdapter 可以执行 HttpRequestHandler 类型的 Handler,源码如下

@Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ((HttpRequestHandler) handler).handleRequest(request, response); return null; }

 

3 SimpleControllerHandlerAdapter

SimpleControllerHandlerAdapter 可以执行 Controller 类型的 Handler,源码如下

@Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return ((Controller) handler).handleRequest(request, response); }

 

4 SimpleServletHandlerAdapter 

SimpleServletHandlerAdapter 可以执行 Servlet 类型的 Handler,源码如下

@Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ((Servlet) handler).service(request, response); return null; }

 

ModelAndView resolveException(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex); 

 

springmvc 的请求处理过程(精编)

标签:代码   http   保存   一个   abi   def   工作   接下来   contain   

原文地址:https://www.cnblogs.com/wangdong811/p/10300247.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!