9 Web开发——springmvc自动配置原理
官方文档目录:
https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#boot-features-spring-mvc

1. Spring MVC auto-configuration
Spring Boot 自动配置好了SpringMVC,以下是SpringBoot对SpringMVC的默认配置:
(WebMvcAutoConfiguration)
- Inclusion of `ContentNegotiatingViewResolver` and `BeanNameViewResolver` beans.
- 自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染(转发?重定向?))
public class WebMvcAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public InternalResourceViewResolver defaultViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix(this.mvcProperties.getView().getPrefix());
resolver.setSuffix(this.mvcProperties.getView().getSuffix());
return resolver;
} @Bean
@ConditionalOnBean({View.class})
@ConditionalOnMissingBean
public BeanNameViewResolver beanNameViewResolver() {
BeanNameViewResolver resolver = new BeanNameViewResolver();
resolver.setOrder(2147483637);
return resolver;
} @Bean
@ConditionalOnBean({ViewResolver.class})
@ConditionalOnMissingBean(
name = {"viewResolver"},
value = {ContentNegotiatingViewResolver.class}
)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(
(ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));
resolver.setOrder(-2147483648);
return resolver;
}
......
}
- ContentNegotiatingViewResolver:只配置一个@RequestMapping, 匹配多个 url
public class ContentNegotiatingViewResolver implements ViewResolver, Ordered, InitializingBean {@Nullable
privateList<ViewResolver> viewResolvers; //视图解析器 //初始化方法
protected void initServletContext(ServletContext servletContext) {
//从容器中根据ViewResolver类型获取所有的视图解析器Collection<ViewResolver> matchingBeans = BeanFactoryUtils
.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), ViewResolver.class).values();
ViewResolver viewResolver;
if (this.viewResolvers == null) {
this.viewResolvers = new ArrayList(matchingBeans.size());
Iterator var3 = matchingBeans.iterator(); //遍历所有的视图解析器
while(var3.hasNext()) {
viewResolver = (ViewResolver)var3.next();
if (this != viewResolver) {
//将所有的视图解析器加入到本地变量
this.viewResolvers.add(viewResolver);
}
}
} else {
for(int i = 0; i < this.viewResolvers.size(); ++i) {
viewResolver = (ViewResolver)this.viewResolvers.get(i);
if (!matchingBeans.contains(viewResolver)) {
String name = viewResolver.getClass().getName() + i;
this.obtainApplicationContext().getAutowireCapableBeanFactory().initializeBean(viewResolver, name);
}
}
} AnnotationAwareOrderComparator.sort(this.viewResolvers);
this.cnmFactoryBean.setServletContext(servletContext);
} @Nullable
publicView 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) {//只配置一个@RequestMapping, 匹配多个 url,所以要获取多个
List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);//获取所有候选的视图对象
View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);//获取最佳视图对象(根据参数或类型选取)
if (bestView != null) {
return bestView;
}
} }- 自定义ViewResolver加入到Spring容器
//springBoot启动类注解,包含@Configuration
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
//将自定义的ViewResolver加入到Spring容器中
@Bean
public ViewResolver myViewResolver() {
return new MyViewResover();
}
//自定义ViewResover
public static class MyViewResover implements ViewResolver {
@Nullable
@Override
public View resolveViewName(String s, Locale locale) throws Exception {
return null;
}
}
}- 当SpringBoot项目启动,随便发一个请求,进到DispatcherServlet的DoDispatch()方法时,能够获取到所有的ViewResolver,包括自定义的,被包含在了ContentNegotiatingViewResolver里



