使用SpringBoot2进行Web开发
一、对SpringMVC的自动配置
1.1 自动配置
SpringBoot中自动配置了SpringMVC,大多场景我们都不需要自定义配置。
在Spring的基础上,SpringBoot添加了以下的特征:
ContentNegotiatingViewResolver
(内容协商视图解析器)和BeanNameViewResolver
(BeanName)视图解析器- 支持静态资源,包括webjars
- 自动注册
Converter,GenericConverter,Formatter
- 支持
HeepMessageConverters
- 自动注册
MessageCodesResolver
,用于国际化 - 静态index.html支持
- 自定义facicon
- 自动使用
ConfigurableWebBindingInitializer
,(DataBinder负责将请求数据绑定到JavaBean上)
1.2 自定义配置
SpringBoot为我们提供了WebMvcConfigurer
接口,可以实现对SpringMVC的各项自定义功能:
1 |
|
我们有两种方式自定义这个接口,都需要先准备一个配置类:
- 直接实现接口,然后按需实现其中的方法。
- 使用@Bean注解返回组件。
两种方式的代码如下:
1 |
|
1 |
|
关于SpringMVC的功能定制,都可以在这个配置类中进行自定义。
二、简单功能分析
2.1 静态资源访问
2.1.1 静态资源目录
SpringBoot默认将静态资源放在以下目录,查找顺序从上往下:
main/resources/META-INF/resources
main/resources/resources
main/resources/static
main/resources/public
以上文件夹的静态资源访问时,使用当前项目根路径/静态资源名
即可访问。
SpringBoot底层使用/**
拦截了所有请求。当收到一个请求时,会先判断controller能不能处理,如果不能处理就交给静态资源处理,都不能处理则返回404。
2.1.2 静态资源访问前缀
默认静态资源访问无前缀,可以通过配置,改变默认的静态资源访问前缀和访问路径:
1 |
|
如果添加了静态资源的访问前缀,这样访问所有静态资源都要使用指定的前缀。
如果修改了静态资源的目录,这样只能访问指定路径下的静态资源,默认的路径全失效。
2.1.3 webjar
项目路径/webjars/**
需要引入依赖,比如引入webjars的jquery:
1 |
|
此时访问地址为:http://localhost:8080/webjars/jquery/3.5.1/jquery.js
,后面的地址需要按照依赖里面的包路径。
2.2 欢迎页支持
SpringBoot支持欢迎页,默认静态资源路径下的index.html会被当作欢迎页。
可以配置静态资源路径。
但是如果配置了静态资源的访问前缀,欢迎页就会失效,因为源码中判断只能在默认静态资源路径中访问欢迎页:
1 |
|
2.3 自定义Favicon
将图标命名为favicon.ico
,并放在静态资源目录下即可。同样地,静态资源访问前缀会导致其失效。
2.4 静态资源配置原理
2.4.1 资源处理的默认规则
1、SpringBoot启动默认加载自动配置类。
2、添加了Web框架支持的项目会自动导入web常见启动器,然后SpringMVC的自动配置类 WebMvcAutoConfiguration
就会生效:
1 |
|
3、WebMvcAutoConfiguration
中有一个静态内部类,WebMvcAutoConfigurationAdapter
:
1 |
|
可以看到,其绑定了三个xxxProperties类,这三个类中定义了SpringMVC应用的参数的默认值,并且绑定了配置文件中的spring.mvc
、spring.resources
、spring.web
三个对应的配置前缀,我们只需要在配置文件中配置这些参数即可修改默认值。其中在WebProperties
这个类中,就定义了静态资源的默认访问路径。
这个内部类,只有一个有参构造器,这个构造器中所有参数的值都会从容器中确定,构造器代码:
1 |
|
2.4.2 欢迎页的处理规则
1 |
|
三、请求映射和参数处理
3.1 请求映射
3.1.1 REST的使用与原理
使用
使用xxxMapping
注解表示对收到的请求进行处理。
RequestMapping
:适用于各种请求@GetMapping
:只适用于get请求,RESTful风格中表示获取、查询信息@PostMapping
:只适用于post请求,RESTful风格中表示添加信息@PutMapping
:只适用于put请求中,RESTful风格中表示修改信息@DeleteMapping
:只适用于delete请求,RESTful风格中表示删除信息。
form表单只支持get和post两种提交方式,如何确保请求方式为put和delete呢?
方法:
首先需要在配置文件中开启隐藏域方法支持,SpringBoot2.5.2已经默认开启了:
1
2
3
4
5spring:
mvc:
hiddenmethod:
filter:
enabled: trueform表单中有一个隐藏方法域,在其中定义请求方式,需要在
method=post
的前提下使用:test.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<form action="/user" method="get">
<input value="REST-GET提交" type="submit"/>
</form>
<form action="/user" method="post">
<input value="REST-POST提交" type="submit"/>
</form>
<!-- 必须在post请求里面定义_method隐藏域才能生效 -->
<form action="/user" method="post">
<input name="_method" type="hidden" value="delete"/>
<input value="REST-DELETE提交" type="submit"/>
</form>
<form action=" /user" method="post">
<input name="_method" type="hidden" value="PUT"/>
<input value="REST-PUT提交" type="submit"/>
</form>这样,在controller收到请求后,如果是post请求,带有_method隐藏域的话,会获取其value值,确认请求方式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19@GetMapping("/user")
public String getUser(){
return "GET请求";
}
@PostMapping("/user")
public String saveUser(){
return "POST请求";
}
@PutMapping("/user")
public String putUser(){
return "PUT请求";
}
@DeleteMapping("/user")
public String deleteUser(){
return "DELETE请求";
}
我们也可以自定义过滤器,将_method修改为自定义的字符串。根据源码分析可以,我们需要对HiddenHttpMethodFilter
这个过滤器组件进行配置。
因此我们定义一个配置类,在其中使用@Bean
注解,注入我们自定义的组件,这样底层就会使用我们手动注入的组件:
1 |
|
REST原理
- 表单提交的时候,会带上隐藏域_method
- 请求会被
HiddenHttpMethodFilter
拦截,判断请求是否正常,并且是POST方式,才做以下操作:- 获取到_method的值,将value的值统一转化为大写。
- 会兼容PUT、DELETE、PATCH三种请求
- 原生request的包装(装饰器)模式,
requestWrapper
重写了getMethod()
方法,返回的是传入的值。 - 过滤器链放行的时候,使用的是wrapper,以后的方法调用的都是requestWrapper的
getMethod()
方法
3.1.2 请求映射原理
SpringMVC的功能分析都从DispatcherServlet
的doDispatch()
方法入手,其继承体系如下:
doDispatch()
方法会遍历查找,找到当前请求会使用哪个Handler(即Controller方法)进行处理。
具体来说,所有的请求映射,都会保存在HandlerMapping
中。
共有以下几种HandleMapping
RequestMappingHandlerMapping
WelcomePageHandlerHandlerMapping
BeanNameUrlHandlerMapping
RouterFunctionHandlerMapping
SimpleUrlHandlerMapping
:
- 比如
WelcomePageHandlerMapping
,就能够访问index.html
这个页面 - SpringBoot自动配置了默认的
RequestMappingHandlerMapping
- 请求进来后,会依次遍历所有的
HandlerMapping
,查看是否有请求信息。- 如果有就找到这个请求对应的
handler
- 如果没有就继续查找下一个
HandlerMapping
- 如果有就找到这个请求对应的
如果我们需要自定义的映射处理,我们可以定义自己的HandlerMapping
。具体做法为在配置类中,使用@Bean
注入定义的组件,在方法里面自定义我们自己的组件。
3.2 参数处理
这里的参数处理主要指的是控制器(controller)方法中的参数。
3.2.1 基本注解
在参数中,可以使用以下注解:
@PathVariable
:路径变量,比如RESTful风格的变量
@RequestHeader
:获取请求头
@RequestAttribute
:获取请求域属性
@RequestParam
:获取请求参数,比如url中?
后面的变量
@RequestBody
:获取请求体
@MatrixVariable
:矩阵变量。如果矩阵变量同名,可以使用这个注解的pathVar
进行区分。使用详情参考:矩阵变量
@CookieValue
:获取cookie值
3.2.2 Servlet API
除了在参数位置使用简单的注解外,我们还可以传入Servlet API类型的参数。
比如在controller中进行结果跳转的时候,我们有一种使用Servlet API的方式进行跳转:
1 |
|
通过debug源码可知,对HttpServletRequest
类型的参数解析,使用的是名为ServletRequestMethodArgumentResolver
的参数解析器进行解析的,这个参数解析器能够解析的所有类型如下:
1 |
|
3.2.3 复杂参数
controller方法中的参数也可以是Map、Model、ModelMap、ModelAndView类型的对象。
这些类型的对象里面的数据,会被放到请求域中。
3.2.4 自定义对象参数
controller方法中的参数也可以是自定义类型,会自动将参数名和变量名匹配。如果不匹配的则值为null
。
比如:
1 |
|
3.3 参数处理原理
HandlerMapping
中找到能够处理请求的Handler
,然后为当前Handler
找一个适配器,即HandlerAdapter
,比如说RequestMappingHandlerAdapter
。
适配器执行目标方法并确定方法参数的每一个值。大致流程如下:
1、执行目标方法。
1 |
|
执行目标方法的细节进一步分析如下。
2、确定要执行的目标方法的每一个参数的值是什么。SpringMVC目标方法能写多少种参数类型,取决于参数解析器。
在InvocableHandlerMethod
类的getMethodArgumentValues
方法中确定目标方法每个参数的值。
底层会遍历参数解析器,如果当前参数解析器能解析当前参数,就调用这个解析器的相关方法进行解析。
3、返回值处理器。返回值处理由返回值处理器进行处理,比如ModelMethodProcessor
、ResponseBodyEmitterReturnValueHandler
等。
4、当目标方法完成后,所有的数据都会保存在ModelAndViewContainer
中,其中包含了视图View
,以及Model
数据。
5、最后处理派发结果,调用processDispatchResult()
方法。
在执行的过程中,底层会将model
中的所有数据都放到请求域中:
1 |
|
3.4 自定义类型参数封装POJO
底层对参数封装为POJO对象的时候,定义了大量的类型转换器(converter),比如StringToNumber
是字符串转为数字类型的一个转换器。
其中在进行封装之前,会调用isSimpleValueType
方法判断是否是简单类型。
如果我们想自定义一个类型转换器,参考源码中类型转换器的写法,我们可以在WebDataBinder
里面放入自己定义的Converter.
在配置类中,自定义WebMvcConfigurer
组件:
1 |
|
这样,当我们收到一个字符串dog,3
的时候,也能够将其解析并封装到Pet
中的name
和age
中。
四、数据响应与内容协商
4.1 响应JSON
SpringBoot的Web场景自动引入了JSON场景,可以返回JSON数据
4.2 返回值解析器
前面说过,controller的返回值是要经过返回值处理器(解析器)进行处理的:
- 返回值解析器判断是否支持这种类型返回值—-
supportsReturnType
- 返回值解析器调用
handleReturnValue
处理 RequestResponseBodyMethodProcessor
可以处理标了@ResponseBody
注解方法:- 利用
MessageConverters
进行处理,将数据写为JSON:- 内容协商:浏览器默认会以请求头的方式告诉服务器能够接收什么类型的数据;服务器根据自己的能力,决定能生产出什么内容类型的数据。
- 其中,SpringMVC会依次遍历容器底层所有的
HttpMessageConverter
(消息转换器),看谁能对数据进行处理。比如,MappingJackson2HttpMessageConverter
可以将对象转为JSON数据再写出去。
- 利用
SpringMVC支持的返回值类型
1 |
|
关于HttpMessageConverter
消息转换器,HttpMessageConverter
接口中有canRead()
和canWrite()
方法,用于判断当前消息转换器能够对数据进行读和写。
默认的消息转换器包括:
ByteArrayHttpMessageConverter
:支持Byte类型StringHttpMessageConverter
:支持String类型ResourceHttpMessageConverter
:支持Resource类型ResourceRegionHttpMessageConverter
:支持ResourceRegion类型SourceHttpMessageConverter
:支持DOMSource、 SAXSource、 StAXSource、StreamSource、Source类型。AllEncompassingFormHttpMessageConverter
:支持MultiValueMap类型MappingJackson2HttpMessageConverter
:无论什么类都返回true,可以将任何类型的对象转换为浏览器所想要的数据类型;Jaxb2RootElementHttpMessageConverter
:支持注解方式xml处理的
4.3 内容协商
内容协商指的是,根据客户端接收能力不同,返回不同媒体类型的数据。
SpringBoot中的Web场景引入了JSON依赖,因此可以返回JSON数据,但没有引入XML依赖,如果想要返回XML类型的数据,需要手动引入以下依赖:
1 |
|
4.3.1 开启内容协商功能
SpringBoot的内容协商功能默认是关闭的,可以手动开启:
1 |
|
开启内容协商功能后,可以使用format参数指定要接收的参数类型,方便浏览器通过修改参数的方式完成内容协商。
比如:
http://localhost:8080/test/person?format=json
请求会返回JSON类型的数据;
http://localhost:8080/test/person?format=xml
请求会返回XML类型的数据。
4.3.2 内容协商原理
1、首先判断当前响应头是否已经有确定的媒体类型(MediaType)
2、获取客户端支持接受的内容类型
3、遍历循环当前系统的MessageConverter
,看谁支持操作这个对象
4、找到支持操作当前对象的消息转换器,把这个消息转换器支持的媒体类型统计出来。
5、进行内容协商,选出最佳匹配的媒体类型
6、用这个能够将对象转化为最佳匹配类型的转换器,进行转化
4.3.3 自定义消息转换器
参考官方文档:Path Matching and Content Negotiation
如果我们想定义自己的消息转换器,比如我们想要传入format=gg
,解析为application/x-guigu
类型。
首先需要定义转换器,实现HttpMessageConverter
接口:
1 |
|
然后,我们需要将我们自己的消息转换器添加到底层的消息转换器中,
1 |
|
这样,我们就可以在format参数传入gg关键字,将会调用自定义的转换器转换为x-guigu
类型。
注意到,我们如果重写内容协商器,可能会导致一些默认的功能失效,推荐的方式是在配置文件中使用配置,想要自定义什么就配置什么,SpringBoot已经帮我们把能够自定义的内容都绑定到了配置文件中,只需要按需配置即可。
1 |
|
添加配置,当format参数为gg时,映射为application/x-guigu。
五、视图解析与模版引擎
SpringBoot默认不支持JSP,需要引入第三方模版引擎技术实现页面渲染
5.1 视图解析
视图解析流程:
1、目标方法处理的过程中,所有数据都会放在ModelAndViewContainer中,包括数据和视图地址
2、任何目标方法执行完成后,都会返回一个ModelAndView
3、processDispatchResult
处理派发结果,即页面如何响应
- 调用
render(mv,request,response)
方法进行页面渲染:- 根据方法的String返回值得到View对象
- 所有的视图解析器尝试是否能根据当前返回值得到View对象,找到以后就进行渲染。
- 如果是
redirect
开头,表示重定向的返回值,则会调用response.sendRedirect()
重定向;请求转发也是如此。
- 根据方法的String返回值得到View对象
总结:
- 返回值以
forward:
开始,则调用new InternalResourceView(forwardUrl);
进行请求转发。- 内部调用
request.getRequestDispatcher(path).forward(request, response);
- 内部调用
返回值以
redirect:
开始,则调用new RedirectView()
进行重定向。返回值是普通字符串:
new ThymeleafView()
5.2 模版引擎-Thymeleaf
Thymeleaf是现代化的服务端Java模版引擎,能够处理HTML、XML、JavaScript、CSS,甚至纯文本数据(Plain Text)。
SpringBoot默认不支持JSP,因此我们使用Thymeleaf模版引擎代替JSP功能。
Thymeleaf的使用方法参考官方Thymeleaf、Thymeleaf的使用
表达式名字 | 语法 | 用途 |
---|---|---|
变量取值 | ${…} | 获取请求域、session域、对象等值 |
选择变量 | *{…} | 获取上下文对象值 |
消息 | #{…} | 获取国际化等值 |
链接 | @{…} | 生成链接 |
片段表达式 | ~{…} | jsp:include 作用,引入公共页面片段 |
SpringBoot为我们自动配置好了Thymeleaf,我们只需要引入Thymeleaf
依赖,然后开发页面即可。
1 |
|
1 |
|
此外,需要在html
页面加入Thymeleaf命名空间:
1 |
|
可以看到,我们的controller返回视图名的时候,底层会自动添加前缀和后缀,类似于SpringMVC的视图解析器。
默认情况下我们将页面放到templates
文件夹,并且后缀名为.html
。
六、拦截器
6.1 配置拦截器
自定义拦截器的步骤如下
1、编写一个拦截器类,实现HandlerInterceptor
接口。
2、将拦截器注册到容器中,即实现WebMvcConfigurer
的addInterceptors
方法
3、指定拦截规则。如果拦截所有请求(/**
),静态资源也会被拦截。可以使用配置静态资源路径或手动排除静态资源请求两种方式解决。
代码如下:
1、实现接口
1 |
|
2、放到容器中
1 |
|
排除静态资源:
方式一:排除静态资源请求,比如上述代码。
方式二:设置静态资源的访问路径,比如拦截所有以
/static
开头的静态资源请求,配置语句为:1
spring.mvc.static-path-pattern=/static/**
6.2 拦截器原理
1、根据当前请求,找到HandlerExecutionChain
,即可以处理请求的handler
以及handler
的所有拦截器.
2、先顺序执行每个拦截器的preHandle()
方法,根据这个方法的返回值决定下一步:
- 如果当前拦截器的
preHandle()
方法返回true
,则继续执行下一个拦截器的preHandle()
方法 - 如果任何一个拦截器的
preHandle()
方法返回false
,直接倒序执行所有已经执行了的拦截器的afterCompletion
。不会执行目标方法。
3、只有所有的拦截器都返回true
的时候,才执行目标方法。
4、然后倒序执行所有拦截器的postHandle()
方法。
5、前面的任何步骤出现异常,都会直接倒序执行afterCompletion()`方法。
6、页面渲染完成后,倒序执行afterCompletion()
方法。
七、文件上传
7.1 实现上传和接收
页面表单:
1 |
|
服务端处理:
1 |
|
服务端使用 @RequestPart
注解和MultipartFile
类型来处理文件类型的数据。
7.2 文件上传原理
1、文件上传配置类MultipartAutoConfiguration
自动配置好了文件上传解析器StandardServletMultipartResolver
,其组件id为multipartResolver
。
2、对于接收到的请求,文件上传解析器判断(isMultipart
)并封装(resolveMultipart
),返回文件上传请求MultipartHttpServletRequest
3、参数解析器解析请求中的文件内容,并封装成MultipartFile
4、将request中的文件信息封装为Map,即MultiValueMap<String, MultipartFile>
,实现文件流的拷贝。
八、异常处理
8.1 默认规则
默认情况下,Spring Boot提供/error
处理所有错误的映射。
对于机器客户端,它将生成JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。
对于浏览器客户端,响应一个“Whitelabel”错误视图,以HTML格式呈现相同的数据。
1 |
|
如果相对其自定义,可以手动添加一个error视图。
其中,/error目录下的4xx,5xx页面会被自动解析,按照状态码匹配,优先精准匹配,没有就模糊匹配。
8.2 定制错误处理逻辑
8.2.1 自定义错误页
自定义错误页:将4xx.html和5xx.html错误页放到/templates
或/static
目录下的error
文件夹,即可自动匹配。优先精确匹配,然后模糊匹配。都没有,则返回WhilteLabel
当发生异常时,底层会结束当前请求,并记录错误信息和状态码等信息;然后重新发送一个error请求,将HTTP的状态码作为视图页地址(viewName),找到error/4xx.html等错误页。
8.2.2 自定义异常处理
1、使用@ControllerAdvice+@ExceptionHandler处理全局异常
比如处理空指针异常、除数为0时的异常等,可以使用这种方式。当发生指定的错误时,会执行这个方法。
底层是ExceptionHandlerExceptionResolver
支持的。
1 |
|
2、使用@ResponseStatus+自定义异常类
比如处理具体某个方法出现错误时,抛出自定义异常和异常信息。
1 |
|
如果出现这个类的异常,会返回状态码403和错误信息。比如 throw new UserTooManyException()
时,就会触发这个异常,然后返回信息。
3、自定义异常解析器
自定义的异常解析器,可以作为默认的全局异常处理规则。
1 |
|
底层会优先遍历DefaultErrorAttributes
和HandlerExceptionResolverComposite
这两个,第二个里面又有三个解析器,会处理所有异常。因此想要使我们自定义的生效,必须将其优先级放到默认的两个前面。
sendError()
方法表示此次请求立即结束,底层tomcat服务器会抛出error
,SpringMVC底层会专门处理这个error
,即BasicErrorController
处理。
调用response.sendError()
,请求会转给controller处理,如果没有解析器能够处理,则tomcat底层会执行这个方法,交给basicErrorController
处理。
8.3 异常处理原理
1、执行目标方法,目标方法运行期间有任何异常都会被catch,而且标志当前请求结束;并且用 dispatchException
保存catch到的异常。
2、进入视图解析流程:
1 |
|
有异常时,mv为null
,异常信息被保存到dispatchException
中
3、mv = processHandlerException;
用于处理handler发生的异常,并处理完成返回ModelAndView,具体步骤如下:
- 遍历所有的
handlerExceptionResolvers
,找到能处理这个异常的解析器。 - 系统默认有两个异常解析器,即
DefaultErrorAttributes
和HandlerExceptionResolverComposite
。默认情况下,DefaultErrorAttributes
先处理异常,把异常信息保存到请求域,并返回null
。 - 默认情况下,没有解析器能处理异常,因此异常会被抛出:
- 异常不能处理,则底层会发出
/error
请求,被底层的BasicErrorController
处理 - 解析错误视图,遍历所有的错误视图解析器,看谁能处理。
- 默认的
DefaultErrorViewResolver
,作用是把响应状态码作为错误页的地址,比如error/500.html
- 模版引擎最终会响应这个页面
error/500.html
。
- 异常不能处理,则底层会发出
错误页面的查找顺序:
1 |
|
九、原生组件注入与嵌入式Servlet容器
9.1 原生组件注入
Web原生组件,比如servlet、filter、listener注入,有两种方式。
方式一:使用Servlet API注解
@WebServlet(urlPatterns = "/my")
`@WebFilter(urlPatterns={"/css/*","/images/*"})
@WebListener
1 |
|
用在自定义的servlet类中。这样,http://localhost:8080/my
就可以返回”hello”
/my
请求会直接响应,没有被拦截器拦截。
如果使用以上注解,需要在主类中使用@ServletComponentScan
进行扫描,用于指定原生Servlet、filter、listener组件的位置。
1 |
|
为什么这里定义的/my
没有被拦截器拦截呢?
SpringMVC的请求优先经过DispatcherServlet
,需要对其进行分析:
容器中自动配置了
DispatcherServlet
,属性绑定到WebMvcProperties
;对应的配置文件配置项是spring.mvc
配置spring.mvc.servlet.path为dispatchSerlvet中拦截的路径
配置server.servlet.context-path为上下文路径,请求访问的前缀
也是通过
ServletRegistrationBean<DispatcherServlet>
把 DispatcherServlet 配置进来。默认映射的是
/
路径
Tomcat-Servlet,如果多个Servlet都能处理到同一层路径,精确优先原则。因此对于/
和/my
来说,/my
请求精准匹配到自定义的servlet,因此不会经过dispatcherServlet
处理,所以不会被拦截器拦截。
方式二:使用RegistrationBean
如果不使用注解,还可以手动实现一个配置类,将它们注入。
在配置类中:
1 |
|
9.2 嵌入式Servlet容器
SpringBoot内嵌了web服务器,比如tomcat、Jetty、Undertow。默认使用的是tomcat
在pom.xml
中排除tomcat依赖,再将要切换到的服务器的starter导入即可实现切换:
1 |
|
我们还可以定制servlet容器,根据文档或者仿照源码。
十、定制化总结
SpringBoot中的Web项目定制化的几种方式
- 修改配置文件;
xxxxxCustomizer定制器;
编写自定义的配置类,然后用
@Bean
替换、增加容器中默认组件;- 对于Web应用,还可以编写一个配置类实现
WebMvcConfigurer
接口, 即可定制化web功能;使用@Bean可以给容器中再扩展一些组件;比如:
1 |
|
@EnableWebMvc
+WebMvcConfigurer
可以全面接管SpringMVC,使用这种方式,所有自动配置的功能会全部失效,需要全部自己重新配置; 配合@Bean
实现定制和扩展功能。
@EnableWebMvc会使SpringBoot关于WebMVC的自动配置全部失效,其功能都需要自己写。
一般分析自动配置的流程:场景启动器—>xxxAutoConfiguration—>导入xxx组件,绑定xxxProperies—>其绑定了配置文件中的配置项。
- 本文作者:Kangshitao
- 本文链接:http://kangshitao.github.io/2021/07/11/springboot-web/index.html
- 版权声明:本博客所有文章均采用 BY-NC-SA 许可协议,转载请注明出处!