SpringBoot 2.3.4
本文最后更新于:2021年4月7日 晚上
SpringBoot Notes
本文基于SpringBoot 2.3.4.RELEASE
一、SpringBoot简介
官网介绍:
- Create stand-alone Spring applications
- Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
- Provide opinionated ‘starter’ dependencies to simplify your build configuration
- Automatically configure Spring and 3rd party libraries whenever possible
- Provide production-ready features such as metrics, health checks, and externalized configuration
- Absolutely no code generation and no requirement for XML configuration
- 创建独立的
spring
应用。 - 嵌入
Tomcat
,Jetty
Undertow
而且不需要部署他们。 - 提供的“starters” poms来简化
Maven
配置 - 尽可能自动配置
spring
应用。 - 提供生产指标,健壮检查和外部化配置
- 绝对没有代码生成和
XML
配置要求。
一般把Spring Boot称为搭建程序的 脚手架 或者说是便捷搭建 基于Spring的工程 脚手架。其最主要作用就是帮助开
发人员快速的构建庞大的spring项目,并且尽可能的减少一切xml配置,做到开箱即用,迅速上手,让开发人员关注业务而非配置。
时代背景
SpringBoot基于微服务以及分布式
二、SpringBoot基础
2.1 SpringBoot 特点
2.1.1 依赖管理
1 |
|
- 其父项目, 自动版本仲裁机制
1 |
|
- 自定义版本号
- 1、查看spring-boot-dependencies里面规定当前依赖的版本 用的 key。
- 2、在当前项目里面重写配置,如下自定义mysql 的版本
1 |
|
基础依赖
1 |
|
- spring-boot-starter:spring boot场景启动器
- Spring把每个场景都抽取出来,做成了一个个starts
- 如我们需要那个场景只需要把对应的启动器来导入进来就可以,不用担心版本。
- 用什么功能(Web、缓存、kafka等等)导入相关启动器即可
注解区别
@Controller
和@RestController
的区别
@RestController
注解相当于@ResponseBody
+ @Controller
合在一起的作用。
- 如果只是使用@RestController注解Controller,则Controller中的方法无法返回jsp页
面,或者html,配置的视图解析器InternalResourceViewResolver
不起作用,返回
的内容就是 Return 里的内容。 - 如果需要返回到指定页面,则需要用 @Controller 配合视图解析器
InternalResourceViewResolver才行。 如果需要返回JSON,XML或自定义
mediaType内容到页面,则需要在对应的方法上加上@ResponseBody注解。
即:
- 使用@Controller 注解
- 在对应的方法上,视图解析器可以解析return 的jsp,html页面,并且跳转到相应页面
- 若返回json等内容到页面,则需要加@ResponseBody注解
- @RestController注解
相当于@Controller+@ResponseBody两个注解的结合。
返回json数据不需要在方法前面加@ResponseBody注解了
使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析
jsp,html页面
打包插件
1 |
|
2.1.2 自动配置
- 以
spring-boot-starter-web
为例,进入父工程可发现
1 |
|
- Tomcat
- 配置了Tomcat
1 |
|
- SpringMVC
- 自动配置MVC常用组件
1 |
|
- Web
- 自动配置好Web常见场景,比如字符编码问题。
1 |
|
默认包结构
- 主程序所在包下所有自包的组件都会默认扫描,不需要以前的包扫描配置
- 想要改变扫描路劲:
@SpringBootApplication(scanBasePackages="com.xxx")
或@ComponentScan 指定扫描路径
各种配置拥有默认值
- 默认配置最终都是映射到某个类上,如:MultipartProperties
- 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
按需加载所有自动配置项
- 非常多的starter
- 引入了哪些场景这个场景的自动配置才会开启
- SpringBoot所有的自动配置功能都在
spring-boot-autoconfigure
包里面
2.2 容器功能
2.2.1 组件添加
@Configuration
配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
配置类本身也是组件
proxyBeanMethods:代理bean的方法。
Full
(proxyBeanMethods = true) 「保证每个@Bean
方法被调用多少次返回的组件都是单实例的」Lite
(proxyBeanMethods = false)「每个@Bean方法被调用多少次返回的组件都是新创建的」‘
组件依赖必须使用Full模式默认。其他默认是否Lite模式。
1 |
|
@Bean
、@Component
、@Controller
、@Service
、@Repository
照常使用即可。
@ComponentScan
、@Import
- 前面自定义扫描包用到了@ComponentScan,用来扫描所有的组件
- @Import 给容器中自动创建出这对应类型的组件、默认组件的名字就是全类名
@Conditional
- 条件装配,满足Conditional指定的条件进行注入。
- Ctrl + H (Intellij IDEA) 打开@Conditional的实现类
- ConditionalOnMissingClass - 不存在某个类时注入
- ConditionalOnBean - 存在某个Bean时注入
- 其余的根据名字可以判断含义
2.2.2 原生配置文件引入
@ImportResource
- @ImportResource(“classpath:beans.xml”)导入Spring的配置文件
- 用于已经有大量Bean在xml文件中注入了,就使用此方式导入。可用于老项目更新迭代。
2.2.3 配置绑定
1.
@ConfigurationProperties
+@Component
在实体类上加上注解 @Component 和 @ConfigurationProperties
@Component让实体类成为容器组件,才能让底层自动配置
1 |
|
- 2.
@EnableConfigurationProperties
+@ConfigurationProperties
- 在配置类上加上@EnableConfigurationProperties,开启Car类的绑定功能
- @ConfigurationProperties加载实体类上,prefix = “前缀”
1 |
|
2.3 自动配置原理
2.3.1 引导加载自动配置类
- 在启动类MainApplication头部加上注解
@SpringBootApplication
1 |
|
@SpringBootConfiguration
- 最重要的就是
@Configuration
,表明启动类MainApplication就是一个配置类
- 最重要的就是
1 |
|
@ComponentScan
Configures component scanning directives for use with @Configuration classes. Provides support parallel with Spring XML’s context:component-scan element.
Either basePackageClasses or basePackages (or its alias value) may be specified to define specific packages to scan. If specific packages are not defined, scanning will occur from the package of the class that declares this annotation.
- 该注解相当于XML文件的
<context:component-scan>
配置 - 如果没有自定义扫描的包,默认扫描声明该注解的类所在包及其子包。所以启动类才应该与控制器包同级。
@EnableAutoConfiguration
- 开启自动配置
1 |
|
先看第一个注解:进入@AutoConfigurationPackage
1 |
|
Registers packages with AutoConfigurationPackages. When no base packages or base package classes are specified, the package of the annotated class is registered.
- 向AutoConfigurationPackages注册包
- 如果未指定基包或基包类,则会注册带注释类的包。
1 |
|
Class for storing auto-configuration packages for reference later (e.g. by JPA entity scanner).
- 用于存储自动配置包以供以后参考的类(例如,通过JPA实体扫描仪)
再看到AutoConfigurationPackages.Registrar.class
1 |
|
给 register
方法打断点,并启动程序。
计算 new PackageImports(metadata).getPackageNames()
的值,(Alt + F8 Intellij IDEA)
- metedata元数据,introspectedClass是启动类。因为该注解是加在启动类上的。
- 然后获得启动类所在的根目录报名,最后
toArray(new String[0])
,封装成一个数组注册。
然后是第二个注解:@Import(AutoConfigurationImportSelector.class)
进入 AutoConfigurationImportSelector
,重写了如下方法
1 |
|
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
给容器中批量导入一些组件。
1 |
|
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
获取所有需要导入到容器中的配置类。打断点观察:
1 |
|
通过
SpringFactoriesLoader
工厂类来加载这些配置类。META-INF/spring.factories
这个目录下有相应的配置内容。
1 |
|
1 |
|
- 利用工厂加载 Map<String, List
> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件 - 默认扫描我们当前系统里面所有
META-INF/spring.factories
位置的文件 - spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
2.3.2 按需开启自动配置项
虽然默认加载了很多自动配置类,但是这些自动配置类都会加上一些条件的注解。@ConditionalOnClass
等 来限定它们的开启。
2.3.3 修改默认配置
SpringBoot 先加载所有的自动配置类
xxxxxAutoConfiguration
每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
生效的配置类就会给容器中装配很多组件
只要容器中有这些组件,相当于这些功能就有了
定制化配置
- 用户直接自己@Bean替换底层的组件
- 用户去看这个组件是获取的配置文件什么值就去修改。
2.3.4 实践
引入场景依赖
查看自动配置了哪些(选做)
- 自己分析,引入场景对应的自动配置一般都生效了
- 配置文件中debug=true开启自动配置报告。Negative(不生效)\Positive(生效)
是否需要修改
- 参照文档修改配置项
- 自定义加入或者替换组件
- @Bean、@Component。。。
- 自定义器 XXXXXCustomizer;
2.4 Web开发
2.4.1 SpringMVC自动配置概览
在官网上有 SpringBOOT 整合 SpringMVC 相关的介绍。
Spring Boot provides auto-configuration for Spring MVC that works well with most applications.(大多场景我们都无需自定义配置)
The auto-configuration adds the following features on top of Spring’s defaults:
Inclusion of
ContentNegotiatingViewResolver
andBeanNameViewResolver
beans.
- 内容协商视图解析器和BeanName视图解析器
Support for serving static resources, including support for WebJars (covered later in this document)).
- 静态资源(包括webjars)
Automatic registration of
Converter
,GenericConverter
, andFormatter
beans.
- 自动注册
Converter,GenericConverter,Formatter
Support for
HttpMessageConverters
(covered later in this document).
- 支持
HttpMessageConverters
(后来我们配合内容协商理解原理)Automatic registration of
MessageCodesResolver
(covered later in this document).
- 自动注册
MessageCodesResolver
(国际化用)Static
index.html
support.
- 静态index.html 页支持
Custom
Favicon
support (covered later in this document).
- 自定义
Favicon
Automatic use of a
ConfigurableWebBindingInitializer
bean (covered later in this document).
- 自动使用
ConfigurableWebBindingInitializer
,(DataBinder负责将请求数据绑定到JavaBean上)
If you want to keep those Spring Boot MVC customizations and make more MVC customizations (interceptors, formatters, view controllers, and other features), you can add your own
@Configuration
class of typeWebMvcConfigurer
but without@EnableWebMvc
.不用
@EnableWebMvc
注解。使用@Configuration
+WebMvcConfigurer
自定义规则
- @EnableWebMvc注解原理
1 |
|
@Import({DelegatingWebMvcConfiguration.class})
,所以在@EnableWebMvc配置后,会自动加载DelegatingWebMvcConfiguration.class
。而在public class WebMvcAutoConfiguration
里面
1 |
|
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
这里表示如果WebMvcConfigurationSupport
注入时,则WebMvcAutoConfiguration
不会被开启。
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
注入DelegatingWebMvcConfiguration
同时也会注入父类WebMvcConfigurationSupport
,所以最终的结论是:
- 注入
@EnableWebMvc
会让WebMVC自定义配置失效
If you want to provide custom instances of
RequestMappingHandlerMapping
,RequestMappingHandlerAdapter
, orExceptionHandlerExceptionResolver
, and still keep the Spring Boot MVC customizations, you can declare a bean of typeWebMvcRegistrations
and use it to provide custom instances of those components.声明
WebMvcRegistrations
改变默认底层组件,并且仍然保留Spring Boot MVC自定义设置。
If you want to take complete control of Spring MVC, you can add your own
@Configuration
annotated with@EnableWebMvc
, or alternatively add your own@Configuration
-annotatedDelegatingWebMvcConfiguration
as described in the Javadoc of@EnableWebMvc
.使用
@EnableWebMvc + @Configuration + DelegatingWebMvcConfiguration 全面接管SpringMVC
2.4.2 功能分析
2.4.2.1 静态资源访问
By default, Spring Boot serves static content from a directory called
/static
(or/public
or/resources
or/META-INF/resources
) in the classpath or from the root of theServletContext
. It uses theResourceHttpRequestHandler
from Spring MVC so that you can modify that behavior by adding your ownWebMvcConfigurer
and overriding theaddResourceHandlers
method.
- 静态资源默认访问路径
/META-INF/resources/
/resources/
/static/
/public/
- 优先级顺序为:META-INF/resources > resources > static > public, 一般来说
public
下放一些公共的资源比如 用户都会访问的 js 文件,static
放一些静态资源,如图片。resources
放一些上传upload文件。
- 它使用Spring MVC中的
ResourceHttpRequestHandler
,这样您就可以通过添加自己的WebMvcConfigurer
并重写addResourceHandlers
方法来修改该行为。
By default, resources are mapped on
/**
, but you can tune that with thespring.mvc.static-path-pattern
property. For instance, relocating all resources to/resources/**
can be achieved as follows:
- 可以修改资源访问的路径(项目resources下面的文件)
You can also customize the static resource locations by using the
spring.web.resources.static-locations
property (replacing the default values with a list of directory locations). The root Servlet context path,"/"
, is automatically added as a location as well.
- 用了
spring.web.resources.static-locations
修改资源文件访问路径,则上面的四个默认的路径就会失效。
- 默认情况下,资源映射到/** ,但可以使用
spring.mvc.static-path-pattern
来重新定位到 /resources/**。就是访问资源路径前面加一个前缀。(url)
1 |
|
1 |
|
请求进来,先去找Controller看能不能处理。不能处理的所有请求又都交给静态资源处理器。静态资源也找不到则响应404页面。
- 静态资源如果是在WebJars这个网站导入的,则下载的目录文件都有同一的路径格式,则从jar文件提供路径为
/webjars/**
的任何资源。
In addition to the “standard” static resource locations mentioned earlier, a special case is made for Webjars content. Any resources with a path in /webjars/**
are served from jar files if they are packaged in the Webjars format.
如导入jquery
1 |
|
访问地址:http://localhost:8080/webjars/jquery/3.5.1/jquery.js 后面地址要按照依赖里面的包路径
2.4.2.2 欢迎页
如下两种情况都会当作静态页处理。1 访问静态页文件 2 Controller进行资源跳转。
- 静态资源路径下 index.html
可以配置静态资源路径
但是不可以配置静态资源的访问前缀。否则导致 index.html 不能被默认访问
spring.mvc.static-path-pattern
❌❌❌
1 |
|
- controller能处理/index
2.4.2.3 自定义 Favicon
favicon.ico 放在静态资源目录下即可。
1 |
|
2.4.2.4 静态资源配置原理
1 |
|
- ✔ 是一个SERVLET应用
- ✔ 在WebMVC自动配置类导入之前已经导入
Servlet
DispatcherServlet
WebMvcConfigurer
- ❌没导入
WebMvcConfigurationSupport
- ✔ WebMvcAutoConfiguration 执行
- 然后看到静态内部类
WebMvcAutoConfigurationAdapter
1 |
|
WebMvcProperties.class
和 ResourceProperties.class
分别绑定前缀属性:spring.mvc, spring.resources
1 |
|
- 只有一个有参构造器
1 |
|
- 所有参数的值都会从容器中确定
- ResourceProperties resourceProperties;获取和spring.resources绑定的所有的值的对象
- WebMvcProperties mvcProperties 获取和spring.mvc绑定的所有的值的对象
- ListableBeanFactory beanFactory Spring的 beanFactory
- HttpMessageConverters 找到所有的HttpMessageConverters
- ResourceHandlerRegistrationCustomizer 找到 资源处理器的自定义器。
- DispatcherServletPath
- ServletRegistrationBean 给应用注册Servlet、Filter….
内部成员方法
addResourceHandlers
—-> 资源处理默认规则1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
.addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}先在
if (!this.resourceProperties.isAddMappings())
打断点
进入isAddMappings
方法
1 |
|
所以配置上:
1 |
|
所以可以用这种方式禁用静态资源的访问
- 中间获取了静态资源的缓存规则,包括缓存时间等
1 |
|
1 |
|
根据注释上的提示,可以,period单位是秒,在配置文件中可以自定义缓存时间
1 |
|
- 第一个if,如果存在
/webjars/**
路径,则去/META-INF/resources/webjars/
下找资源,并配置好设置的缓存规则。这种方式就是在WebJars方式导入静态资源。
1 |
|
- 如果不是webjars方式导入,则从resources目录下找资源
先获取资源路径,默认路径就是 /**
1 |
|
接下来的代码与上面逻辑相同。
1 |
|
进入this.resourceProperties.getStaticLocations()
1 |
|
就是默认的四个静态资源访问路径。
- 进入静态内部类
EnableWebMvcConfiguration
1 |
|
1 |
|
welcomePageHandlerMapping
这个方法就是控制欢迎页。
进入WelcomePageHandlerMapping
有参构造方法
1 |
|
要用欢迎页功能,路径必须是/**,欢迎页存在,走if
不能存在,走else if:调用Controller /index
- Favicon
浏览器会自动发送 /favicon.ico 请求获取图标,整个session期间不再获取
2.4.3 请求参数处理
2.4.3.1 请求映射
@xxxMapping;
Rest风格支持(使用HTTP请求方式动词来表示对资源的操作)
- 以前:**/getUser 获取用户 /deleteUser 删除用户 /editUser 修改用户 /saveUser 保存用户
- 现在: /user GET-获取用户 DELETE-删除用户 PUT-修改用户 POST-保存用户
- 核心Filter:
HiddenHttpMethodFilter
- 用法: 表单method=post,隐藏域 _method=put
- SpringBoot中手动开启
因为
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!