java前端控制器如何处理请求_HTTP请求处理流程-SpringMvc

1、在SpringMVC的http请求处理过程中,包括了前端控制器(DispatcherServlet)、处理映射器(HandlerMapping)、处理适配器(HandlerAdapter)、处理器((Handler)Controller)、视图解析器(ViewReslover)、视图(View)这六大主要对象。他们负责对http请求做处理,具体流程如下图。

5165cba4c6be4e6de5eb7d2b294d0405.png

第一步:前端控制器dispatcher接受请求

Client---url--->Dispatcher

第二步:前端控制器去发起handler映射查找请求

Dispatcher---HttpServletRequest---> HandlerMapping

第三步:处理器映射器查找hanlder并返回HandlerExetuionChain

Dispatcher

第四步:前端控制器发起请求处理器适配器请求执行

Dispatcher---Handler---> HandlerAdapter

第五步:处理器适配器去调用handler执行

HandlerAdapter---HttpServletRequest> Handler(Controller)

第六步:处理器处理后返回ModelAndView给HandlerAdapter

HandlerAdapter 

第七步:处理器适配器将ModelAndView返回给前端控制器

Dispatcher

第八步:前端控制器请求视图解析器解析ModelAndView

Dispatcher---ModelAndView---> ViewReslover

第九步:视图解析器解析视图后返回视图View给前端控制器

Dispatcher

第十步:前端控制器请求视图要求渲染视图

Dispatcher--->View--->render

第十一步:前端控制器返回响应

Response

源码探秘

第一步接受请求:

我们可以来看看DispatcherServlet的继承结构

07c4f4e899a5545550349a873c29a521.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

其实DispatcherServlet能处理请求是因为HttpServlet类的service方法,而HttpServlet又来自Servlet接口定义的规范。

c906d0ec648e8ecbc6fad9d6a889770b.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

可以看到抽象类HttpServlet实现了接口Servlet的service方法,根据请求类型不同执行了不同的方法(doGet,doPost)

607f97ca05cbfdff87c7a37dc575c4a6.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

当请进来后,由HttpServlet的子类FrameworkServlet重写的service方法执行请求,可以看到437行子类调用了父类的service方法,然后在父类执行doGet之类的方法时,由于子类FrameworkServlet重写了父类方法,交由子类执行,所以进到了我的doGet断点里面,它调用了处理请求方法。

接下来我们看看ProcessRequest方法的源码

protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

long startTime = System.currentTimeMillis();

Throwable failureCause = null;

LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();

LocaleContext localeContext = this.buildLocaleContext(request);

RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();

ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor(null));

this.initContextHolders(request, localeContext, requestAttributes);

try {

this.doService(request, response);

} catch (IOException | ServletException var16) {

failureCause = var16;

throw var16;

} catch (Throwable var17) {

failureCause = var17;

throw new NestedServletException("Request processing failed", var17);

} finally {

this.resetContextHolders(request, previousLocaleContext, previousAttributes);

if (requestAttributes != null) {

requestAttributes.requestCompleted();

}

this.logResult(request, response, (Throwable)failureCause, asyncManager);

this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);

}

}

前面一系列初始化工作我们先不管,看看重要的部分,try里面的doService方法

6218d7888d81766304a7892d91203844.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

跟踪进去看了一下,由于它是抽象方法,所以会由子类实现和执行,也就是我们的DispatchServlet类了

572dca80ff4171b3128bd30647ea5301.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

老规矩,先贴上源码,它是DispatchServlet的doService方法--------------------------------------------------------------------------------------------------------------

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {

this.logRequest(request);

Map attributesSnapshot = null;

if (WebUtils.isIncludeRequest(request)) {

attributesSnapshot = new HashMap();

Enumeration attrNames = request.getAttributeNames();

label95:

while(true) {

String attrName;

do {

if (!attrNames.hasMoreElements()) {

break label95;

}

attrName = (String)attrNames.nextElement();

} while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));

attributesSnapshot.put(attrName, request.getAttribute(attrName));

}

}

request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());

request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);

request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);

request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());

if (this.flashMapManager != null) {

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 {

this.doDispatch(request, response);

} finally {

if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {

this.restoreAttributesAfterInclude(request, attributesSnapshot);

}

}

}

所以第一步也就完成了,第一步的任务就是走进这里来。

第二步:前端控制器去发起handler映射查找请求

Dispatcher---HttpServletRequest---> HandlerMapping

上面的源码中主要工作就是给request实例设置一系列参数,要注意的就是doDispatch方法,这里面就是mvc的核心了,前面第一张交互图里面的流程都是在这里实现的。

5e0a36dc21f28e34f85bb0101b8ef304.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

可以看到,通过HttpRequestServlet作为参数请求handlerMapping

第三步:处理器映射器查找hanlder并返回HandlerExetuionChain

Dispatcher

可以看到上图中返回了mappedHandler变量,就是HandlerExtuceChain类型

e566ee1edb22c77d7213b7ca060cca8f.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

可以看到,已经找到并返回了我们的HomeController处理器(Hanlder)

第四步:前端控制器发起请求处理器适配器请求执行

Dispatcher---Handler---> HandlerAdapter

c1841fae783ac8a52376ad730e632dee.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

从508行可以看到,适配器传入handler对象和reaquest等信息,执行handler()方法

第五步:处理器适配器去调用handler执行

HandlerAdapter---HttpServletRequest> Handler(Controller)

ba9114684b91d6390551ae185c3daa9a.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

从这里可以看到,调用的handlerInternal是个抽象方法,会调用子类的实现方法,子类由RequestMappingHandlerAdapter实现,这个类也是我们经常在xml里面配置的类

28281e94ee790040eda89e1d09327023.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

通过invokeHandlerMethod方法执行进到controller里面

291137c5e09c2d68ff9fb6a910432518.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

方法执行后返回我们的index

45fe01b3ff70b4c8672a5ca02e3dade5.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

第六步:处理器处理后返回ModelAndView给HandlerAdapter

HandlerAdapter 

通过调用invokeHandlerMethod方法返回ModelAndView

ed2fd8185445483fd9cdfcadba1782de.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

第七步:处理器适配器将ModelAndView返回给前端控制器

Dispatcher

fc47ff23b39f84308ea900c0a6c2037a.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

第八步:前端控制器请求视图解析器解析ModelAndView

Dispatcher---ModelAndView---> ViewReslover

37fa233c0bef3b9a31f5351b14ec3df0.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

第九步:视图解析器解析视图后返回视图View给前端控制器

Dispatcher

fb2c7e2b37a81e80f171a3d0efcb9316.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

可以看到,返回的视图,url指向index.jsp页面

第十步:前端控制器请求视图要求渲染视图

Dispatcher--->View--->render

如果View对象不为空,将会调用render方法渲染

526886d5145a77aeb85d0103b24e16b1.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

如果返回的是json对象,属于接口的,是不会走这里的

f8f31e77240ce34657bbeb0f65ccbd5e.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

此时会找对应的视图解析器去渲染

bb47c8ce5c8e819013d3bb5f79cdc523.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

里面其实也没干啥,就做了个跳转,到jsp页面去绑定数据

ac41eaeea9e437194e3acede4265d246.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

第十一步:前端控制器返回响应

Response

56eb302b30316d9b2c8bc457662f7155.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

到这里也就基本上完了。

17022b103c4031cce72ae211ccb7ab00.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

处理请求完成后做了个重置工作,然后发布一个事件,你可以选择监听这个事件,做相应处理。

再看看response里面

b4b3bff6569c54f75d4479e6ff21965f.pngwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

这个就是我们页面上的内容了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值