# 概述
SpringBoot 是个好东西,简化了很多,尤其是配置,很少的配置就能使得项目运行。
Spring Boot 基于 Spring 开发,Spirng Boot 本身并不提供 Spring 框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于 Spring 框架的应用程序。Spring Boot 以约定大于配置的核心思想,默认帮我们进行了很多设置,多数 Spring Boot 应用只需要很少的 Spring 配置。同时它集成了大量常用的第三方库配置(例如 Redis、MongoDB、Jpa、RabbitMQ、Quartz 等等),Spring Boot 应用中这些第三方库几乎可以零配置的开箱即用。
# 创建
使用官方的 Spring Initializr 生成 SpringBoot 项目:https://start.spring.io/
当然 IDEA 也带有 SpringBoot 新建功能,只需要选好配置和依赖就行。
# 版本
SpringBoot 支持
目前(2023.03)Springboot 已经发布了 3.1.x 版本,但是 3 版本最低要求 JDK17。而 JDK8 可以使用 2.7.x 版本。
# 项目类型
首先对于项目的创建可以选择基于 Mevan 或是 Gradle,这里要提一下 Gradle:
Gradle 是一个基于 Apache Ant 和 Apache Mevan 概念的项目自动化建构工具。
构建脚本使用 Groovy 和 Kotlin 的特定领域语言来编写的,不是传统的 XML
groupid 和 artifactId 被统称为 “坐标” 是为了保证项目唯一性而提出的,如果你要把你项目弄到 maven 本地仓库去,你想要找到你的项目就必须根据这两个 id 去查找。
# 打包方式
jar 与 war 区别:
jar 是类的归档文件(JAVA Archive)是与平台无关的文件格式,它允许将多个组合成一个压缩文件,jar 文件格式以 zip 文件格式为基础。同时,jar 文件不仅用于压缩和发布,还用于部署和封装库、组件和插件程序,并可被编译器和 JVM 这样的工具直接使用。
war 包是一个 Web 应用程序,里面包含我们 web 程序需要的一些东西,其中包括 web.xml 的配置文件,前端的页面文件,以及依赖的 jar。便于我们部署工程,直接放到 tomcat 的 webapps 目录下,直接启动 tomcat 即可。同时,可以使用 WinRAR 查看 war 包,直接将后缀.war 改成.rar。
Web 存档 (war) 文件包含 Web 应用程序的所有内容。它减少了传输文件所需要的时间。
区别:
SpringBoot 项目既可以打成 war 包发布,也可以找成 jar 包发布。
jar 包:直接通过内置 Tomcat 运行,不需要额外安装 Tomcat。如需修改内置 Tomcat 的配置,只需要在 SpringBoot 的配置文件中配置。内置 Tomcat 没有自己的日志输出,全靠 jar 包应用输出日志。但是比较方便,快速,比较简单。
war 包:传统的应用交付方式,需要安装 Tomcat,然后放到 wabapps 目录下运行 war 包,可以灵活选择 Tomcat 版本,可以直接修改 Tomcat 的配置,有自己的 Tomcat 日志输出,可以灵活配置安全策略,相对打成 jar 包来说没那么快速方便。
# 依赖
在创建 springboot 项目时可以添加自己需要的依赖,只需要点击 ADD DEPENDENCIES 或者 ctrl + B
查找依赖进行添加
# 项目目录
项目下载解压后目录:
├─.idea | |
├─.mvn | |
│ └─wrapper | |
├─src | |
│ ├─main | |
│ │ ├─java | |
│ │ └─resources | |
│ └─test | |
│ └─java | |
└─target |
# git 和 maven 相关文件
# .gitignore
分布式版本控制系统 git 的配置文件,忽略提交
在.gitignore 文件中,遵循相应的语法,在每一行指定一个忽略规则如:
.log
.temp
/vendor
# mvnw
maven wrapper 缩写
在 maven-wrapper.properties 文件中记录你要使用的 maven 版本,当用户执行 mvnw clean
命令,发现当前用户的 mevan 版本和期望的版本不一致,那么就下载期望的版本,然后用期望的版本来执行 mvn 命令
# .mvn 文件夹
存放 maven-wrapper.properties 和相关 jar 包
# mvn.cmd
执行 mvnw 命令的 cmd 入口
# resouces 目录
# static
存放静态资源
# templates
存放模板资源
freemaker 相关
# 配置文件
springboot 默认读取全局配置文件:
application.yam 或 application.properties 文件
yml 文件格式:yaml(Ain't a Markup Language)
一种直观的能够被电脑识别的数据序列化格式,并且容易被人类阅读
文件默认在 resources 目录下读取,使用配置文件修改默认配置
prooperties 文件格式:
server.port=8080 |
yml 文件格式:
server: | |
port:8080 |
# profile
Profile 是 Spring 用来针对不同环境对不同配置提供全局的 Profile 配置,使用 application-{Profile}.yml
主配置文件 application.yml
## 环境选择配置 | |
spring: | |
profiles: | |
active:"{profile}" |
工程当中我们会使用三种配置文件对应不同的环境:
- dev 开发环境
- test 测试环境
- pro 正式环境
也可以使用 application-dev.xml
,然后在项目启动时加上 -Dspring.profiles.active=dev
来使用开发配置启动项目,在本地 idea 开发时可以在启动配置中加入这个参数:
启动时会打印相关信息:
2023-03-06 16:04:46.031 INFO 38292 --- [main] n.b.s.SecurityDepartmentApplication : The following 1 profile is active: "dev" |
# 日志
使用 web 自动引入依赖
application.yml:
logging: | |
pattern: | |
level: DEBUG | |
file: | |
name: "springboot.log" | |
path: "./" |
# Start 坐标
SpringBoot 引入全新坐标体系,简化 pom.xml
使用 Spring MVC 来构建 RESTful Web 应用,并使用 Tomcat 作为默认容器
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-web</artifactId> | |
</dependency> |
集成视图技术
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-freemarker</artifactId> | |
</dependency> |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-thymeleaf</artifactId> | |
</dependency> |
Spring-boot 项目引入 starter 系列坐标,对应的版本库统一由父工程坐标统一控制,即:
<parent> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-parent</artifactId> | |
<version>2.7.4</version> | |
<relativePath/> | |
</parent> |
<relativePath/> 设定一个空值将始终从仓库中获取,不从本地路径获取
# 自动化配置
SpringBoot 的项目一般都会有 * Application 的入口类,入口类中提供 main 方法,这是一个标准的 Java 应用程序的入口方法。 @SpringBootApplication
注解是 SpringBoot 的核心注解,它其实是一个组合注解。
# 元注解概述
JDK1.5 开始,Java 增加了对元数据的支持,也就是 Annotation
注解就是就是代码中的特殊标记,用于替代配置文件
# meta-annotation
除了 JDK 定义好的注解,我们还可以自定义注解,JDK1.5 提供了四个标准用来对注解类型进行注解的注解类
@Target
@Retention
@Document
Inherited
# @Target 注解
描述注解的使用范围
Target 注解用来说明被注解的注解类可修饰的对象的范围:
注解可以修饰 packages types(类、接口、枚举、注解类)、类成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量
取值范围在 ElementType 枚举中:
public enum ElementType { | |
TYPE, // 类、接口、枚举类 | |
FIELD, // 成员变量(包括:枚举常量) | |
METHOD, // 成员方法 | |
PARAMETER, // 方法参数 | |
CONSTRUCTOR, // 构造方法 | |
LOCAL_VARIABLE, // 局部变量 | |
ANNOTATION_TYPE, // 注解类 | |
PACKAGE, // 可用于修饰:包 | |
TYPE_PARAMETER, // 类型参数,JDK 1.8 新增 | |
TYPE_USE // 使用类型的任何地方,JDK 1.8 新增 | |
} |
# @Retention 注解
描述注解保留的时间范围
限定所注解的注解类注解到其他类上后,可以被保留到何时,一共三个策略,定义在 RetentionPolicy 枚举中:
public enum RetentionPolicy { | |
SOURCE, // 源文件保留 | |
CLASS, // 编译期保留,默认值 | |
RUNTIME // 运行期保留,可通过反射去获取注解信息 | |
} |
# @Documented 注解
描述在使用 javadoc 工具为类生成帮助文档时是否需要保留注解信息
# @Inherited 注解
使被修饰的注解具有继承性
# 总结
SpringBoot 通过 maven 中的 starter 导入了所需场景下的 jar 包,并通过主启动类 @SpringBootApplication 中的 @EnableAutoConfiguration 读取该 jar 路径下的 META—INF/spring.factories 下 EnableAutoFiguration 的配置类,这些配置类使用 @ConditionOnClass 来标注,根据 @ConditionOnClass 约束条件引入自动化环境的配置。
# 项目使用
# 开启
使用 war 包就打包为 war 包放到 tomcat 容器下
jar 包使用 java -jar 包名
运行
# 关闭
springboot 关闭貌似比较麻烦
# 使用 Actuator
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
SpringBoot 内置监控功能 Actuator,添加依赖后正常启动项目,Actuator 会把收集的所有信息暴露给 JMX(Java Management Extensions)
Spring Boot Actuator 端点通过 JMX 和 HTTP 公开暴露给外界访问,大多数时候我们使用基于 HTTP 的 Actuator 端点,因为它们很容易通过浏览器、CURL 命令、shell 脚本等方式访问。
常用端点:
- /beans:此端点返回应用程序中配置的所有 bean 的列表。
- /env:提供有关 Spring Environment 属性的信息。
- /health:显示应用程序运行状况
- /info:显示应用程序信息,我们可以在 Spring 环境属性中配置它。
- /mappings:显示所有 @RequestMapping 路径 的列表 。
- /shutdown:允许我们正常关闭应用程序。
- /threaddump:提供应用程序的线程转储。
# 全局异常处理
# @ControllerAdivice
组合注解,组合了 @Componet 注解,常用全局异常处理切面类,同时该注解可以指定扫描包范围
# @ExceptionHandler
spring3.x 引入,处理异常时标注到方法,代表当前方法处理异常有哪些
# 数据校验
# validation
日常项目开发中,对于前端提交的表单,后台接口接收到表单数据后,为了程序的严谨性,通常后端会加入业务参数的合法校验操作来避免程序的非技术性 bug, 这里对于客户端提交的数据校验,SpringBoot 通过 spring-boot-starter-validation 模块包含了数据校验的工作。
相关概念:
- JSR303:是一项标准,只提供规范不提供实现,规定一些校验规范即校验注解,如 @Null、@NouNull、@Pattern、位于 javax.validation.constrains 包下。JSR-349 是升级版本
- Hibernate Validation:对以上规范的实现,并增加了一些其他校验,如 @Email、@Length、@Range 等等
- Spring Validation :对 Hibernate Validation 的二次封装,在 SpringMVC 模块添加了自动校验,并将校验信息封装进了特定的类中
约束性注解:
注解 | 说明 |
---|---|
@AssertFalse | 可以为 null,如果不为 null 的话必须为 false |
@AssertTrue | 可以为 null,如果不为 null 的话必须为 true |
@DecimalMax | 设置不能超过最大值 |
@decimalMin | 设置不能超过最小值 |
@Digits | 设置必须是数字且数字整数的位数和小数的位数必须在指定范围内 |
@Future | 日期必须先在当前日期未来 |
@Past | 日期必须在当前日期过去 |
@Max | 最大不得超过此最大值 |
@Min | 最小不得小于最小值 |
@NotNull | 不能为 null 可以是空 |
@Null | 必须 null |
@Pattern | 必须满足指定的正则表达式 |
@Size | 集合、数组、map 等的 size () 不能为 0;字符串 trim () 后可以等于 “” |
必须是 email 格式 | |
@Length | 长度必须在指定范围内 |
@NotBlank | 字符串不能为 null,字符串 trim () 后不能为 “” |
@NotEmpty | 不能为 null,集合、数组、map 等 size () 不能为 0;字符串 trim () 后可以等于 “” |
@Range | 值必须在指定范围内 |
@URL | 必须是一个 URL |
配合全局异常捕捉
@ExceptionHandler(Exception.class) | |
public Map<String, Object> exceptionMessageReturn(BindException b){ | |
Map<String, Object> map = new HashMap<>(); | |
map.put("msg",b.getBindinResult(),getFieldError().getDefaultMessage()); | |
return map; | |
} |
# 分布式缓存 Ehcache 整合
Ehcache 是一个成熟的 java 缓存框架,最早从 hibernate 发展而来,是进程中的缓存系统,它提供了用内存,磁盘文件存储,以及分布式存储的方式等多种灵活的 cache 管理方案,快速简单
springboot 对 Ehcache 的使用提供支持,所以在 springboot 中只需要简单配置即可使用 Ehcache 实现数据缓存处理。
依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
# 缓存配置文件
encache-config.xml
<?xml version="1.0" encoding="UTF-8"?> | |
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:NamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"> | |
<!-- 默认缓存 --> | |
<defaultCache | |
maxEntriesLocalHeap="10000" | |
eternal="false" | |
timeToIdleSeconds="120" | |
timeToLiveSeconds="120" | |
maxEntriesLocalDisk="10000000" | |
diskExpiryThreadIntervalSeconds="120" | |
memoryStoreEvictionPolicy="LRU"> | |
<persistence strategy="localTempSwap"/> | |
</defaultCache> | |
<!-- helloworld 缓存 --> | |
<cache name="HelloWorldCache" | |
maxElementsInMemory="1000" | |
eternal="false" | |
timeToIdleSeconds="5" | |
timeToLiveSeconds="5" | |
overflowToDisk="false" | |
memoryStoreEvictionPolicy="LRU"/> | |
</ehcache> |
也可以:
Cache cache = manager.getCache("mycache"); | |
CacheConfiguration config = cache.getCacheConfiguration(); | |
config.setTimeToIdleSeconds(60); | |
config.setTimeToLiveSeconds(120); | |
config.setmaxEntriesLocalHeap(10000); | |
config.setmaxEntriesLocalDisk(1000000); |
# SpringCache 相关注解说明
springBoot 缓存实现内部使用 springcache 实现缓存机制,这里集成 Ehcache 实际上是对 springCache 的抽象的一种实现。
# @CacheConfig
用于标注类上,可以存放该类中所有缓存的公有属性,比如缓存名
@CacheConfig(cacheName = "users") | |
pulic interface UserService{ | |
} |
配置了该数据访问对象中返回的内容将存储于名为 users 的缓存对象中,我们也可以不使用该注解,直接通过 @Cacheable 自己配置缓存集的名字来定义。
# @Cacheable
应用到读取数据的方法上,即可缓存的方法,如查找方法,先从缓存中读取,如果没有就调用相应方法获取数据,然后把数据添加到缓存中。
该注解有以下参数:
- value、cacheNames : 两个等同的参数 (cacheNames 为 Spring4 新增,作为 value 的别名),用于指定缓存存储的集合名。由于 Spring4 中新增了 @CacheConfig, 因此在 Spring 了中原本必须有的 value 属性,也成为非必需项了
- key: 缓存对象存储在 Map 集合中的 key 值,非必需,缺省按照函数的所有参数组合作为 key 值,若自己配置需使用 SqL 表达式,比如: @Cacheable (key = "#p0") : 使用函数第一个 参数作为缓存的 key 值,更多关于 SpEL 表达式的详细内容可参
考官方文档。 - condition : 缓存对象的条件,非必需,也需使用 SpEL 表达式,只有满足表达式条件的内容才会被缓存,比如:
@Cacheable (key = "#p0", condition = "#p0.length ()< 3"),表示只有当第一个 参数的长度小于 3 的时候才会被缓存。 - unless : 另外一个缓存条件参数,非必需,需使用 SpEL 表达式。它不同于 condition 参数的地方在于它的判断时机,该条件是在函数被调用之后才做判断的,所以它可以通过对 result 进行判断。
- keyGenerator : 用于指定 key 生成器,非必需。若需要指定一个自定义的 key 生成器,我们需要去实现
org.springframework.cache.interceptor.KeyGenerator 接口,并使用该参数来指定。需要注意的是:该参数与 key 是互斥
的。 - cacheManager : 用于指定使用哪个缓存管理器,非必需。只有当有多个时才需要使用
- cacheResolver : 用于指定使用那个缓存解析器,非必需。需通过 org.springframework.cache.interceptor.CacheResolver
接口来实现自己的缓存解析器,并用该参数指定。
# 缓存过期策略
EhCache 提供了三种淘汰算法:
- FIFO:First In First Out,先进先出。判断被存储的时间,离目前最远的数据优先被淘汰。
- LRU:Least Recently Used,最近最少使用。判断最近被使用的时间,目前最远的数据优先被淘汰。
- LFU:Least Frequently Used,最不经常使用。在一段时间内,数据被使用次数最少的,优先被淘汰。
Ehcache 采用的是懒淘汰机制,每次往缓存放入数据时,都会存一个时间,在读取时要和设置的时间做 TTL 比较来判断是否过期。
# 单元测试
控制层单元测试
@SpringBootTest | |
@AutoConfigureMockMvc | |
public class TestController { | |
private MockMvc mockMvc; | |
@Test | |
public void test() throws Exception { | |
// 构建请求 | |
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("") | |
.contentType("text/html") | |
.accept(MediaType.APPLICATION_JSON); | |
ResultActions perform = mockMvc.perform(builder); | |
perform.andExpect(MockMvcResultMatchers.status().isOk()); | |
MvcResult result = perform.andReturn(); | |
MockHttpServletResponse response = result.getResponse(); | |
System.out.println(response.getContentAsString()); | |
} | |
} |
# 热部署
热部署,就是再应用正在运行的时候升级软件(增加业务 / 修改 bug),而不需要重启应用。
项目开发过程中,常常会修改页面数据或数据结构,为了显示改动效果,往往需要重新启动应用,查看变动效果,其实就是重新编译生成了 class 文件,这个文件里记录了与代码对应的各种信息,然后 class 文件将被虚拟机 ClassLoader 加载。
而热部署正是利用了这个特点,它监听到如果有 Class 文件改动了。就会创建一个新的 ClassLoader 进行加载改文件,经过一系列的过程,最终将结果呈现在我们眼前,SpringBoot 通过配置 DevTools 工具来达到热部署效果。
在原理上是使用了两个 ClassLoader,一个 ClassLoader 加载哪些不会改变的类,另一个 ClassLoader 加载会改变的类,称为 resrart ClassLoader,这样在有代码更改的时候,原来的 restart ClassLoader 被丢弃,重新创建一个 restart ClassLoader,由于需要加载的类相比较少,所以实现了较快的重启时间,。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<!--当前项目被继承后不向下传递-->
<optional>true</optional>
</dependency>
devtools 可以实现页面热部署(即页面修改后会立即生效,这个可以直接再 application.yml 文件中配置 spring.thymeleaf.cache=true 实现),实现类文件热部署(类文件修改后不会立即生效),实现对属性文件的热部署。即 devtools 会监听 classpath 下的文件变动,并且会立即重启应用(发生在保存实际),注意,以为其采用虚拟机机制,该项目重启是很快的。配置了后在修改 java 文件后也就支持了热启动,不过这种方式属于项目重启(速度比较快的项目重启),会清空 session 中的值,也就是如果有用户登录的话,项目重启后需要重新登录。
默认情况下,/META-INF/maven,/META-INF/resources,/resources , /static/templates, /public 这些文件修改不会使应用重启,但会重新加载(devtools 内嵌了一个 LiveReload server,当资源发生改变时,浏览器刷新
配置文件:
spring: | |
devtools: | |
restart: | |
enabled: true | |
additional-paths: src/main/java/ | |
# 解决项目自动重新编译后报 404 问题 | |
poll-interval: 3000 | |
quiet-period: 1000 |
配置 spring.devtools.restart.enabled=true 后 restart 类加载器还会初始化,但不会监视文件更新
修改 java 类后,idea 默认是不自动编译的,而 spring-boot-devtools 又是监测 classpath 下的文件发生变化才重新启动应用,所以需要设置 idea 重新编译
之后启动应用 ctrl+F9 重新启动即热部署成功
# API 文档构建 - swagger2
由于 SpringBoot 能够快速开发、便捷部署等特性,通常再使用 SpringBoot 构建 RESTful 风格接口应用时考虑到多终端的原因,这些终端会共用很多底层逻辑,因此我们会抽象出这样一层来同时服务于多个移动端或者 Web 前端。对于不同的终端公用一套接口 API 时,对于联调测试的时候就知道后端提供的接口 Api 列表文档,对于服务端开发人员来说就需要编写接口文档,描述接口调用地址、参数结果等,这里借助第三方构建工具 Swagger2 来实现 API 文档生成功能。
依赖添加:
<dependency> | |
<groupId>io.springfox</groupId> | |
<artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> | |
</dependency> | |
<dependency> | |
<groupId>io.springfox</groupId> | |
<artifactId>springfox-swagger-ui</artifactId> | |
<version>2.9.2</version> | |
</dependency> |
常用注解:
# @Api
用在请求的类上,说明该类作用
@Api(tags="App用户注册Controller") |
# @ApiOperation
@ApiOperation: 用在请求方法上,说明方法作用
value = 说明方法作用
notes = 方法的备用说明
@ApiOperation(value="用户注册",notes="手机号、密码都是必填项,年龄是选填项,但必须数字") |
# @ApiImplicitParams
@ApiImplicitParams用在方法上,包含一组参数说明 | |
@ApiImplicitParam用在ApiImplicitParams注解中,指定一个请求参数的配置信息 | |
name:参数名 | |
value:参数的汉字说明、解释 | |
required:参数是否必须传 | |
paramType:参数放在哪个地方 | |
· header --> 请求参数的获取: @RequestHeader | |
· query --> 请求参数的获取: @RequestParam | |
· path(用于REST接口) --> 请求参数的获取:@PathVariable | |
· body(不常用) | |
form(不常用) | |
dataType: 参数类型,默认String, 其他值dataType="Integer" | |
dafaultValue: 参数默认值 |
@ApiImplicitParams({ | |
@ApiImplicitParam(name="mobile", value="手机号",required=true,paramType="form"), | |
@ApiImplicitParam(name="password", value="密码",required=true,paramType="form"), | |
}) |
# @ApiResponses
@ApiResponse:用于请求的方法上,表示一组响应 | |
@ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息 | |
code:数字 400 | |
message:信息 | |
response:抛出异常的类 |
# @ApiModel
用于响应类上,表示一个返回响应数据的信息(一般在 post 创建的时候,使用 @RequestBody 这样的场景,请求参数无法使用 @ApiImplicitParam 注解进行描述的时候)
@ApiModelProperty:用在属性上,描述响应类的属性
# Quartz 定时任务
在日常项目运行中,我们总会有需求在某一时间段周期性执行某个动作。比如每天再某个时间段导出报表,或者每隔多久统计一次现在在线的用户量等。
在 SpringBoot 中有 Java 自带的 Java.util.Timer 类,也有强大的调度器 Quartz,还有 SpringBoot 自带的 Scheduled 来实现。Scheduled 在 Spring3.X 引入,默认 SpringBoot 自带该功能,使用起来也很简单,在启动类级别添加 @EnableScheduling 注解即可引入定时任务环境。但遗憾的是 Scheduled 默认不支持分布式环境,这里主要讲解 Quartz 时钟调度框架与 SpringBoot 集成。
依赖:
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-quartz</artifactId> | |
</dependency> |