springmvc执行流程 源码分析
浏览器发送一个请求给DispatcherServlet (在doDispatch(request, response)中);DispatcherServlet将请求交给HandleMapping 获取处理器执行链;DispatcherServlet获得执行链中的handle;遍历所有处理器适配器,获得支持handle的具体的适配器;处理器执行链执行前置处理(返回false就不再往下执行);然后由DispatcherServlet将请求、响应和handle交给处理器适配器处理,HandleAdapter执行控制器Controller中具体的方法返回ModelAndView;处理器执行链执行后置处理;通过试图解析器解析准确试图,将模型数组放到request域中渲染试图;将试图返回前端页面。
HandlerMapping接口就一个作用:根据request获取handle和拦截器数组。
概念理解:
handler在这里,是指包含了我们请求的Controller类和 url映射的Method方法的对象。
一个控制器Controller中有内部N个方法== N个Handler
M个控制器=M×N个Handler
M×N个Hanlder存放在handlerMappings中
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return null;
}
进入DispatcherServlet 执行onRefresh,然后执行初始化方法initStrategies。然后调用doService——>doDispatch。
根据继承关系执行Servlet的步骤:
init...............initStrategies
service...........doService
/**
* This implementation calls {@link #initStrategies}.
*/
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
} /**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
/**
* Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
* for the actual dispatching.
*/
@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.
// 保存request中的所有属性
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);
}
}
}
}
/**
* Process the actual dispatching to the handler.
* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
* themselves to decide which methods are acceptable.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
*/
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); // 遍历handlerMappings获取HandlerExecutionChain实例(handle和HandlerInterceptor[])
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
} // Determine handler adapter for the current request.
// 通过 处理器执行链 匹配 处理器适配器 实例
// 获取 处理器执行链 HandlerExecutionChain中 handle,查找并返回支持handle的 处理器适配器HandlerAdapter
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 (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//执行所有自定义的拦截器的preHandle(前置处理)方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
} // Actually invoke the handler.
// 执行handle返回ModelAndView实例
// 使用匹配的 HandlerAdapter 处理请求
// 此处将调用用户自定义的Controller类中的方法
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);
}
}
}
}
AbstractHandlerMapping的 getHandler方法,通过HandlerMapping获取处理器执行链:
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);//获取hangdle
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);
}
//添加拦截器
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
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;
}
springmvc执行流程 源码分析的更多相关文章
- springMvc的执行流程(源码分析)
1.在springMvc中负责处理请求的类为DispatcherServlet,这个类与我们传统的Servlet是一样的.我们来看看它的继承图 2. 我们发现DispatcherServlet也继承了 ...
- Springboot中mybatis执行逻辑源码分析
Springboot中mybatis执行逻辑源码分析 在上一篇springboot整合mybatis源码分析已经讲了我们的Mapper接口,userMapper是通过MapperProxy实现的一个动 ...
- springmvc拦截器入门及其执行顺序源码分析
springmvc拦截器是偶尔会用到的一个功能,本案例来演示一个较简单的springmvc拦截器的使用,并通过源码来分析拦截器的执行顺序的控制.具体操作步骤为:1.maven项目引入spring依赖2 ...
- SpringMVC由浅入深day01_6源码分析(了解)
6 源码分析(了解) 通过前端控制器源码分析springmvc的执行过程. 入口 第一步:前端控制器接收请求 调用doDiapatch 第二步:前端控制器调用处理器映射器查找 Handler 第三步: ...
- Django rest framework 的认证流程(源码分析)
一.基本流程举例: urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^users/', views.HostView.as_view() ...
- (五)myBatis架构以及SQlSessionFactory,SqlSession,通过代理执行crud源码分析---待更
MyBatis架构 首先MyBatis大致上可以分为四层: 1.接口层:这个比较容易理解,就是指MyBatis暴露给我们的各种方法,配置,可以理解为你import进来的各种类.,告诉用户你可以干什么 ...
- springMvc Velocity tool 源码分析
在公司使用pandoraboot配置了velocity tool,一直不明白官方支持的init方法没有调用,而且不支持velocity tool 1.x版本的定义(1.x和2.x的定义见下面),而另一 ...
- Spring Securtiy 认证流程(源码分析)
当用 Spring Security 框架进行认证时,你可能会遇到这样的问题: 你输入的用户名或密码不管是空还是错误,它的错误信息都是 Bad credentials. 那么如果你想根据不同的情况给出 ...
- Spring之SpringMVC的RequestToViewNameTranslator(源码)分析
前言 SpringMVC如果在处理业务的过程中发生了异常,这个时候是没有一个完整的ModelAndView对象返回的,它应该是怎么样处理呢?或者说应该怎么去获取一个视图然后去展示呢.下面就是要讲的Re ...
随机推荐
- 【320】Python 2.x 与 3.x 的区别
通过代码移植的报错进行梳理! 1. print 函数的区别 Python 2.x 中可以加空格或者括号,但是 Python 3.x 只能是括号的 # Python 2.x >>> p ...
- JSTL的基本使用
<body> <% request.setAttribute("name", "lisi123"); request.setAttribute ...
- 快速变幻AABB的顶点
[快速变幻AABB的顶点] 当要变幻一个AABB时,可以快速计算变幻后顶点的AABB.当有旋转时,根据8个顶点变幻后的AABB可能会更大. AABB的八个顶点需分别作如下变幻: 注意到为了使 x' 最 ...
- JAVA-用HttpClient来模拟浏览器GET,POST
一般的情况下我们都是使用IE或者Navigator浏览器来访问一个WEB服务器,用来浏览页面查看信息或者提交一些数据等等.所访问的这些页面有的仅仅是一些普通的页面,有的需要用户登录后方可使用,或者需要 ...
- TOGAF架构培训材料学习总结
作于一个架构师尤其是企业架构师来说,丰富的理论知识可以帮助他在架构规划及管理过程中站在更高的角度去看待问题,历史发展原因有很多已成体系的架构理论,TOGAF是近年来比较接地气的,受到了政府和银 ...
- JavaScript 语法总结2
1. 对象的toString()和valueOf(). - toString() 和Java中的toString() 一样 - valueOf(), 和toString() 都是用来进行类型转换的方法 ...
- About Game Controllers
[About Game Controllers] Game Controller(GC),框架从iOS 7和OS X v10.9开始加入,用于便捷使用控制器(手柄). Once discovered, ...
- msfconsole邮件收集器模块
msfconsole search email collector use auxiliary/gather/search_email_collector show options 下面我们设置域名. ...
- mysql 开通远程连接
使用localhost好用,但是改成ip地址后不好用,执行sql语句做如下修改: update user set host = '%' where user = 'root'; flush privi ...
- linux每天一小步---rm命令详解
1 命令功能 rm命令用于删除文件或者目录,值得注意的是linux下的删除不弯曲等同于windows系统下的删除操作,linux系统下一旦删除了文件或者目录那么它将消失,而windows系统下我们还可 ...