【springMVC源码分析】SpringMVC工作流程

SpringMVC工作流程如图:

可以看到DispatcherServlet是一个核心类,充当分发器的角色,它的继承关系如下图:

可以看出DispatcherServlet继承自Framework,继承自HttpServletBean,继承自HttpServlet。

所以DispatcherServler是一个Servlet。可由Servlet容器调用执行。

 

用源码解释流程图:

1、用户的请求会被tomcat发送到DispatchServlet

请求是如何经过tomcat到达servlet的参考:https://blog.csdn.net/sumengnan/article/details/111504047

2、dispatchServlet会先去查询处理器映射器,并返回处理器执行链(里面包含拦截器和handler)

到达servlet后最终会执行到doDispatch方法

getHandler方法内容如下:根据一开始初始化获取的handlerMapping挨个去找合适的处理器映射器

挨个调用handlerMapping各实现类的getHandlerInternal方法,如图:

试着能否解析出处理器Handler,如果能则继续往下执行,封装HandlerExecutionChain执行链并返回

通过new HandlerExecutionChain创建执行链,在通过addInterceptor添加拦截器,如图:

handlerMapping有多种实现类,分别用来处理不同的映射配置方式

例如:

  • BeanNameUrlHandlerMapping :xml中bean标签配置处理器方法。例如:<bean id="aController" name="/a.action" class="com.xxx.simpleController"/>
  • SimpleUrlHandlerMapping:xml中bean配置的urlMap属性来实现请求URL到控制器(controller handler bean)的映射。<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><property name="urlMap"><map><entry key="a.action" value-ref="aController"/></map></property></bean>
  • RequestMappingHandlerMapping :用来处理@RequestMapping注解的处理器方法

  你也可以自定义处理器映射器HandlerMapping,但是要注意Order顺序(实现Order接口或@Order注解)

3、dispatchServlet去查询对应的处理器适配器,由处理器适配器调用自定义的controller(有拦截器先执行拦截器before方法),并返回ModelAndView对象(里面包含了逻辑视图),再执行拦截器post方法

继续在doDispatch方法向下执行到getHandlerAdapater方法

getHandlerAdapter方法内容如下:根据一开始初始化获取的handlerAdapter挨个去找合适的处理器适配器

HandlerAdapter接口有多种实现类如下:分别用来调用不同的Handler

例如:

  • HttpRequestHandlerAdapter 用来调用实现了HttpRequestHandler接口的controller
  • SimpleControllerHandlerAdapter  用来调用实现了Controller接口的controller
  • RequestMappingHandlerAdapter  用来调用@RequestMapping注解的controller

常用的就这三种,其他的有兴趣可以试试。

SpringMVC实现控制器controller的三种方式?

1、实现Controller接口(返回值为ModelAndView)

2、实现HttpRequestHandler接口(无返回值

3、@Controller或@RestController注解

如果想自定义Adapter来调用controller,可以实现HandlerAdapter接口,但是要注意Order顺序(实现Order接口或@Order注解)

调用拦截器的时机如下图:

这里还有一个关键点,就是当使用注解@RequestMapping时,反射调用的参数是如何解析的?

参考:https://blog.csdn.net/sumengnan/article/details/113774179

4、dispatchServlet去查询对应的视图解析器,并返回View(真实的视图)

继续在doDispatch方法向下执行到processDispatchResult方法

继续往下走,如果handler返回了mv视图,则会进入render方法,进行渲染操作,否则跳过

如果ModelAndView对象中设置了逻辑视图viewName的名字,则去查找对应的视图解析器,并返回view对象

ViewResolver视图解析器接口的实现类如下:

View视图接口的实现类如下:

5、渲染View,之后执行拦截器After方法

继续往下走,调用view接口的render渲染方法

执行拦截器after方法

6、返回用户

MVC自定义配置

三种方法:

  1. 实现WebMvcConfigurer接口 
  2. 继承WebMvcConfigurerAdapter类 (已过时)
  3. 继承WebMvcConfigrutionSupport类

当springboot环境时,最好不要继承WebMvcConfigrutionSupport类。因为springboot自动配置类WebMvcAutoConfiguration有@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)注解,springboot就不会帮我们自动配置了,我们还需要手动配置各个组件,如ResourceHandlers 否则会导致访问静态资源的时候出现404

WebMvcConfigurer接口各方法解释,参考:https://blog.csdn.net/sumengnan/article/details/109064789

1、2、实现WebMvcConfigurer接口和继承WebMvcConfigurerAdapter类,其实是个效果,只是第二个过时了而已。

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/nihao").setViewName("success");
    }
    //……其他方法
}

3、继承WebMvcConfigrutionSupport类

@Configuration
class MyMvcConfig extends WebMvcConfigurationSupport {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/nihao").setViewName("success");
    }
    //……其他方法
}

扩展:

当我们是springboot环境时,可以在application.protires中配置如下内容:

# SPRING MVC
spring.mvc.locale=en_UK
spring.mvc.date-format=yyyy-MM-dd

 其实最终也是使用的继承WebMvcConfigrutionSupport类的方式注册的配置。

springboot把我们的配置封装进WebMvcProperties类中

 

猜你喜欢

转载自blog.csdn.net/sumengnan/article/details/105381225