SpringBoot——MVC原理

优质博文:IT-BLOG-CN

一、SpringMVC自动配置

SpringMVC auto-configurationSpringBoot自动配置好了SpringMVC。以下是SpringBootSpringMVC的默认配置:[WebMvcAutoConfiguration]
【1】包括ContentNegotiatingViewResolverBeanNameViewResolver如下:

@Bean
@ConditionalOnBean({ViewResolver.class})
@ConditionalOnMissingBean(name = {"viewResolver"},value = {ContentNegotiatingViewResolver.class}
)
//存在于 WebMvcAutoConfiguration.java
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));resolver.setOrder(-2147483648);return resolver;
}//进入ContentNegotiatingViewResolver对象,查找解析视图的方法resolveViewName()
public View resolveViewName(String viewName, Locale locale) throws Exception {RequestAttributes attrs = RequestContextHolder.getRequestAttributes();Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());if(requestedMediaTypes != null) {//获取候选的视图对象List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);//选择最适合的视图对象View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);if(bestView != null) {return bestView;}
}//进入上面的getCandidateViews()方法,查看获取的视图解析器,发现SpringBoot是将所有的视图解析器获取到viewResolvers,挨个遍历获取。
private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes) throws Exception {List<View> candidateViews = new ArrayList();Iterator var5 = this.viewResolvers.iterator();while(var5.hasNext()) {

【2】自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染(转发?重定向?))
【3】ContentNegotiatingViewResolver:组合所有的视图解析器的;

//进入ContentNegotiatingViewResolver发现初始化视图解析器的时候,是从容器中BeanFactoryUtils获取所有的视图解析器。
protected void initServletContext(ServletContext servletContext) {Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.getApplicationContext(), ViewResolver.class).values();if(this.viewResolvers == null) {

【4】如何定制:我们可以自己给容器中添加一个视图解析器;自动的将其组合进来;

 @Bean@ConditionalOnProperty(prefix = "spring.mvc", name = "date‐format")//在文件中配置日期格式化的规则public Formatter<Date> dateFormatter() {        return new DateFormatter(this.mvcProperties.getDateFormat());//日期格式化组件            } //举个栗子如下:
//可以自定义一个视图解析器,放入容器,springboot就会自动识别,继承viewreserve
@Bean
public MyView myView(){return new MyView();
}
//需要实现ViewResolver接口
private static class MyView implements ViewResolver{@Overridepublic View resolveViewName(String s, Locale locale) throws Exception {return null;}
}

【5】服务对静态资源的支持,静态资源文件夹路径,webjars等。静态首页访问,自定义favicon.ico 图标文件的支持。
【6】自动注册了of Converter,GenericConverter,Formatter beans
 ○ Converter:转换器; public String hello(User user):类型转换使用ConverterStringint等等。
 ○ Formatter 格式化器; 2017.12.17===Date,源码如下:可以看到格式可以通过spring.mvc.date-format调整。

@Bean
@ConditionalOnProperty(prefix = "spring.mvc",name = {"date-format"}
)
public Formatter<Date> dateFormatter() {return new DateFormatter(this.mvcProperties.getDateFormat());
}

 ○ 自己添加的格式化器转换器,我们只需要放在容器中即可,上面代码块有演示。
【7】支持HttpMessageConverters
 ○ HttpMessageConverterSpringMVC用来转换Http请求和响应的;UserJson方式写出去;
 ○ HttpMessageConverters是从容器中确定;获取所有的HttpMessageConverter
 ○ 自己给容器中添加HttpMessageConverter,只需要将自己的组件注册容器中[@Bean,@Component]
【8】自动注册MessageCodesResolver,定义错误代码生成规则。自动使用ConfigurableWebBindingInitializer类;

protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {return (ConfigurableWebBindingInitializer)this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);
}

它是从容器中获取ConfigurableWebBindingInitializer的,从而可知,我们可以配置一个ConfigurableWebBindingInitializer来替换默认的(添加到容器),如果没有配置会初始化一个Web数据绑定器:

//初始化Web数据绑定器,作用就是将请求数据绑定到JavaBean中,参数等,涉及数据转换等等
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();initializer.setConversionService(this.mvcConversionService());initializer.setValidator(this.mvcValidator());initializer.setMessageCodesResolver(this.getMessageCodesResolver());return initializer;
}

