文章目录
- WEB开发
- `WebMvcAutoConfiguration`原理
- 生效条件
- 效果
- `WebMvcConfigurer`接口
- 静态资源源码规则
- `EnableWebMvcConfiguration`规则
- 容器中`WebMvcConfigurer`配置底层行为
- Web场景
- 自动配置
- 默认效果
- 静态资源
- 默认规则
- 静态资源映射
- 静态资源缓存
- 欢迎页
- Favion
- 自定义静态资源规则
- 配置方式
- 代码方式
- 路径匹配
- Ant风格路径用法
- 模式切换
- 内容协商
- 多端内容适配
- 默认规则
- 配置协商规则与支持类型
- 自定义内容返回
- 内容协商原理-`HttpMessageConverter`
- `@ResponseBody`由`HttpMessageConverter`处理
- `WebMvcAutoConfiguration`提供集中默认`HttpMessageConverters`
- 模板引擎
- Thymeleaf整合
- 基础语法
- 控制
- 遍历
- 判断
- 属性优先级
- 变量选择
- 模板布局
- devtools
- 错误处理
- 默认机制
- 流程
- 示例
- 前后端分离
- 服务端页面渲染
- 嵌入式容器
- 自动配置原理
- 自定义
- 示例
- 全接管SpringMVC
- `WebMvcAutoConfiguration`自动配置的规则
- `@EnableWebMvc`禁用默认行为
- 实践
- 三种方式
- 两种模式
WEB开发
SpringBoot的WEB开发能力由SpringMVC提供
WebMvcAutoConfiguration
原理
生效条件
@AutoConfiguration(after = { DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })//在这些自动配置后
@ConditionalOnWebApplication(type = Type.SERVLET)//若是web应用则生效,类型SERVLET
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)//容器中没有该Bean则生效,默认没有
@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
组件,给SpringMVC添加各种定制功能
- 所有功能最终和配置文件进行绑定
WebMvcProperties
:spring.mvc
配置文件WebProperties
:spring.web
配置文件
@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)//额外导入其他配置
@EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {
WebMvcConfigurer
接口
提供了配置SpringMVC底层的所有组件入口
静态资源源码规则
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
addResourceHandler(registry, this.mvcProperties.getWebjarsPathPattern(),
"classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
registration.addResourceLocations(resource);
}
});
}
-
访问
/webjars/**
路径去classpath:/META-INF/resources/webjars/
下寻找: -
访问
/**
路径去静态资源默认位置寻找:
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
- 静态资源默认都有缓存规则的设置:浏览器访问了静态资源
index.js
,若其没有发生变化,下次访问则可以直接让浏览器用自己缓存中的内容
registration.setCachePeriod(getSeconds(this.resourceProperties.getCache().getPeriod()));
registration.setCacheControl(this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl());
registration.setUseLastModified(this.resourceProperties.getCache().isUseLastModified());
- 所有缓存设置,直接通过
spring.web
配置文件设置/修改cachePeriod
:缓存周期,以秒为单位cacheControl
:HTTP缓存控制useLastModified
:是否使用最后一次修改,配合HTTP缓存规则
EnableWebMvcConfiguration
规则
SpringBoot给容器中存入WebMvcConfigurationSupport
组件,若开发者自己放置了这个组件,Boot中的WebMvcConfiguration
都会失效
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(WebProperties.class)
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
*HandlerMapping
:根据请求路径/a
查找对应handler
处理请求
WelcomPageHandlerMapping
:找index.html
,只要静态资源位置中存在该页面,则项目启动时默认访问
容器中WebMvcConfigurer
配置底层行为
WebMvcConfiguration
是一个自动配置类,它存在一个EnableWebMvcConfiguration
EnableWebMvcConfiguration
继承于DelegatingWebMvcConfiguration
,两类同时生效DelegatingWebMvcConfiguration
利用 DI 将容器中所有WebMvcConfigurer
注入- 他人调用
DelegatingWebMvcConfiguration
的方法配置底层规则,其方法调用所有WebMvcConfigurer
的配置底层方法
Web场景
自动配置
- 整合场景,引入
starter-web
- 引入
autoconfiguration
@EnableAutoConfiguration
注解使用@Import(AutoConfigurationImportSelector.class)
批量导入组件- 加载
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件配置所有组件 - 绑定配置文件的配置项:
- SpringMVC的所有配置
spring.mvc
- Web场景通用配置
spring.web
- 文件上传配置
spring.servlet.multipart
- 服务器配置
server
,如编码方式等
默认效果
- 包含
ContextNegotiatingViewResolver
和BeanNameViewResolver
组件,方便视图解析 - 默认的静态资源处理机制,使静态资源在
static
文件夹下即可直接访问 - 自动注册
Converter
,GenericConverter
,Formatter
组件,适配常见数据类型转换和格式化需求 - 支持
HttpMessageConverters
,便于返回JSON等数据类型 - 注册
MessageCodesResolver
,便于国际化及错误消息处理 - 支持静态
index.html
- 自动使用
ConfigurableWebBindingInitializer
,实现消息处理、数据绑定、类型转化、数据校验等功能
静态资源
默认规则
静态资源映射
- 规则都定义在
WebMvcAutoConfiguration
/webjars/**
—>classpath:/META-INF/resources/webjars/
/**
—>classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
静态资源缓存
所有静态资源都定义了缓存规则,但此功能参数无默认值
Period
:缓存周期,以秒为单位,默认0s
cacheControl
:HTTP缓存控制,默认无useLastModified
:是否使用最后一次修改,配合HTTP缓存规则,默认false
欢迎页
- 静态资源目录下找
index.html
- 没有时在
templates
下找index
模板页
Favion
静态资源目录下找favicon.ico
作为图标
自定义静态资源规则
配置方式
#spring.web
#开启静态资源映射规则
spring.web.resources.add-mappings=true
#设置缓存
spring.web.resources.cache.period=3600
#浏览器首次请求服务器,服务器告知最大留存时间7200s,此时间内此资源访问不需要再次请求
#覆盖 period 配置
spring.web.resources.cache.cachecontrol.max-age=7200
#使用资源上次修改时间,对比服务器和浏览器资源是否相同,相同返回304
spring.web.resources.cache.use-last-modified=true
#共享缓存
spring.web.resources.cache.cachecontrol.cache-public=true
#自定义静态资源文件夹位置
spring.web.resources.static-locations=classpath:/a/, classpath:/b/
#spring.mvc
#自定义webjars路径前缀
spring.mvc.webjars-path-pattern=/wj/**
#静态资源访问路径前缀
spring.mvc.static-path-pattern=/static/**
代码方式
只要容器中存在一个WebMvcConfigurer
组件,配置的底层行为都会生效
//@EnableWebMvc
//标注则不再保留
@Configuration
//向容器中放置一个WebMvcConfigurer,就能自定义底层
public class MyConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//保留
WebMvcConfigurer.super.addResourceHandlers(registry);
//自定义
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/a/")
.setCacheControl(CacheControl.maxAge(1500, TimeUnit.SECONDS));
}
}
@Configuration
public class MyConfiguration {
@Bean
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/a/")
.setCacheControl(CacheControl.maxAge(1500, TimeUnit.SECONDS));
}
};
}
}
路径匹配
Spring5.3后,支持AntPathMatcher
路径策略外,加入对PathpatternParser
策略的支持
Ant风格路径用法
- 规则:
*
:任意数量字符,*.html
匹配任意扩展名为html
的文件?
:任意一个字符**
:任意数量的目录
/folder1/*/*.java
匹配folder1
目录下两级任意java
文件;
/folder2/**.java
匹配folder2
目录下任意深度的java
文件;
{}
:一个命名的模式占位符,/{type}/{id}.html
匹配任意{type}
目录下任意{id}.html
的文件[]
:字符集合,[a-z]
标识小写字母- 特殊字符转义如
\\*
\\?
等
模式切换
PathpatternParser
较AntPathMatcher
提升了多倍吞吐量,降低部分空间分配率,兼容AntPathMatcher
语法并支持更多类型路径模式,但**
多段匹配只允许在模式末尾使用
默认路径匹配规则是PathpatternParser
,切换语法:
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
内容协商
一套系统适配多端数据返回,SpringMVC拥有
多端内容适配
默认规则
- SpringBoot多端内容适配
- 基于请求头:客户端向服务端发送请求,携带HTTP标准的Accept请求头(默认)
Accept:
application/json
、text/xml
、text/yml
服务器端根据客户端请求头期望的数据类型进行动态返回
- 基于请求参数:(需要开启)
发送请求
GET/projects/spring-boot?format=json
匹配到@GetMapping("/projects/spring-boot") 根据参数协商,优先返回 json 类型数据[需要开启参数匹配] 发送请求
GET/projects/spring-boot?format=xml`优先返回 xml 数据类型
配置协商规则与支持类型
请求相同接口,可以返回 json 和 xml 不同格式数据。在web场景中已经默认引入了jackson包,直接享有json的操作。对xml的操作需要:
- 引入支持写出 xml 的依赖
<!--jackson-->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
- 标注
@JacksonXmlRootElement//写出xml文档
@Data
public class Person {
private Long id;
private String userName;
}
- 开启基于请求参数的内容协商
##开启基于请求参数的内容协商功能,默认参数名:format
spring.mvc.contentnegotiation.favor-parameter=true
##指定内容协商时使用的参数名,默认参数名:format
spring.mvc.contentnegotiation.parameter-name=type
自定义内容返回
- 增加
yaml
返回支持:
依赖
<!--yaml-->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
对象写出YAML
public static void main(String[] args) {
Person person = new Person();
person.setId(1L);
person.setName("Max");
YAMLFactory factory = new YAMLFctory().disable(YAMLGenerator.Feature.WRITE_DOC_START_MAKER);
ObjectMapper mapper = new ObjectMapper(factory);
//...
}
配置,新增媒体类型
spring.mvc.contentnegotiation.media-types.yaml=text/yaml
- 增加其它类型
- 配置媒体类型支持:
spring.mvc.contentnegotiation.media-types.yaml=text/yaml
- 编写对应的
HttpMessageConverter
,告知Boot这个支持的媒体类型- 将
MessageConverter
组件加入到底层:容器中存入WebMvcConfigurer
组件,并配置底层MessageConverter
HttpMessageConverter
的示例写法
public class MyYAMLHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
//将对象转换为YAML
private ObjectMapper objectMapper = null;
public MyYAMLHttpMessageConverter() {
//告知SpringBoot该Converter支持哪种媒体类型
super(new MediaType("text", "yaml", Charset.forName("UTF-8")));
YAMLFactory factory = new YAMLFactory()
.dissable(YAMLGenerator.Feature.WRITE_DOC_START_MAKER);
this.objectMapper = new ObjectMapper(factory);
}
@Override
protected boolean supports(Class clazz) {
/*只要是对象类型,而非基本数据类型,就*/return false;
}
@Override
protected Object readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
@Override
protected void writeInternal(Object methodReturnValue, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
//try...with,自动关流
try(OutputStream os = outputMessage.getBody()) {
this.objectMapper.writeValue(os, methodReturnValue);
}
}
}
内容协商原理-HttpMessageConverter
定制HttpMessageConverter
以实现多端内容协商:编写WebMvcConfigurer
提供的configureMessageConverters
底层,修改底层的MessageConverter
@ResponseBody
由HttpMessageConverter
处理
标注了@ResponseBody
的返回值将会由支持它的HttpMessageConverter
写给浏览器
- 若
controller
方法的返回值标注了@ResponseBody
- 请求先来到
DispatcherServlet
的doDispatch()
方法处理RequestMappingHandlerAdapter
执行,调用invokeHandlerMethod()
执行目标方法- 目标方法执行前,准备:
HandlerMethodArgumentResolver
:参数解析器,确定目标方法每个参数值;
HandlerMethodReturnValueHandler
:返回值处理器,确定如何处理目标方法的返回值
RequestMappingHandlerAdapter
中的invokeAndHandle()
真正执行目标方法- 目标方法执行完成,返回返回值对象
- 找到合适的返回值处理器
HandlerMethodReturnValueHandler
- 最终使用
RequestResponseBodyMethodProcessor
处理标注了@ResponseBody
的方法RequestResponseBodyMethodProcessor
调用writeWithMessageConverters
,利用MessageConverter
将返回值写回
HttpMessageConverter
进行内容协商
- 遍历所有的
MessageConverter
看谁支持此种内容类型数据- 需求
json
所以MappingJackson2HttpMessageConverter
支持写出json
- jackson使用
ObjectMapper
将对象写入
WebMvcAutoConfiguration
提供集中默认HttpMessageConverters
EnableWebMvcConfiguration
通过addDefaultHttpMessageConverters
添加了默认的Messageconverter
如下:
ByteArrayHttpMessageConverter
:字节数据读写
StringHttpMessageConverter
:字符串读写
ResourceHttpMessageConverter
:资源读写
ResourceRegionHttpMessageConverter
:分区资源读写
AllEncompassingFormHttpMessageConverter
:表单xml/json读写
MappingJackson2HttpMessageConverter
请求响应体Json读写
模板引擎
- SpringBoot采取嵌入式Servlet容器,所以JSP默认不能使用。若需要服务端页面渲染,优先考虑使用模板引擎
- 模板引擎页面默认放在
src/resources/templates
- SpringBoot包含自动配置的模板引擎:
- FreeMarker
- Groovy
- Thymeleaf
- Mustache
Thymeleaf整合
<!--Thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
- 自动配置
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration
- 属性绑定在
ThymeleafProperties
中,对应配置文件spring.thymeleaf
- 默认效果:
- 所有模板页面在
classpath:/templates/
中- 查找后缀名为
.html
的页面
- 示例
welcome.html
<!DOCTYPE h
<html lang=
<head>
<meta c
<title>
</head>
<body>
<h1>
hello,<
</h1>
</body>
</html>
WelcomeController.java
@Controller//适配前后端不分离,服务器渲染
public class WelcomeController {
@GetMapping("abc")
public String hello(@RequestParam("name") String name,
Model model) {
//模板的逻辑视图名
//物理视图 = 前缀 + 逻辑视图名 + 后缀
//真实地址 = classpath:/templates/welcome.html
//将需要和页面共享的数据放入model
model.addAttribute("msg", name);
return "welcome";
}
}
基础语法
- 引入thymeleaf名称空间获取提示
<html lang="en" xmlns:th="http://www.thymeleaf.org">
th:*
:动态渲染指定的html标签属性值,或th指令(便利、判断等)
th:text
:标签体内文本值渲染
th:utext
:不将值中标签(若有的话)转义,按照目的显示
th:属性
:标签指定属性渲染th:attr
:标签任意属性渲染th:if
th:each
...
:其它th指令
eg.
<p th:text="${content}">内容</p>
<a th:href="${url}">login</a>
<img src="../../images/a.jpg" th:attr="src=@{/images/a.jpg},title=#{logo},alt=#{logo}" />
- 表达式:用来动态取值
${}
:变量取值;使用model共享给页面的值都用${}
@{}
:url路径,配合${}
可以很安全的传输地址#{}
:国际化消息~{}
:片段引用*{}
:变量选择,配合th:object
绑定对象
- 系统工具&内置对象
param
:获取请求参数session
:直接访问javax.servlet.http.HttpSession
与当前请求关联的对象application
:用于检索应用程序/servlet
上下文属性#execInfo
:提供有关在 Thymeleaf 模板的相关信息#messages
:用于获取变量表达式内的外部化消息的实用方法#uris
:用于在处理url/uri
编码解码#conversions
:允许在模板的任何点执行转换服务#dates
:处理日期工具类#calendars
:日历工具类#temporals
:JDK8+java.time
API工具类#numbers
:处理数字#strings
:字符串工具类#objects
:处理一般对象工具类#bools
:布尔类型处理#arrays
:处理数组#lists
:处理list
工具类#sets
:set
集合工具类#maps
:map
工具类#aggregates
:聚合操作工具类#ids
:用于处理id
可能重复的 方法
控制
遍历
- 语法:
th:each="param, state : ${集合}"
- 若没有显式地设置状态变量,则Thymeleaf将创建⼀个默认变量,该变量名为迭代变量+“Stat”
paramStat
<tr th:each="user,item:${users}">
<td th:text="${item.index}"></td>
<td th:text="${item.count}"></td>
<td th:text="${item.size}"></td>
<td th:text="${item.current}"></td>
<td th:text="${item.even}"></td>
<td th:text="${item.odd}"></td>
<td th:text="${item.first}"></td>
<td th:text="${item.last}"></td>
</tr>
<!--
index:当前迭代索引,从 0 开始。
count:当前迭代索引,从 1 开始。
size:迭代变量中的元素总数。
current:每次迭代的iter 变量。
even/odd:当前迭代是偶数还是奇数。
first:当前迭代是否是第一个。
last:当前迭代是否是最后一次。
-->
判断
th:if
eg.
<td th:if="${#strings.isEmpty(person.email)}" th:text="cant connect"></td>
<td th:if="${not #strings.isEmpty(person.email)}" th:text="${person.email}"></td>
th:switch
<td th:switch="${animal.kind}">
<p th:case="cats" th:color="red">cat</p>
<p th:case="dogs" th:color="blue">dog</p>
</td>
属性优先级
当标签中有多个属性时,按照优先级执行
Order | Feature | Attributes |
---|---|---|
1 | 片段包含 | th:insert th:replace |
2 | 遍历 | th:each |
3 | 判断 | th:if th:unless th:switch th:case |
4 | 定义本地变量 | th:object th:with |
5 | 通用方式属性修改 | th:attr th:attrprepend th:attrappend |
6 | 指定属性修改 | th:value th:href th:src ... |
7 | 文本值 | th:text th:utext |
8 | 片段指定 | th:fragment |
9 | 片段移除 | th:remove |
变量选择
<div>
<p>name:<span th:text="${animal.kind.name}">cookie</span></p>
</div>
<!--替换-->
<div th:object="${animal.kind}">
<p>name:<span th:text="*{name}">cookie</span></p>
</div>
模板布局
- 定义模板:
th:fragment
- 引用模板:
~{templatename :: selector}
- 插入模板:
th:insert
th:replace
fragment.html
<footer th:fragment="myFooter" ...></footer>
quote.html
<div th:replace="~{fragment :: myFooter}"></div>
devtools
html
中的修改使用ctrl+F9
即可刷新页面效果;
Java代码中的修改不建议使用此工具,易引起某些不易排查的问题
<!--devtools热启动工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
错误处理
默认机制
- 默认机制储存在
ErrorMvcAutoConfiguration
中
- SpringBoot会自适应处理错误,区分响应页面或JSON数据
- SpringMVC的错误处理机制仍旧发挥作用,处理不了时再移交给Boot处理
- 错误发生后,会被转发给
/error
路径,SpringBoot在底层放置了一个BasicErrorController
组件,专门处理该请求
//返回HTML
@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);
}
//返回 ResponseEntity,JSON
@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);
}
- 错误页面解析
//解析错误视图地址
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
//若解析不到,则给出 error 默认错误页
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
- 容器中有一个默认名为
error
的视图,提供了默认白页
@Bean(name="error")
@ConditionlOnMissBean(name="error")
public View defaultErrorView() {
return this.defaultErrorView;
}
流程
- 在错误移交至Boot手中后,受
BasicErrorController
管理 - 需求JSON数据,则
DefaultErrorAttributes
获取信息并返回 - 需求页面
- 在
templates/error
中精确匹配错误状态码对应的页面- 在静态资源目录中匹配
4xx.html
、5xx.html
对应页面- 匹配
error
视图- SpringBoot默认提供的名为
error
的页面
示例
前后端分离
后台发生的所有错误,统一由@ControllerAdvice
+ @ExceptionHandler
进行异常处理
服务端页面渲染
- 给
classpath/templates/error
下,放置精确匹配精确码.html
- 给
classpath/templates/error
下,放置模糊匹配4(5)xx.html
- 业务错误:
- 核心业务:每种错误都应有代码控制,跳转至对应定制的错误页面
- 通用业务:
classpath/templates/error.html
页面显示错误信息
嵌入式容器
管理、运行Servlet组件的环境,一般指服务器
自动配置原理
- SpringBoot默认嵌入Tomcat作为Servlet容器
- 自动配置类为
ServletWebServerFactoryAutoConfiguration
、EmbeddedWebServerFactoryCustomizerAutoConfiguration
- 自动配置类开始分析功能:
*AutoConfiguration
@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 {...}
ServletWebServerFactoryAutoConfiguration
自动配置了嵌入式容器场景- 绑定
ServerProperties
配置类,所有服务器相关的配置server
ServletWebServerFactoryAutoConfiguration
导入了Tomcat、Jetty、Undertow
- 导入嵌入式服务器都有条件注解,系统中须有此类(已导包)
- 默认Tomcat配置,向容器中放置
TomcatServletWebServerFactory
- 向
ServletWebServerFactory
放置web服务器工厂- web服务器工厂使用
getWebServer
获取web服务器TomcatServletWebServerFactory
创建tomcat
- IoC容器
ServletWebServerApplicationContext
,启动时调用创建web服务器 - Spring容器刷新(启动)时存在一个时机用以刷新子容器
- refresh()容器刷新会调用
onRefresh()
自定义
切换已提供的服务器:
<properties>
<servlet-api.version>3.1.0</servlet-api.version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--ban tomcat-->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--use jetty-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
示例
用法:
- 修改
server
下的相关配置可以修改服务器参数 - 通过给容器中放一个
ServletWebServerFactory
以禁用SpringBoot默认的服务器工厂,实现自定义嵌入
全接管SpringMVC
- SpringBoot默认配置了SpringMVC所有常用特性
- 若我们需要全面接管SpringMVC并禁用所有默认配置,只需
WebMvcConfigurer
配置类并标注@EnableWebMvc
即可
WebMvcAutoConfiguration
自动配置的规则
@EnableWebMvc
禁用默认行为
@EnableWebMvc
向容器中导入DelegatingWebMvcConfiguration
组件,其自身继承WebMvcConfigurationSupport
WebMvcConfiguration
存在核心注解@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
:容器中没有WebMvcConfigurationSupport
,WebMvcConfiguration
才生效
实践
- SpringBoot已经默认配置了Web开发常用功能
三种方式
全自动 | 直接标注控制器逻辑 | 全部使用自动配置默认效果 |
---|---|---|
半自动 | @Configuration +WebMvcConfigurer +WebMvcRegistrations 不标注 @EnableWebMvc | 自动配置效果 手动设置部分功能 定义MVC底层组件 |
全手动 | @Configuration +WebMvcConfigurer 标注 @EnableWebMvc | 禁用自动配置效果 全手动设置 |
两种模式
- 前后端分离模式:
@RestController
响应JSON数据 - 前后端不分离模式:
@Controller
+Thymeleaf
模板引擎