大纲
前言
本章节所需的案例代码,可以直接从 GitHub 下载对应章节 spring-boot3-04
。
自动配置
自动配置的原理
- Web 场景的自动配置原理
- 1、导入
spring-boot-starter-web
,会导入 spring-boot-starter
,也就会导入 spring-boot-autoconfigure
包。 - 2、
spring-boot-autoconfigure
包里面有一个文件 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
,里面指定了应用启动时所有要加载的自动配置类。 - 3、
@EnableAutoConfiguration
会自动地将上面文件里写的所有自动配置类都导入进来,同时 xxxAutoConfiguration
是有声明条件注解的,目的是按需加载。 - 4、
xxxAutoConfiguration
往容器中导入一堆组件,这些组件都是从 xxxProperties
中获取属性值。 - 5、
xxxProperties
又是和配置文件进行了绑定。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration org.springframework.boot.autoconfigure.web.reactive.ReactiveMultipartAutoConfiguration org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration org.springframework.boot.autoconfigure.web.reactive.WebSessionIdResolverAutoConfiguration org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration
|
- Web 场景下配置文件的前缀配置项说明
- 1、服务器的配置
server
- 2、Web 场景通用配置
spring.web
- 3、Spring MVC 的所有配置
spring.mvc
- 4、文件上传配置
spring.servlet.multipart
自动配置的默认效果
SpringBoot Web 场景自动配置的效果如下:
- 支持静态
index.html
- 支持默认的静态资源处理机制,静态资源放在
static
文件夹下即可直接访问 - 包含了
ContentNegotiatingViewResolver
和 BeanNameViewResolver
组件,用于视图解析 - 自动注册了
Converter
,GenericConverter
,Formatter
组件,适配了常见的数据类型转换和格式化需求 - 支持
HttpMessageConverters
,可以方便返回 JSON 等数据类型 - 注册
MessageCodesResolver
,方便国际化及错误消息处理 - 自动使用
ConfigurableWebBindingInitializer
实现消息处理、数据绑定、类型转化、数据校验等功能
重点知识
- 如果想保持 SpringBoot MVC 的默认配置,并且自定义更多的 MVC 配置(如 interceptors,formatters,view controllers 等),可以使用
@Configuration
标注一个配置类,让配置类实现 WebMvcConfigurer
接口,并不要使用 @EnableWebMvc
注解。 - 如果想保持 SpringBoot MVC 的默认配置,但要自定义核心组件的实例(如
RequestMappingHandlerMapping
,RequestMappingHandlerAdapter
,ExceptionHandlerExceptionResolver
),往容器中放一个 WebMvcRegistrations
组件,并不要使用 @EnableWebMvc
注解。 - 如果想全面接管 SpringBoot MVC 的配置,可以使用
@Configuration
标注一个配置类,让配置类实现 WebMvcConfigurer
接口,并加上 @EnableWebMvc
注解即可。
静态资源
默认静态资源规则
静态资源映射
静态资源映射规则都在 WebMvcAutoConfiguration
自动配置类中进行了定义。
- 访问
/webjars/**
路径就会去 classpath:/META-INF/resources/webjars/
下找资源,一般用于访问通过 Maven 引入的第三方前端组件(如 Vue、Bootstrap) - 访问
/**
路径就会去静态资源默认的四个位置找资源,包括 classpath:/META-INF/resources/
、classpath:/resources/
、classpath:/static/
、classpath:/public/
静态资源缓存
所有静态资源都定义了缓存规则,浏览器访问过一次,就会缓存一段时间,但此功能的参数无默认值。
cachePeriod
:缓存周期,多久不用找服务器要新的,默认值 0s,以秒为单位cacheControl
: HTTP 缓存控制,参照 Mozilla 文档useLastModified
:是否使用 Last-Modified
头,默认值 false
,配合 HTTP Cache 规则使用- 所有缓存参数的配置,都可以通过配置文件里的
spring.web
前缀配置项指定(如下)
1 2 3 4 5 6 7 8
| spring.web.resources.cache.period=3600
spring.web.resources.cache.cachecontrol.max-age=7200
spring.web.resources.cache.use-last-modified=true
|
Favicon 图标
- 在默认的四个静态资源路径下查找
favicon.ico
欢迎页面
欢迎页面的映射规则在 WebMvcAutoConfiguration
中进行了定义:
- 首先会在默认的四个静态资源路径下查找
index.html
- 如果静态资源路径下找不到,就会在
templates
目录下找 index
模板页面
自定义静态资源规则
配置方式
spring.mvc
:配置静态资源访问路径的前缀spring.web
:配合静态资源目录、静态资源策略 (开启映射、处理链、缓存规则)、国际化的区域信息
1 2 3 4 5 6 7 8
| spring.mvc.static-path-pattern=/static/**
spring.mvc.webjars-path-pattern=/webjars/**
spring.web.resources.static-locations=classpath:/static/,classpath:/public/,classpath:/asset/
|
提示
- 当不使用
spring.mvc.static-path-pattern
自定义静态资源访问路径的前缀时,静态资源默认的访问路径示例是 http://127.0.0.1:8080/backgrond.png
- 当使用
spring.mvc.static-path-pattern=/static/**
自定义静态资源访问路径的前缀时,静态资源的访问路径示例是 http://127.0.0.1:8080/static/backgrond.png
代码方式
提示
- 如果希望完全禁用 SpringBoot MVC 的自动配置,可以在配置类上添加
@EnableWebMvc
注解,此时相当于采用全手动的方式配置 MVC。
- 第一种写法:实现
WebMvcConfigurer
接口,同样可以自定义静态资源规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import org.springframework.context.annotation.Configuration; import org.springframework.http.CacheControl; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.concurrent.TimeUnit;
@Configuration public class WebConfiguration implements WebMvcConfigurer {
@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry .addResourceHandler("/static/**") .addResourceLocations("classpath:/static/", "classpath:/public/", "classpath:/asset/") .setCacheControl(CacheControl.maxAge(7200, TimeUnit.SECONDS)); }
}
|
- 第二种写法:使用
@Bean
注解,定义 WebMvcConfigurer
组件,同样可以自定义静态资源规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.CacheControl; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.concurrent.TimeUnit;
@Configuration public class WebConfiguration {
@Bean public WebMvcConfigurer webMvcConfigurer() { return new WebMvcConfigurer() { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry .addResourceHandler("/static/**") .addResourceLocations("classpath:/static/", "classpath:/public/", "classpath:/asset/") .setCacheControl(CacheControl.maxAge(7200, TimeUnit.SECONDS)); } }; }
}
|
错误处理
默认机制
SpringBoot 错误处理的自动配置都在 ErrorMvcAutoConfiguration
中,两大核心机制:
- 1、SpringBoot 会自适应处理错误,响应页面或 JSON 数据给客户端
- 2、SpringMVC 的错误处理机制依然保留,SpringMVC 处理不了的,才会交给 SpringBoot 进行处理
- 发生错误以后,请求转发给
/error
路径,SpringBoot 在底层写好一个 BasicErrorController
组件,专门处理这个请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE) public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { HttpStatus status = getStatus(request); Map<String, Object> model = Collections .unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML))); response.setStatus(status.value()); ModelAndView modelAndView = resolveErrorView(request, response, status, model); return (modelAndView != null) ? modelAndView : new ModelAndView("error", model); }
@RequestMapping public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { HttpStatus status = getStatus(request); if (status == HttpStatus.NO_CONTENT) { return new ResponseEntity<>(status); } Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL)); return new ResponseEntity<>(body, status); }
|
1 2 3 4
| ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
|
1 2 3 4 5 6
| @Bean @ConditionalOnBean(DispatcherServlet.class) @ConditionalOnMissingBean(ErrorViewResolver.class) DefaultErrorViewResolver conventionErrorViewResolver() { return new DefaultErrorViewResolver(this.applicationContext, this.resources); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Override public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) { ModelAndView modelAndView = resolve(String.valueOf(status.value()), model); if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) { modelAndView = resolve(SERIES_VIEWS.get(status.series()), model); } return modelAndView; }
private ModelAndView resolve(String viewName, Map<String, Object> model) { String errorViewName = "error/" + viewName; TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext); if (provider != null) { return new ModelAndView(errorViewName, model); } return resolveResource(errorViewName, model); }
private ModelAndView resolveResource(String viewName, Map<String, Object> model) { for (String location : this.resources.getStaticLocations()) { try { Resource resource = this.applicationContext.getResource(location); resource = resource.createRelative(viewName + ".html"); if (resource.exists()) { return new ModelAndView(new HtmlResourceView(resource), model); } } catch (Exception ex) { } } return null; }
|
- 容器中有一个默认的名为
error
的 View,提供了默认错误页面的功能
1 2 3 4 5
| @Bean(name = "error") @ConditionalOnMissingBean(name = "error") public View defaultErrorView() { return this.defaultErrorView; }
|
1 2 3 4 5
| @Bean @ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT) public DefaultErrorAttributes errorAttributes() { return new DefaultErrorAttributes(); }
|
- 错误页面的解析规则
- 1、解析一个错误页
- a. 如果发生了 500、404、503、403 这些错误
- ⅰ. 如果有模板引擎,模板文件默认在
classpath:/templates/error/精确码.html
- ⅱ. 如果没有模板引擎,在静态资源文件夹下找
精确码.html
- b. 如果匹配不到
精确码.html
这些精确的错误页,就去找 5xx.html
,4xx.html
模糊匹配- ⅰ. 如果有模板引擎,模板文件默认在
classpath:/templates/error/5xx.html
- ⅱ. 如果没有模板引擎,在静态资源文件夹下找
5xx.html
- 2、如果模板引擎路径
templates
下有 error.html
页面,就直接渲染并返回给客户端
自定义错误响应
- 自定义 JSON 响应,使用
@ControllerAdvice
+ @ExceptionHandler
进行统一异常处理
1 2 3 4 5 6 7 8 9 10
| @ControllerAdvice public class GlobalExceptionHandler {
@ResponseBody @ExceptionHandler(Exception.class) public R handleException(Exception exception) { return R.error(exception.getMessage()); }
}
|
- 自定义页面响应,根据 SpringBoot 的错误页面解析规则,自定义错误页面。
错误处理的最佳实践
- 前后端分离开发模式
- 后台发生的所有错误,通过
@ControllerAdvice
+ @ExceptionHandler
进行统一异常处理
- 前后端不分离模式(服务端模板页面渲染)
- 一些不可预知的错误,如使用 HTTP 码表示的服务器或客户端错误
- 在
classpath:/templates/error/
下面,存放常用精确的错误码页面,如 500.html
、404.html
- 在
classpath:/templates/error/
下面,存放通用模糊匹配的错误码页面,如 5xx.html
、4xx.html
- 发生业务错误
- 核心业务的每一种错误,都应该通过代码控制,跳转到定制的错误页
- 通用业务,可以通过
classpath:/templates/error.html
错误页面,显示通用的错误信息
- 在模板页面或者服务端返回的 JSON 数据中,可用的 Model 数据如下:
嵌入式容器
Servlet 容器指的是管理、运行 Servlet 组件(Servlet
、Filter
、Listener
)的环境,一般指 Web 服务器。
自动配置原理
- SpringBoot 默认使用嵌入的 Tomcat 作为 Servlet 容器
- 嵌入式容器的自动配置类是
ServletWebServerFactoryAutoConfiguration
,EmbeddedWebServerFactoryCustomizerAutoConfiguration
ServletWebServerFactoryAutoConfiguration
自动配置了嵌入式容器场景- 绑定了
ServerProperties
配置类,所有和服务器相关的配置都使用 server
作为开始前缀 ServletWebServerFactoryAutoConfiguration
默认导入了嵌入式的三大服务器,包括 Tomcat
、Jetty
、Undertow
- 导入
Tomcat
、Jetty
、Undertow
时都有条件注解,系统中有对应的类才会生效(也就是导了包) - 在默认情况下,Tomcat 的配置会生效,SpringBoot 往容器中放了
TomcatServletWebServerFactory
组件 - 往容器中放一个 Web 服务器工厂
ServletWebServerFactory
后,可以创建 Web 服务器 - Web 服务器工厂都有一个功能,可以调用
getWebServer()
获取 Web 服务器 TomcatServletWebServerFactory
创建了 Tomcat Web 服务器
ServletWebServerApplicationContext
IOC 容器在启动的时候,会调用 ServletWebServerFactory
创建 Web 服务器- Spring 容器刷新(启动)的时候,会预留一个时机,调用
onRefresh()
刷新子容器 refresh()
容器刷新,十二大步的刷新子容器会调用 onRefresh()
1 2 3 4 5 6 7 8 9 10 11 12
| @AutoConfiguration @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @ConditionalOnClass(ServletRequest.class) @ConditionalOnWebApplication(type = Type.SERVLET) @EnableConfigurationProperties(ServerProperties.class) @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, ServletWebServerFactoryConfiguration.EmbeddedTomcat.class, ServletWebServerFactoryConfiguration.EmbeddedJetty.class, ServletWebServerFactoryConfiguration.EmbeddedUndertow.class }) public class ServletWebServerFactoryAutoConfiguration { }
|
1 2 3 4 5 6 7 8 9 10
| @Override protected void onRefresh() { super.onRefresh(); try { createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start web server", ex); } }
|
总结
- Web 场景的 Spring 容器启动,在调用
onRefresh()
的时候,会调用创建 Web 服务器的方法。 - Web 服务器的创建是通过
WebServerFactory
实现的,容器中又会根据条件注解,启动相关的服务器配置,默认 EmbeddedTomcat
会往容器中放一个 TomcatServletWebServerFactory
组件,导致项目启动后,自动创建出 Tomcat 服务器。
自定义嵌入式容器
- 嵌入式三大容器有
Tomcat
、Jetty
、Undertow
,SpringBoot 默认使用 Tomcat 作为容器。若希望切换到其他容器,只需要更改 Maven 的配置即可,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <properties> <servlet-api.version>3.1.0</servlet-api.version> </properties>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency> </dependencies>
|
- 最佳实践
- 修改以
server
为开始前缀的相关配置,这样就可以修改服务器参数 - 通过往容器中放一个
ServletWebServerFactory
组件,来禁用掉 SpringBoot 默认引入的 Web 服务器工厂,这样就可以实现自定义任意的嵌入服务器。
底层源码浅析
Web MVC 自动配置原理
自动配置生效的条件
1 2 3 4 5 6 7 8 9 10 11 12
|
@AutoConfiguration(after = { DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class }) @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) @ImportRuntimeHints(WebResourcesRuntimeHints.class) public class WebMvcAutoConfiguration {
}
|
自动配置实现的效果
效果一:往容器中放了两个 Filter
HiddenHttpMethodFilter
:页面表单提交 REST 请求(支持 GET、POST、PUT、DELETE 方法)FormContentFilter
: 表单内容 Filter,GET(数据放 URL 后面)、POST(数据放请求体)请求可以携带数据,PUT、DELETE 的请求体数据会被忽略
效果二:往容器中放了 WebMvcConfigurer
组件,给 Spring MVC 添加各种定制功能,所有功能最终都会和配置文件的内容进行绑定
WebMvcProperties
: 绑定了以 spring.mvc
为开始前缀的配置项WebProperties
: 绑定了以 spring.web
为开始前缀的配置项
1 2 3 4 5 6 7
| @Configuration(proxyBeanMethods = false) @Import(EnableWebMvcConfiguration.class) @EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class }) @Order(0) public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware{ }
|
静态资源映射规则的源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {
public void addResourceHandlers(ResourceHandlerRegistry registry) { if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); } else { this.addResourceHandler(registry, this.mvcProperties.getWebjarsPathPattern(), "classpath:/META-INF/resources/webjars/"); this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> { registration.addResourceLocations(this.resourceProperties.getStaticLocations()); if (this.servletContext != null) { ServletContextResource resource = new ServletContextResource(this.servletContext, "/"); registration.addResourceLocations(new Resource[]{resource}); }
}); } }
}
|
规则一:访问 /webjars/**
路径就会去 classpath:/META-INF/resources/webjars/
下找资源,一般用于访问通过 Maven 引入的第三方前端组件(如 Vue、Bootstrap)
规则二:访问 /**
路径就会去静态资源默认的四个位置找资源,包括 classpath:/META-INF/resources/
、classpath:/resources/
、classpath:/static/
、classpath:/public/
规则三:静态资源默认都有缓存规则的设置
- 所有缓存参数的配置,都可以通过配置文件里的
spring.web
前缀配置项指定 cachePeriod
:缓存周期,多久不用找服务器要新的,默认值 0s,以秒为单位cacheControl
: HTTP 缓存控制,参照 Mozilla 文档useLastModified
:是否使用 Last-Modified
头,默认值 false
,配合 HTTP Cache 规则使用
1 2 3
| registration.setCachePeriod(getSeconds(this.resourceProperties.getCache().getPeriod())); registration.setUseLastModified(this.resourceProperties.getCache().isUseLastModified()); registration.setCacheControl(this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl());
|
提示
当浏览器访问了一个静态资源文件 index.js
,如果在服务器中这个资源文件没有发生变化,那么在用户下次访问的时候,就可以直接让浏览器用本地缓存中的资源文件,而不用给服务器发送请求。
EnableWebMvcConfiguration 的源码
EnableWebMvcConfiguration
继承了 DelegatingWebMvcConfiguration
,而 DelegatingWebMvcConfiguration
则继承了 WebMvcConfigurationSupport
。
1 2 3 4
| @Configuration(proxyBeanMethods = false) public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
}
|
1 2 3 4 5
| @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(WebProperties.class) public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware { }
|
SpringBoot 默认会往容器中放入 WebMvcConfigurationSupport
组件,如果开发者注册了 WebMvcConfigurationSupport
组件,那么 SpringBoot 的 WebMvcAutoConfiguration
组件就会失效。这相当于禁用 SpringBoot 的自动配置,采用全手动的方式配置 MVC。
1 2 3 4 5 6 7 8 9
| @AutoConfiguration(after = { DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class }) @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) @ImportRuntimeHints(WebResourcesRuntimeHints.class) public class WebMvcAutoConfiguration {
}
|
- 欢迎页面的查找规则
HandlerMapping
:根据请求路径找到能处理请求的 HandlerWelcomePageHandlerMapping
:- 访问
/**
路径下的所有请求,都会去默认的四个静态资源路径下查找页面,这也适用于欢迎页面 - 只要在任意一个静态资源路径下有一个
index.html
页面,项目启动后就可以正常访问它
WebMvcAutoConfiguration
是一个自动配置类,它里面有一个 EnableWebMvcConfiguration
配置类EnableWebMvcConfiguration
继承了 DelegatingWebMvcConfiguration
,且两者都会生效DelegatingWebMvcConfiguration
利用 DI (自动注入) 将容器中所有的 WebMvcConfigurer
都注入进来- 别人调用
DelegatingWebMvcConfiguration
的方法配置底层规则,而它自身则调用所有 WebMvcConfigurer
的底层配置方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
@Configuration(proxyBeanMethods = false) public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
@Autowired(required = false) public void setConfigurers(List<WebMvcConfigurer> configurers) { if (!CollectionUtils.isEmpty(configurers)) { this.configurers.addWebMvcConfigurers(configurers); } }
@Override protected void configurePathMatch(PathMatchConfigurer configurer) { this.configurers.configurePathMatch(configurer); }
@Override protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) { this.configurers.configureContentNegotiation(configurer); }
...
}
|
全面接管 Spring MVC
SpringBoot 默认配置好了 Spring MVC 的所有常用特性,如果需要全面接管 Spring MVC 的所有配置并禁用默认配置,仅需要编写一个 WebMvcConfigurer
配置类,并标注 @EnableWebMvc
即可。
WebMvcAutoConfiguration 自动配置了哪些规则
Spring MVC 自动配置场景给我们配置了如下所有默认行为:
@EnableWebMvc 禁用默认行为
@EnableWebMvc
往容器中导入了 DelegatingWebMvcConfiguration
组件,它继承自 WebMvcConfigurationSupport
WebMvcAutoConfiguration
有一个核心的条件注解,@ConditionalOnMissingBean (WebMvcConfigurationSupport.class)
,当容器中没有 WebMvcConfigurationSupport
组件时,WebMvcAutoConfiguration
才生效@EnableWebMvc
导入了 WebMvcConfigurationSupport
,从而会导致 WebMvcAutoConfiguration
失效,即会导致 SpringBoot 禁用 MVC 自动配置的所有功能
WebMvcConfigurer
定义并扩展了 Spring MVC 的底层功能,其中的功能列表如下:
提供方法 | 核心参数 | 功能 | 默认 |
---|
addFormatters | FormatterRegistry | 格式化器:支持属性上 @NumberFormat 和 @DatetimeFormat 的数据类型转换 | GenericConversionService |
getValidator | 无 | 数据校验:校验 Controller 上使用 @Valid 标注的参数合法性。需要导入 spring-boot-starter-validator | 无 |
addInterceptors | InterceptorRegistry | 拦截器:拦截收到的所有请求 | 无 |
configureContentNegotiation | ContentNegotiationConfigurer | 内容协商:支持多种数据格式返回。需要配合支持这种类型的 HttpMessageConverter | 支持 JSON |
configureMessageConverters | List<HttpMessageConverter<?>> | 消息转换器:标注 @ResponseBody 的返回值会利用 MessageConverter 直接写出去 | 支持 8 种数据类型,包括 byte ,string ,multipart ,resource ,json |
addViewControllers | ViewControllerRegistry | 视图映射:直接将请求路径与物理视图映射。用于无 Java 业务逻辑的直接视图页渲染 | 无 |
configureViewResolvers | ViewResolverRegistry | 视图解析器:逻辑视图转为物理视图 | ViewResolverComposite |
addResourceHandlers | ResourceHandlerRegistry | 静态资源处理:静态资源路径映射、缓存控制 | ResourceHandlerRegistry |
configureDefaultServletHandling | DefaultServletHandlerConfigurer | 默认 Servlet :可以覆盖 Tomcat 的 DefaultServlet 。让 DispatcherServlet 拦截 / | 无 |
configurePathMatch | PathMatchConfigurer | 路径匹配:自定义 URL 路径匹配。可以自动为所有路径加上指定前缀,比如 /api | 无 |
configureAsyncSupport | AsyncSupportConfigurer | 异步支持 | TaskExecutionAutoConfiguration |
addCorsMappings | CorsRegistry | 跨域支持 | 无 |
addArgumentResolvers | List | 参数解析器 | MVC 默认提供 |
addReturnValueHandlers | List | 返回值解析器 | MVC 默认提供 |
configureHandlerExceptionResolvers | List | 异常处理器 | 3 个核心类:ExceptionHandlerExceptionResolver ,ResponseStatusExceptionResolver ,DefaultHandlerExceptionResolver |
getMessageCodesResolver | 无 | 消息码解析器:国际化使用 | 无 |
最佳实践
SpringBoot 已经默认配置好了 Web 开发场景常用的功能,一般情况下直接使用即可。
三种配置方式
在 SpringBoot Web 开发场景下,有以下三种方式可以配置 SpringBoot MVC。
方式 | 用法 | 重点 | 效果 |
---|
全自动 | 直接编写控制器的业务逻辑 | | 全部使用 SpringBoot 自动配置的默认效果 |
手自一体 | @Configuration + 配置 WebMvcConfigurer 或者配置 WebMvcRegistrations | 不要标注 @EnableWebMvc 注解 | 保留 SpringBoot 自动配置效果,手动配置部分功能,自定义 MVC 底层组件 |
全手动 | @Configuration + 配置 WebMvcConfigurer | 标注 @EnableWebMvc 注解 | 禁用 SpringBoot 自动配置效果,全手动配置 |
两种开发模式
- 前后端分离模式:
@RestController
直接响应 JSON 数据 - 前后端不分离模式:
@Controller
+ Thymeleaf
模板引擎