【9】org.springframework.boot.autoconfigure.webweb的所有自动场景;上面能够得到的主要思想就是:如何修改Springboot的默认配置:
 1)、在自动配置很多组件的时候,先看容器中有木有用户自己配置的(@Bean,@Component)如果有就是用用户配置的,如果没有就是用自动配置的,因为底层使用了@ConditionalOnMiss注解来判断,容器中是否已经存在此类配置。
 2)、如果有些组件可以配置多个,比如视图解析器(ViewResolver)将用户配置的和自己默认的组合起来。

扩展 SpringMVC: 官方解释:If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.

【1】根据我们之前的配置xml来进行扩展:

<mvc:view‐controller path="/hello" view‐name="success"/>
<mvc:interceptors><mvc:interceptor><mvc:mapping path="/hello"/><bean></bean></mvc:interceptor>
</mvc:interceptors>

【2】SpringBoot编写一个配置类@Configuration,继承WebMvcConfigurerAdapter类型,不能标注@EnableWebMvc。 继承抽象类既保留了所有的自动配置,也能用我们扩展的配置;

//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {@Overridepublic void addViewControllers(ViewControllerRegistry registry) {// super.addViewControllers(registry);//浏览器发送 /yintong 请求来到 success ,视图映射,当没有业务逻辑的时候就比较方便registry.addViewController("/yintong").setViewName("success");}
}

原理:
【1】WebMvcAutoConfigurationSpringMVC的自动配置类;
【2】在做其他自动配置时会导入;@Import(EnableWebMvcConfiguration.class)

@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();//从容器中获取所有的WebMvcConfigurer    @Autowired(required = false)public void setConfigurers(List<WebMvcConfigurer> configurers) {if (!CollectionUtils.isEmpty(configurers)) {this.configurers.addWebMvcConfigurers(configurers);//一个参考实现;将所有的WebMvcConfigurer相关配置都来一起调用;      @Override    public void addViewControllers(ViewControllerRegistry registry) {for (WebMvcConfigurer delegate : this.delegates) {delegate.addViewControllers(registry);}}}
}

【3】容器中所有的WebMvcConfigurer都会一起起作用;
【4】我们的配置类也会被调用;
【5】效果:SpringMVC的自动配置和我们的扩展配置都会起作用;

二、全面接管SpringMVC

让所有SpringMVC的自动配置都失效。使用我们需要的配置,需要在配置类中添加 @EnableWebMvc即可。非常不推荐,不然使用SpringBoot开发干嘛,哈哈。

