springmvc流程_基于Spring MVC框架的Http流程分析

一、问题提出

我们可以方便的利用Spring MVC进行业务开发,请求的大部分工作都被框架和容器封装,使得我们只需要做很少量的工作。但是整个http请求流程是怎么样的?Spring MVC框架在其中起到什么作用?它是怎么和Web容器进行交互的?Controller中的一个方法怎么被暴露出来提供http请求服务的?本着这些想法,我们对整个http请求过程进行讨索。全文以 spring-mvc-demo 为例

二、整体处理流程概述

整个过程包括三部分:应用启动、请求路由与处理、请求返回。

应用启动:web容器初始化(context建立等)、应用初始化(初始化handlerMap)。

请求路由与处理:请求路由(根据url找到Context、根据context找到dispatcherServlet、根据url找到handler、根据url找到handler的方法)、method反射调用获取ModelAndView。

请求返回:逻辑视图到物理视图的转换、物理视图的渲染、视图返回。

具体流程如下:

4ffd0737ec6ace79e01e785844f6d460.png

系统启动:

1、web容器自己去将contextPath、docBase设置到一个context里面,这里面的一个context就是对应一个web应用。

2、web容器会根据docBase的值去获取web.xml,并解析它来获取servlet信息,并设置web容器启动完毕的监听器。

3、web容器启动后,会触发spring mvc容器的启动,spring mvc容器启动时,会解析controller,并将@RequestMapping、@GetMapping、@PostMapping的值设置到handlerMap中,方便后续请求路由。

请求发送:

1、外部发送请求( http://localhost:8080/spring-mvc-demo/user/register )时,请求会被转发到web容器(这里以tomcat为例),实际上就是tomcat与客户端建立了socket链接。

2、根据url,tomcat会对应的host,host找到context,context找到对应的servlet(这里为dispatcherServlet)。

3、dispatcherServlet会根据url,在handlerMap中去查到到对应的handler,然后将handler转化为handlerAdapter。

4、AnnotationMethodHandlerAdapter会调用ServletHandlerMethodInvoker.invokeHandlerMethod方法,ServletHandlerMethodInvoker会通过反射的方式去调用controller的对应方法。

请求返回:

1、根据controller的返回,获取对应的ModelAndView。

2、DispatcherServlet的resolveViewName方法会将逻辑视图转换为物理视图。

3、org.springframework.web.servlet.view.AbstractView#render方法会进行视图渲染工作,具体的渲染视图为org.springframework.web.servlet.view.JstlView

4、jsp文件会被编译成一个servlet,然后,jspServlet会调用service方法,最后会将视图写到客户端。

三、系统启动

1、context设置

我们通过shell脚本调用gradle的tomcatRun方法来启动应用,然后在本地debug的方式来获取运行参数。在org.apache.catalina.startup.Tomcat#addWebapp(org.apache.catalina.Host, java.lang.String, java.lang.String)的方法上打断点,获取信息如下:

85322275c1e778b604863592a14814bc.png

这里的listener为ContextConfig,它会监听容器相关事件,其中一项工作就是监听tomcat启动后去解析web.xml。也可以看出contextPath、docBase的值。

被调用的addWebapp方法就是初始化context,并将context添加到host中。具体如下:

public Context addWebapp(Host host, String contextPath, String docBase, LifecycleListener config) { silence(host, contextPath); Context ctx = createContext(host, contextPath); ctx.setPath(contextPath); ctx.setDocBase(docBase); ctx.addLifecycleListener(new DefaultWebXmlListener()); ctx.setConfigFile(getWebappConfigFile(docBase, contextPath)); ctx.addLifecycleListener(config); if (config instanceof ContextConfig) { // prevent it from looking ( if it finds one - it'll have dup error ) ((ContextConfig) config).setDefaultWebXml(noDefaultWebXmlPath()); } if (host == null) { getHost().addChild(ctx); } else { host.addChild(ctx); } return ctx; }

2、context中servlet设置

通过在ContextConfig的lifecycleEvent方法是监听系统事件的入口:

public void lifecycleEvent(LifecycleEvent event) { // Identify the context we are associated with try { context = (Context) event.getLifecycle(); } catch (ClassCastException e) { log.error(sm.getString("contextConfig.cce
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值