- 总结:如何定制视图解析器ViewResolver?:
根据@WebMvcAutoConfiguration
——》 @Bean ContentNegotiatingViewResolver viewResolver()
——》initServletContext()中根据类型加载容器中所有的ViewResolver
我们可以自己给容器中添加一个视图解析器,@Bean加入到容器中,SpringBoot便自动的将其组合进来; 关于视图解析器详情在SprintMVC知识点中学习
这些前面章节已有学过
- Support for serving static resources, including support for WebJars (see below).静态资源文件夹路径,webjars
- Static `index.html` support. 静态首页访问
- Custom `Favicon` support (see below). favicon.ico
- 自动注册了 of `Converter`, `GenericConverter`, `Formatter` beans.
- Converter:转换器; public String hello(User user):类型转换使用Converter (如果页面传参和User对象类型一一对应,不用转换,如果对应不上就需要转换)
- `Formatter` 格式化器; 2017.12.17 / 2017-12-17 / 2017/12/17===Date; (1:字符串转日期;2:按照给定的格式转)
@Configuration
@ConditionalOnWebApplication(
type = ConditionalOnWebApplication.Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration { @Configuration
@Import({org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ResourceLoaderAware {
private final ListableBeanFactory beanFactory; @Bean
public FormattingConversionService mvcConversionService() {
WebConversionService conversionService = new WebConversionService(this.mvcProperties.getDateFormat());
this.addFormatters(conversionService);
return conversionService;
} protected void addFormatters(FormatterRegistry registry) {
this.configurers.addFormatters(registry);
} //添加格式化器
public void addFormatters(FormatterRegistry registry) {
//容器中符合Converter类型的bean都被格式化注册器FormatterRegistry注册进来
Iterator var2 = this.getBeansOfType(Converter.class).iterator(); while(var2.hasNext()) {
Converter<?, ?> converter = (Converter)var2.next();
registry.addConverter(converter);
} //容器中符合GenericConverter类型的bean都被格式化注册器FormatterRegistry注册进来
var2 = this.getBeansOfType(GenericConverter.class).iterator(); while(var2.hasNext()) {
GenericConverter converter = (GenericConverter)var2.next();
registry.addConverter(converter);
} //容器中符合Formatter类型的bean都被格式化注册器FormatterRegistry注册进来
var2 = this.getBeansOfType(Formatter.class).iterator(); while(var2.hasNext()) {
Formatter<?> formatter = (Formatter)var2.next();
registry.addFormatter(formatter);
} /**
* 从容器中获取所有从属于此类型的Bean
* 自己添加的格式化器转换器,我们只需要放在容器中即可
*/
private <T> Collection<T> getBeansOfType(Class<T> type) {
return this.beanFactory.getBeansOfType(type).values();
}
}
}
}
- HttpMessageConverter:SpringMVC用来转换Http请求和响应的;返回结果将 User ——》转化为 Json;
- `HttpMessageConverters` 是从容器中确定;获取所有的HttpMessageConverter;
//@Configuration包含了@Component
@Configuration
public class WebMvcAutoConfiguration {
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ResourceLoaderAware {
private final ObjectProvider<HttpMessageConverters> messageConvertersProvider; //通过构造方法从容器中注入进来
public WebMvcAutoConfigurationAdapter(ObjectProvider<HttpMessageConverters> messageConvertersProvider,其它参数) {
this.messageConvertersProvider = messageConvertersProvider;
......
}
}
} //@Configuration包含了@Component
@Configuration
public class HttpMessageConverters implements Iterable<HttpMessageConverter<?>> {
private final List<HttpMessageConverter<?>> converters; //
public HttpMessageConverters(HttpMessageConverter... additionalConverters) {
this((Collection) Arrays.asList(additionalConverters));
}
//通过构造方法从容器中注入进来
public HttpMessageConverters(Collection<HttpMessageConverter<?>> additionalConverters) {
this(true, additionalConverters);
}
}自己给容器中添加HttpMessageConverter,只需要将自己的组件注册容器中(@Bean,@Component)
- Automatic registration of `MessageCodesResolver` (see below).定义错误代码生成规则
- Automatic use of a `ConfigurableWebBindingInitializer` bean (see below).
我们可以配置一个ConfigurableWebBindingInitializer来替换默认的;(添加到容器)
```初始化WebDataBinder;
```请求数据=====JavaBean;
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.
If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.
总结:如何修改SpringBoot的默认配置?
1)、SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如果有就用用户配置的,
如果没有,才自动配置;
如果有些组件可以有多个(ViewResolver)将用户配置的和自己默认的组合起来;
9 Web开发——springmvc自动配置原理的更多相关文章
- spring boot @EnableWebMvc禁用springMvc自动配置原理。
说明: 在spring boot中如果定义了自己的java配置文件,并且在文件上使用了@EnableWebMvc 注解,那么sprig boot 的默认配置就会失效.如默认的静态文件配置路径:&quo ...
- springboot08(springmvc自动配置原理)
MVC WebMvcAutoConfiguration.java @ConditionalOnMissingBean(name = "viewResolver", value = ...
- SpringBoot学习(七)-->SpringBoot在web开发中的配置
SpringBoot在web开发中的配置 Web开发的自动配置类:在Maven Dependencies-->spring-boot-1.5.2.RELEASE.jar-->org.spr ...
- Springboot 系列(三)Spring Boot 自动配置原理
注意:本 Spring Boot 系列文章基于 Spring Boot 版本 v2.1.1.RELEASE 进行学习分析,版本不同可能会有细微差别. 前言 关于配置文件可以配置的内容,在 Spring ...
- SpringBoot:配置文件及自动配置原理
西部开源-秦疆老师:基于SpringBoot 2.1.6 的博客教程 秦老师交流Q群号: 664386224 未授权禁止转载!编辑不易 , 转发请注明出处!防君子不防小人,共勉! SpringBoot ...
- springboot核心技术(二)-----自动配置原理、日志
自动配置原理 配置文件能配置的属性参照 1.自动配置原理: 1).SpringBoot启动的时候加载主配置类,开启了自动配置功能 @EnableAutoConfiguration 2).@Enable ...
- Spring Boot自动配置原理
使用Spring Boot之后,一个整合了SpringMVC的WEB工程开发,变的无比简单,那些繁杂的配置都消失不见了,这 是如何做到的? 一切魔力的开始,都是从我们的main函数来的,所以我们再次来 ...
- SpringBoot入门一:基础知识(环境搭建、注解说明、创建对象方法、注入方式、集成jsp/Thymeleaf、logback日志、全局热部署、文件上传/下载、拦截器、自动配置原理等)
SpringBoot设计目的是用来简化Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.通过这种方式,SpringBoot致力于在蓬勃发 ...
- SpringBoot自动配置原理
前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 回顾前面Spring的文章(以学习的顺序排好): S ...
随机推荐
- Jquery 组 checkbox全选按钮
<!DOCTYPE html><html lang="zh-cn"><head> <meta charset="utf-8&qu ...
- 微信内置浏览器在使用video标签时(安卓)默认全屏的原因及解决办法
根据X5论坛得到的答案是:设计如此. 腾讯真是越来越嚣张了,一家独大后用户体验都不注重了(不给程序员留活路). 听说有个申请加入vdeo白名单的,域名验证后就可以解决默认全屏(反正我是没见过申请入口, ...
- 关于mybatis的@Param注解和参数
1,使用@Param注解 当以下面的方式进行写SQL语句时: @Select("select column from table where userid = #{userid} " ...
- delphi7调用数据库连接属性
背景:连接数据库用ADOQuery控件,但是程序一旦编译完成,如果想更改数据库连接设置还得重新修改ADOQuery的属性重新编译 如果可以在程序中可以随时设置ADOQuery的属性则会方便很多. 实现 ...
- CSS变形transform(2d)
前面的话 CSS变形transform是一些效果的集合,主要是移动.旋转.缩放和倾斜这四种基本操作,还可以通过设置matrix矩阵来实现更复杂的效果.变形transform可以实现2D和3D两种效果. ...
- 【转】用宏定义代替printf函数
问题提出 有时候我们想用宏定义来决定是编译debug版本的代码还是release的代码,dubug版本的代码会通过printf打印调试信息,release版本的代码则不会.我们总不能对每一条print ...
- luogu1345 奶牛的电信 (最小割)
虽然割点不好搞,但是可以变成割边呀 拆点,拆出来的边权给1,原图中的边权给inf,然后跑dinic就行了 #include<bits/stdc++.h> #define pa pair&l ...
- MD5 SHA1 CRC32
md5: import hashlib md5 = hashlib.md5() md5.update(bytes('http://www.baidu.com',encoding="utf-8 ...
- P1856 矩形周长
哇!这小破题坑了我好久. 扫描线+线段树 这题数据范围小,没离散化.真要离散化我还搞不好呢. 具体的看这个博客吧. 主要是这个坑爹的c,len把我搞了,其他的还好. 代码: #include < ...
- Android: 待机时如何让程序继续运行 extends Service
接触Android没几天,不太了解. 本来写好的一个应用在无意中发现,待机的时候,应用中的一个线程停止了运行. 这个线程是每隔一分钟上传一个数据到服务器上. 我当时测试的时候,没想过待机(接开关键)下 ...