springboot+thymeleaf modelandview解析异常_Springboot中MVC学习笔记

依赖组件spring-boot-starter-web和servlet3.0等;

0db33f4f7fa6e2a00ff935ad9bf60324.png

DispatchServlet注入容器和服务器

了解servlet或者filter是怎么注入spring容器的,最典型例子莫过于DispatchServlet;这里并不说明传统的web.xml配置的方式,而主要是springboot推荐的自动配置,具体在DispatcherServletAutoConfiguration类;
851648a788a779bf04a43b8219f35930.png

@AutoConfigureAfter(EmbeddedServletContainerAutoConfiguration.class)主要是servlet容器的配置,由项目的classpath决定用tomcat、jetty或者undetow等;@ConditionalOnClass(DispatcherServlet.class)主要是要求DispatchServlet必须存在才能将继续解析这个Bean,即加入了spring-boot-starter-web依赖;

以上只是DispatcherServletAutoConfiguration自动配置的先决条件,接下来是代码内部一些Bean的注入;

eee34f516d1237bba0d0a88575183ea1.png

以上代码包含了spring mvc需要的核心DispatcherServlet,他会随着tomcat启动注入到ServletContext;webMvcProperties就是我们在application.yml里面配置的参数;

e409e2f361989fed64448fd50a2d360f.png

以上代码是对DispatcherServlet的包装;由于一个web application包括很多servlet和filter,容器需要通过查找符合类型的Bean,并提取servlet注入到ServletContext,其中就包括了ServletRegistrationBean和实现了Servlet接口的Bean; ServletRegistrationBean包括了传统web.xml需要配置的参数;

类似还有FilterRegistrationBean、ServletListenerRegistrationBean和DelegatingFilterProxyRegistrationBean等;

除了reactive,springboot 容器主要是 AnnotationConfigServletWebServerApplicationContext类,而在容器refresh过程中,当BeanDefination注入spring容器后会调用子类的onRefresh方法,实现web server的创建和servlet的注入;

6e7e2bdb79bde67f94da843c591c0651.png

以上代码是AbstractApplicationContext子类ServletWebServerApplicationContext.onRefresh方法启动服务器的过程;

ServletWebServerFactory factory = getWebServerFactory()主要是根据环境依赖产生提供tomcat server或者其它server的工厂;

getSelfInitializer方法用于取得spring容器当中实现ServletContextInitializer接口的Bean;

6718219daa2068b9ce56acc43adc1ddb.png

以上代码显示了服务器创建以后,将spring上下文保存在ServletContext形成web特性的容器;调用getServletContextInitializerBeans方法创建ServletContextInitializerBeans;ServletContextInitializerBeans初始化时调用addServletContextInitializerBeans方法将RegistrationBean的子类如ServletRegistrationBean等(DispatchServlet的包装类)加入到ServletContextInitializer队伍;调用addAdaptableBeans方法将普通的servlet和filter等也通过RegistrationBean包装加入到需要onStartup的队伍;代码如下;

f9b7e1fe76e0518b6c38f71a8249bf29.png
a6fd5c090557b376870e364f25ba2310.png

接着调用ServletContextInitializer实现类的onStartup方法,注册servlet和filter等;由于ServletRegistrationBean既包含了需要注册servlet实体又实现了ServletContextInitializer接口,它只需要传入ServletContext就可以注册自身;

WebMvcAutoConfiguration的自动装配

DispatcherServlet接受请求,需要将路径和对应的Controller映射,然后返回资源给客户端; WebMvcAutoConfiguration的作用正是装配DispatcherServlet需要的Bean,它包括了:EnableWebMvcConfiguration、WebMvcAutoConfigurationAdapter等内部类;

EnableWebMvcConfiguration主要是装配RequestMappingHandlerMapping、RequestMappingHandlerAdapter、ExceptionHandlerExceptionResolver;

RequestMappingHandlerMapping的作用是让DispatcherServlet调用HandlerMapping.getHandler根据请求解析出Controller对应的HandlerMethod和Interceptor;

d3378856f3b33e03b0dc7651cfe3293e.png

RequestMappingHandlerMapping的父类AbstractHandlerMethodMapping实现了接口InitializingBean,在触发afterPropertiesSet的时候会调用initHandlerMethods方法解析具有Controller或者RequestMapping注解的Bean,利用反射拾取其中包含RequestMapping注解的方法,将它们注册到MappingRegistry变量,形成url和HandlerMethod的映射;

50109171cdee63c5894c1910a84c6dba.png

RequestMappingHandlerMapping的父类AbstractHandlerMapping实现了接口HandlerMapping,方法getHandler根据HttpServletRequest请求解析出对应的Interceptor和HandlerMethod,将其封装在HandlerExecutionChain,而HandlerMethod则封装了需要执行的目标对象的方法和方法参数等信息;

RequestMappingHandlerAdapter的主要作用是让DispatcherServlet调用HandlerAdapter.handle处理HandlerMethod的调用和返回ModelAndView;

RequestMappingHandlerAdapter实现了InitializingBean接口,在afterPropertiesSet方法触发的时候会执行: 1、调用initControllerAdviceCache, 拾取具有ControllerAdvice的注解的Bean放入局部变量;2、设置各种HandlerMethodArgumentResolver到局部变量,它们用于将请求参数转变成为执行HandlerMethod即Controller方法需要的MethodParameter参数;