//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能 
@EnableWebMvc 
@Configuration 
public class MyMvcConfig extends WebMvcConfigurerAdapter {     @Override     public void addViewControllers(ViewControllerRegistry registry) {// super.addViewControllers(registry);         //浏览器发送 /atguigu 请求来到 success                 registry.addViewController("/atguigu").setViewName("success");     } 
}

原理: 为什么@EnableWebMvc自动配置就失效了?

【1】@EnableWebMvc的核心组合注解:

@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {

【2】我们打开上面导入的DelegatingWebMvcConfiguration类,会发现其继承了WebMvcConfigurationSupport

@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

【3】我们看下SpringBoot自动配置的文件,发现如下:@ConditionalOnMissingBean(WebMvcConfigurationSupport.class),可知当容器中存在WebMvcConfigurationSupport类时,就不会导入自动配置的类了,第二步导入的就是这个类。

@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
WebMvcConfigurerAdapter.class })        
//容器中没有这个组件的时候,这个自动配置类才生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })        
public class WebMvcAutoConfiguration {

【4】@EnableWebMvcWebMvcConfigurationSupport组件导入进来;
【5】导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能;

结论:SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置。同时,在SpringBoot中也会有很多的xxxCustomizer帮助我们进行定制配置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/164578.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Keil工程打开发现目标芯片无法选择解决方案

买了一个开发板&#xff0c;配套有一些底层驱动的例程&#xff0c;打开后发现目标芯片无法选择&#xff0c;对应的下载Flash FLM文件也无法选择。从提示框中可以知道所提供的例程是Keil4的例程&#xff0c;我电脑上安装的Keil版本是Keil版本&#xff0c;估计是这个原因导致工程…

C# 执行Excel VBA宏工具类

写在前面 在Excel文档的自动化处理流程中&#xff0c;有部分值需要通过已定义的宏来求解&#xff0c;所以延伸出了用C# 调用Excel中的宏代码的需求。 首先要从NuGet中引入Microsoft.Office.Interop.Excel 类库 using Excel Microsoft.Office.Interop.Excel; 代码实现 /// &l…

HashMap,1.7与1.8的区别,HashMap的扩容方式有哪些

HashMap,1.7与1.8的区别 底层数据结构的区别 JDK 1.8之前&#xff1a; 1&#xff09;JDK1.8 之前HashMap 底层是数组和链表结合在一起使用也就是链表散列。 2&#xff09;HashMap 通过key 的hashCode 经过扰动函数处理过后得到hash 值&#xff0c;然后通过(n - 1&#xff09…

修改el-radio-group样式,自定义单选组件

修改el-radio-group样式,自定义单选组件 自定义组件 MyRadioGroup.vue <template><div class"btnsBox"><el-radio-group v-model"activeIndex" change"handleClick"><el-radio-buttonv-for"(item, index) in list&qu…

CSS3动画

在CSS3中新增了一个很有意思的东西&#xff0c;那就是动画&#xff0c;有了动画我们可以做很多的事情&#xff0c;让我为大家介绍一下动画吧&#xff01; 本篇文章关于介绍动画&#xff0c;利用小球移动为你们介绍一下动画 默认样式&#xff1a; <!DOCTYPE html> <ht…

普通话考试相关(一文读懂)

文章目录&#xff1a; 一&#xff1a;相关常识 1.考试报名时间 2.报名地方 费用 证件 3.考试流程 4.普通话等级说明 二&#xff1a;题型 三&#xff1a;技巧 1.前三题 2.命题说话 四&#xff1a;普通话考试题库 1.在线题库 2.下载题库 一&#xff1a;相关常识 …

JavaEE(SpringMVC)期末复习

文章目录 JavaEE期末复习一、单选题&#xff1a; JavaEE期末复习 一、单选题&#xff1a; 1.Spring的核⼼技术是&#xff08; A &#xff09;&#xff1f; A依赖注入 B.JdbcTmplate C.声明式事务 D.资源访问 Spring的核心技术包括依赖注入&#xff08;Dependency Injection&am…

【前端】js通过canvas获取浏览器的唯一指纹可以当做唯一标识

【前端】js通过canvas获取浏览器的唯一指纹可以当做唯一标识 <!DOCTYPE html> <html><head> <meta charset"utf-8" /> <meta name"viewport" content"widthdevice-width" /> <title>JS Bin</title> &…

解决Emmy Lua插件在IDEA或 Reder 没有代码提示的问题(设置文件关联 增加对.lua.txt文件的支持)

目录 Reder版本2019.x Reder版本2021.1.5x Reder版本2019.x 解决Emmy Lua插件在IDEA或 Reder 没有代码提示的问题(设置文件关联 增加对.lua.txt文件的支持) Reder版本2021.1.5x 解决Emmy Lua插件在IDEA或 Reder 没有代码提示的问题(设置文件关联 增加对.lua.txt文件的支持)…

java游戏制作-王者荣耀游戏

一.准备工作 首先创建一个新的Java项目命名为“王者荣耀”&#xff0c;并在src下创建两个包分别命名为“com.sxt"、”com.stx.beast",在相应的包中创建所需的类。 创建一个名为“img”的文件夹来储存所需的图片素材。 二.代码呈现 package com.sxt;import javax.sw…

Netty Review - 探索ByteBuf的内部机制

文章目录 概念ByteBuf VS Java NIO BufferByteBuf实现类HeapByteBuf vs DirectByteBufPooledByteBuf vs UnpooledByteBuf其他 ByteBuf的实现机制 概念 ByteBuf是Netty中用于处理二进制数据的缓冲区 Netty的ByteBuf是一个可用于高效存储和操作字节数据的数据结构。与传统的Byt…

跳跃游戏[中等]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给你一个非负整数数组nums&#xff0c;你最初位于数组的第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回true&#xff1b;否则&#xff0c;返…

阿里入局鸿蒙!鸿蒙原生应用再添两员新丁

今日HarmonyOS微博称&#xff0c;阿里钉钉、蚂蚁集团旗下的移动开发平台mPaaS与华为达成合作&#xff0c;宣布启动鸿蒙原生应用的开发&#xff01;相关应用将以原生方式适配#HarmonyOS NEXT#系统。 #HarmonyOS#市场或迎来爆发式增长&#xff01; 阿里钉钉 阿里钉钉与华为达成合…

Android 匿名内存深入分析

Android 匿名内存解析 有了binder机制为什么还需要匿名内存来实现IPC呢&#xff1f;我觉得很大的原因就是binder传输是有大小限制的&#xff0c;不说应用层的限制。在驱动中binder的传输大小被限制在了4M&#xff0c;分享一张图片可能就超过了这个限制。匿名内存的主要解决思路…

黑马点评-10实现用户点赞和点赞排行榜功能

用户点赞功能 如果用户只要点赞一次就对数据库中blog表中的liked字段的值加1就会导致一个用户无限点赞 PutMapping("/like/{id}") public Result likeBlog(PathVariable("id") Long id) {// 修改点赞数量,update tb_blog set liked liked 1 where id …

编译器核心技术概览

编译技术是一门庞大的学科&#xff0c;我们无法对其做完善的讲解。但不同用途的编译器或编译技术的难度可能相差很大&#xff0c;对知识的掌握要求也会相差很多。如果你要实现诸如 C、JavaScript 这类通用用途语言&#xff08;general purpose language&#xff09;&#xff0c…

buck降压电路

一、Buck电路的拓扑结构 Buck是直流转直流的降压电路,下面是拓扑结构,作为硬件工程师,这个最好是能够记下来,了然于胸。 为啥要记下来,自然是因为这个电路太基础了,并且谁都会用到,更重要的一点,面试可能会考。。。 上图是个异步buck,同步buck就是将里面的二极管换成M…

3D火山图绘制教程

一边学习&#xff0c;一边总结&#xff0c;一边分享&#xff01; 本期教程内容 **注&#xff1a;**本教程详细内容 Volcano3D绘制3D火山图 一、前言 火山图是做差异分析中最常用到的图形&#xff0c;在前面的推文中&#xff0c;我们也推出了好几期火山图的绘制教程&#xff0…

Android——资源IDnonFinalResIds和“Attribute value must be constant”错误

一、异常描述 通过资源ID引用资源提示错误 Attribute value must be constant 二、解决方案 在根目录下的文件 gradle.properties 中添加如下配置&#xff0c;然后Sync Project android.nonFinalResIdsfalse 三、问题原因 android.nonFinalResIds 是Android开发中一个用于解…

此处不允许使用特性namespace

1.DOCTYPE 后面改成 mapper 2.PUBLIC一行中的Config改为Mapper 3.将下一行config变为小写的mapper <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.or…