当前位置: 首页 > news >正文

Spring MVC 五:DispatcherServlet初始化之 mvc:annotation-driven

通过xml方式初始化DispatcherServlet时,xml文件中可以配置:

<mvc:annotation-driven />

或:

   <mvc:annotation-driven ><!--设置响应输出字符集--><mvc:message-converters><bean class="org.springframework.http.converter.StringHttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/html;charset=utf-8</value></list></property></bean></mvc:message-converters></mvc:annotation-driven>

表示对MVC注解的支持。

该标签的解析工作最终会由AnnotationDrivenBeanDefinitionParser的parse方法完成,parse方法主要完成以下工作

  1. 注册RequestMappingHandlerMapping的beanDefinition到WebApplication容器
  2. 注册RequestMappingHandlerAdapter的beanDefinition到WebApplication容器,同时从xml文件解析其messageConverters的定义(这也是xml文件中messageConverters生效的原因)
  3. 注册ExceptionHandlerExceptionResolver的beanDefinition到WebApplication容器
  4. 注册ResponseStatusExceptionResolver的beanDefinition到WebApplication容器
  5. 注册DefaultHandlerExceptionResolver的beanDefinition到WebApplication容器

之后在容器refresh的过程中根据beanDefinition创建对应的bean。

之后,在DispatcherServlet初始化的过程中,通过initStrategies初始化SpringMVC的相关“特殊类型的Bean”:

	protected void initStrategies(ApplicationContext context) {initMultipartResolver(context);initLocaleResolver(context);initThemeResolver(context);initHandlerMappings(context);initHandlerAdapters(context);initHandlerExceptionResolvers(context);initRequestToViewNameTranslator(context);initViewResolvers(context);initFlashMapManager(context);}

比如initHandlerMappings方法:

private void initHandlerMappings(ApplicationContext context) {this.handlerMappings = null;if (this.detectAllHandlerMappings) {// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.//首先通过beanFactoryUtils从Spring容器中,通过类型获取Map<String, HandlerMapping> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);//如果从容器中获取到了bean,放入到handlerMappings中if (!matchingBeans.isEmpty()) {this.handlerMappings = new ArrayList<>(matchingBeans.values());// We keep HandlerMappings in sorted order.AnnotationAwareOrderComparator.sort(this.handlerMappings);}}else {try {//通过名字和类型从容器获取HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);this.handlerMappings = Collections.singletonList(hm);}catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default HandlerMapping later.}}// Ensure we have at least one HandlerMapping, by registering// a default HandlerMapping if no other mappings are found.if (this.handlerMappings == null) {//从容器中没有获取到,才调用getDefaultStrategies获取默认的、dispatcherServlet.properties文件中定义的this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);if (logger.isTraceEnabled()) {logger.trace("No HandlerMappings declared for servlet '" + getServletName() +"': using default strategies from DispatcherServlet.properties");}}}

如果xml文件中不配置<mvc:annotation-driven />,也没有 <mvc:default-servlet-handler />,则Spring容器中就不会有对应的bean,这种情况下,才通过调用getDefaultStrategies方法,读取DispatcherServlet.properties文件获取该文件定义的默认HandlerMappings,完成创建,当然,创建后也会放入Spring容器:

	protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {return context.getAutowireCapableBeanFactory().createBean(clazz);}
DefaultServletHandlerBeanDefinitionParser

xml文件中如果配置了 <mvc:default-servlet-handler />,SpringMVC启动时解析 <mvc:default-servlet-handler />标签过程中会调用DefaultServletHandlerBeanDefinitionParser,其parse方法会将SimpleUrlHandlerMapping以及BeanNameUrlHandlerMapping注入到WebApplicationContext容器中,目的是通过SimpleUrlHandlerMapping来处理"/**"请求(转交给DefaultServletHttpRequestHandler)。

这个处理有个副作用:由于SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping作为handlerMappings注入到容器中,分析DispatcherServlet的初始化方法initHandlerMappings的源码可知:DispatcherServlet.properties文件中默认的RequestMappingHandlerMapping不会被注入!而RequestMappingHandlerMapping是具体负责SpringMVC注解解释的,没有了RequestMappingHandlerMapping,类似@Controller等SpringMVC注解就不会生效。

所以,其实SpringMVC默认情况下天生是可以支持SpringMVC注解的,只不过是 <mvc:default-servlet-handler />往往不可避免的需要配置(因为项目中总有静态资源需要展示),但是加了 <mvc:default-servlet-handler />会导致SpringMVC的注解失效!

因此导致了,正常的SpringMVC项目的以下两项配置往往需要成对出现:

 <mvc:annotation-driven /><mvc:default-servlet-handler />

上一篇 Spring MVC 十:异常处理

http://www.lryc.cn/news/189055.html

相关文章:

  • uniapp EventChannel 页面跳转参数事件传递navigateBack,navigateTo 成功后通知事件区别
  • 【C++ Primer Plus学习记录】指针——使用delete释放内存
  • 2023 NOIP A层联测9 - 风信子 题解
  • 岩土工程安全监测无线振弦采集仪在无线组网的关键要点
  • 代码随想录Day14 LeetCodeT110平衡二叉树 T257二叉树的所有路径 T404 左叶子之和
  • C语言自定义类型_枚举联合(3)
  • asp.net网上销售系统VS开发mysql数据库web结构c#编程Microsoft Visual Studio计算机毕业设计
  • 【Windows】RPC调用过程实例详解
  • 动手学强化学习第2章多臂老虎机
  • 钡铼BL124EC实现EtherCAT转Ethernet/IP的优势
  • 使用IntelliJ Idea必备的插件!
  • 代码随想录算法训练营第23期day19| 654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树
  • 第四章 字符串part02 28. 实现strStr() 459. 重复的子字符串
  • 设计模式 - 状态模式
  • 【vim 学习系列文章 9 -- .vim 脚本文件开发学习】
  • NAT模式和桥接模式的区别
  • 应对出海安全合规挑战,兆珑科技为什么选择了亚马逊云科技?
  • Allegro基本规则设置指导书之Spacing规则设置
  • 使用【Blob、Base64】两种方式显示【文本、图片、视频】 使用 video 组件播放视频
  • 深度学习_1_基本语法
  • c#设计模式-行为型模式 之 中介者模式
  • 小程序uView2.X框架upload组件上传方法总结+避坑
  • 人脸检测及追踪回顾
  • 虚拟环境和包
  • springboot配置文件读取
  • 纵享丝滑!Cesium + ffmpegserver 生成高质量动态视频【逐帧生成】
  • Linux下C++编程-进度条
  • C语言常见题目(1)交换两个变量的值,数的逆序输出,猜数游戏,两个数比较大小等
  • Springboot使用sqlcipher4加密sqlite数据库
  • 指针拔尖(2)(巩固提高,全网最牛,包会,看不懂带电脑来找我)