RequestMappingHandlerAdapter的父类AbstractHandlerMethodAdapter实现了接口HandlerAdapter,接口方法handle会调用子类的handleInternal方法,利用反射对HandlerMethod进行调用并返回ModelAndView;

ExceptionHandlerExceptionResolver的作用是当DispatchServlet捕获异常后,交由给具有ExceptionHandler注解的方法处理异常,并定向到错误视图;

WebMvcAutoConfigurationAdapter主要是装配ViewResolver,设置资源处理策略;

Resolver的作用是根据返回的ModelAndView查找资源,处理视图;springboot自动装载了InternalResourceViewResolver、BeanNameViewResolver、ContentNegotiatingViewResolver,可以重写或者添加自己的ViewResolver以适应业务需求;对于资源处理,如果用户没自定义修改application.yml或者重写addResourceHandlers方法,程序将默认使用WebMvcProperties和ResourceProperties中的默认值,即/**和ResourceProperties.CLASSPATH_RESOURCE_LOCATIONS;

EableWebMvcConfiguration的祖父类WebMvcConfigurationSupport实际上已经具备了一个MVC需要的基本组件,包括各种资源mapping和adapter等;当我们需要自定MVC配置的时候,只需要继承WebMvcConfigurationSupport并加上EnableWebMvc注解即可;

WebMvcConfigurationSupport提供了addInterceptors和addResourceHandlers等模板方法给用户,用于实现自定义拦截器和静态资源访问策略;

55ee545c4ae0a16be23cb109392f7f39.png
32ff089a53669b0766e6318c5a4263ba.png

viewControllerHandlerMapping方法用于创建处理简单Controller需要的SimpleUrlHandlerMapping;addViewControllers方法提供给用户注入url和Controller的关系映射;

47f496bb2fe8794457cb58e8a7895c20.png

resourceHandlerMapping方法用于创建一个处理静态资源的HandlerMapping;

DispatchServlet的初始化

DispatcherServlet注册到spring容器后需要初始化才能接受服务,包括HandlerMapping、HandlerAdapter、ViewResolver等;DispatcherServlet的父类是FrameworkServlet,而FrameworkServlet的父类是HttpServletBean;

因为FrameworkServlet实现了ApplicationContextAware接口,在spring容器初始化完成以后会调用setApplicationContext方法将上下文(对于springboot程序实际可能是AnnotationConfigServletWebServerApplicationContext)赋值给FrameworkServlet的webApplicationContext变量;

HttpServletBean的init方法是初始化的方法,它会调用FrameworkServlet.initServletBean方法,而initServletBean内部则会调用initWebApplicationContext方法创建化Web环境下需要的WebApplicationContext上下文;由于此前webApplicationContext已经被赋值,createWebApplicationContext不会再次执行;

4dc82849dd1de90cab5c733c9ced6284.png

接着调用模板方法onRefresh执行子类DispatcherServlet的initStrategies方法,初始化的各种选项;这些选项已经由WebMvcAutoConfiguration自动装配并载入spring容器;

9ad9dcf53c8504de4f49040311e01d82.png

DispatcherServlet处理业务的核心方法是doDispatch,它由Servlet的方法doService调用;对于一个Http请求,MVC主要处理流程如下:

调用checkMultipart方法,交由MultipartResolver.resolveMultipart处理请求并判断一个HttpServletRequest是否包含文件上传;

调用getHandler方法,遍历HandlerMapping的集合解析HttpServletRequest请求查找适合的HandlerExecutionChain,如果不能找到则返回错误代码404;由于MVC会默认自动配置ErrorMvcAutoConfiguration,当请求找不到HandlerMapping的时候,程序会转向/error路径,这个路径会匹配到BasicErrorController.errorHtml,用户可以定义自己的error.html显示错误信息;

调用getHandlerAdapter方法,遍历HandlerAdapter的集合选择支持handler的HandlerAdapter;例如HandlerExecutionChain的handler类型如果是HandlerMethod则返回RequestMappingHandlerAdapter,如果是Controller则返回SimpleControllerHandlerAdapter,如果是HttpRequestHandler则返回HttpRequestHandlerAdapter等;

调用HandlerExecutionChain的applyPreHandle方法,遍历当中的拦截器的preHandle方法,如果返回为false则返回;

调用HandlerAdapter的handle方法,由具体的HandlerAdapter处理需要执行的业务方法,处理结束返回ModelAndView;以 RequestMappingHandlerAdapter为例子,它的invokeHandlerMethod方法将利用HandlerMethod封装的信息,取得目标的对象及其需要执行的方法,将request当中取得请求参数转变为需要正确的方法参数,反射执行;

8d84048a426ad8faae596488f0b0d9a7.png

调用HandlerExecutionChain的applyPostHandle方法,遍历当中的拦截器的postHandle方法;

调用processDispatchResult方法处理View;如果以上过程产生了异常,则调用processHandlerException方法,将异常交给HandlerExceptionResolve.resolveException处理,并返回ModelAndView;如果前面没有异常发生,则调用render方法,从配置的ViewResolver列表中查找View,由具体的View渲染视图给客户端;

8bc8055999784b951e1414fc5c0a141e.png

如果请求包括文件上传,最后需要调用cleanupMultipart方法做一些Multipart清理,减少资源浪费;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值