一、什么是Spring Boot
Spring Boot
是目前流行的微服务框架 倡导约定优先于配置
其目的是 用来简化新 Spring 应用的初始化搭建以及开发过程。 SpringBoot 提供了很多核心的功 能,比如自动化配置 starter(启动器) 简化 Maven配置、内嵌 Servlet 容器、应用监控等功能, 让我们可以快速构建企业级应用程序。
- 特性:
- 创建独立的Spring 应用程序
- 嵌入式 Tomcat、 Jetty、 Undertow容器(jar)
- 提供的 starters 简化构建配置(简化依赖管理和版本控制)
- 尽可能自动配置 spring应用和第三方库
- 提供生产指标,例如指标、健壮检查和外部化配置
- 没有代码生成,无需XML配置
SpringBoot 同时提供开箱即用,约定优于配置的特性。
开箱即用
:SpringBoot应用无需从0开始,使用脚手架创建项目。基础配置已经完成。 集成大部分第三方库对象,无需配置就能使用。例如在SpringBoot项目中使用MyBatis。可以直接使用XXXMapper对象, 调用方法执行sql语句。
约定优于配置
:SpringBoot定义了常用类,包的位置和结构,默认的设置。代码不需要做调整,项目能够按照预期运行。比如启动类在根包的路径下,使用了@SpringBooApplication注解。创建了默认的测试类。controller,service,dao 应该放在根包的子包中。application为默认的配置文件。
SpringBoot3 最小 jdk17, 支持 17-22。
二、最新的SpringBoot3 新特性
2022 年 11月 24日。SpringBoot3 发布,里程碑的重大发布。这个版本应该是未来5年的使用主力。Spring官网支持SpringBoot3.0.X 版本到2025年。
- SpringBoot3 中的重大变化:
- JDK最小Java17,能够支持17-22.
- Spring Boot 3.0 已将所有底层依赖项从 JavaEE 迁移到了
JakartaEEAPI
。原来javax开头的包名,修改为jakarta
。 例如 jakarta.servlet.http.HttpServlet 原来 javax.servlet.http.HttpServlet - 支持 GraalVM 原生镜像。将Java应用编译为本机代码,提供显著的内存和启动性能改进
- 对第三方库,更新了版本支持
- 自动配置文件的修改
- 提供新的声明式Http服务,在接口方法上声明@HttpExchange获取http远程访问的能力。代替OpenFeign
- Spring HTTP 客户端提供基于 Micrometer 的可观察性. 跟踪服务,记录服务运行状态等
- AOT(预先编译) 支持AheadOfTime,指运行前编译
- Servlet6.0 规范
- 支持 Jackson 2.14
- Spring MVC :默认情况下使用的 PathPatternParser。删除过时的文件和 FreeMarker 、JSP 支持
伴随着SpringBoot3 的发布,还有 SpringFramework6.0的发布(2022-11-16),先于 Spring Boot 发布。
三、脚手架
脚手架
是一种用在建筑领域的辅助工具,是为了保证建筑施工过程顺利进行而搭设的工作平台。软件工程中的脚手架是用来快速搭建一个小的可用的应用程序的骨架,将开发过程中要用到的工具、环境都配置好,同时生成必要的模板代码。脚手架辅助创建程序的工具,SpringInitializr
是创建SpringBoot项目的脚手架。快速建立 SpringBoot项目的最好方式。他是一个web应用,能够在浏览器中使用。IDEA中继承了此工具,用来快速创建SpringBoot项目以及Spring Cloud 项目。
Spring Initializr
脚手架的 web 地址: https://start.spring.io/
阿里云脚手架
:https://start.aliyun.com/
四、使用脚手架创建项目
4.1 浏览器访问脚手架,创建项目
这里我们以Spring Initializr 脚手架为例。脚手架使用需要联网。
4.2 IDEA 中使用脚手架(推荐)
- 1、New Project
- 2、Spring Initializr
4.3 spring-boot-starter-parent
pom.xml
中的<parent>指定 spring-boot-starter-parent 作为坐标,表示继承 Spring Boot 提供的父项目。从spring-boot-starter-parent 继承以获得合理的默认值和完整的依赖树,以便快速建立一个SpringBoot项目。
父项目提供以下功能:
- JDK的基准版本,比如<java.version>17</java.version>
- 源码使用UTF-8 格式编码
- 公共依赖的版本
- 自动化的资源过滤:默认把src/main/resources目录下的文件进行资源打包
- maven的占位符为'@'
- 对多个Maven插件做了默认配置,如maven-compile-plugin,maven-jar-plugin
快速创建SpringBoot项目,同时能够使用父项目带来的便利性,可以采用如下两种方式:
- 在项目中,继承spring-boot-starter-parent
- pom.xml 不继承,单独加入spring-boot-dependencies 依赖
xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.3.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
五、配置文件基础
5.1 配置文件格式
- 配置文件有两种格式分别:
properies
和yaml(yml)
。properties是Java中的常用的一种配置文件格式,key=value
。key 是唯一的,文件扩展名为properties
。- yaml(YAML Ain't Markup Language)也看做是 yml,是一种做配置文件的数据格式,基本的语法
key:[空格]值
。yml文件文件扩展名是yaml或yml(常用)。
yml 格式特点:
- YAML基本语法规则:
- 大小写敏感
- 使用缩进表示层级关系
- 缩进只可以使用空格,不允许使用Tab键
- 缩进的空格数目不重要,相同层级的元素左侧对齐即可
#
字符表示注释,只支持单行注释。#放在注释行的第一个字符
YAML缩进必须使用空格
,而且区分大小写,建议编写YAML文件只用小写和空格。
- YAML支持三种数据结构:
- 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
- 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
- 标量(scalars):单个的、不可再分的值,例如数字、字符串、true|false等
需要掌握数据结构完整内容,可从https://yaml.org/type/index.html 获取详细介绍。
5.2 application 文件
Spring Boot 同时支持properties 和 yml 格式的配置文件。 配置文件名称默认是application。我们可以使用
application.properties
,application.yml
。读取配置文件的key值,注入到Bean的属性可用@Value
,@Value一次注入一个key的值。将多个key值绑定到Bean的多个属性要用到@ConfigurationProperties
注解。在代码中访问属性除了注解,Spring提供了外部化配置的抽象对象
Environment
。Environment 包含了几乎所有外部配置文件,环境变量,命令行参数等的所有key和value。需要使用Environment的注入此对象,调用它的getProperty(String key)
方法即可。
- 注意:
- Spring Boot 建议使用一种格式的配置文件,如果properties和yml都存在。properties文件优先。推荐使用yml文件。
- application 配置文件的名称和位置都可以修改。约定名称为application,位置为resources目录。
5.3 application.properties
需求:在application.properties 提供应用程序的 name,owner, port 基本信息,程序读取这些数据,显示给用户。
-
step1:在 application.properties 自定义配置项目
propertiesapp.name=Lession01 app.age=25 app.port=8001
-
step2: 创建 SomeService 类读取 app.name, app.owner,app.port 配置 key。
注解@Value读取单个值,语法${key:默认值}
java@Service public class DemoService { //spring提供默认的类型转换 @Value("${app.name}") private String userName; @Value("${app.age}") private Integer age; @Value("${app.port:8080}") private Integer port; public void printValue() { StringJoiner stringJoiner = new StringJoiner(";"); String str = stringJoiner.add(userName).add(String.valueOf(age)).add(String.valueOf(port)).toString(); System.out.println("result = " + str); } }
-
step3:单元测试
java@SpringBootTest public class TestDemo { @Autowired private DemoService demoService; @Test void test01() { demoService.printValue(); } }
5.4 application.yml
需求:同上面一样的需求,配置为application.yml。首先修改application.properties 名称为其他的任意名称,比如1appliction.properties。在创建 application.yml 文件。
- step1:编写application.yml
- step2: 运行单元测试
5.5 Environment
Environment 是外部化的抽象,是多种数据来源的集合。从中可以读取application配置文件,环境变量,系统属性。使用方式在Bean中注入Environment。调用它的getProperty(key)方法。
-
step1:创建 ReadConfig 类,注入 Environment
java@Service public class ReadConfig { @Autowired private Environment environment; public void print() { String name = environment.getProperty("app.name"); //key是否存在 if (environment.containsProperty("app.age")) { System.out.println("有app.age配置项"); } //读取key转为需要的类型,提供默认值8000 Integer port = environment.getProperty("app.port", Integer.class, 8000); String result = String.format("读取的name:%s,端口port:%d", name, port); System.out.println("result=" + result); } }
-
step2:单元测试
java@SpringBootTest public class TestDemo { @Autowired private ReadConfig readConfig; @Test void test02() { readConfig.print(); } }
5.6 组织多文件
大型集成的第三方框架,中间件比较多。每个框架的配置细节相对复杂。如果都将配置集中到一个application文件,导致文件内容多,不易于阅读。我们将每个框架独立一个配置文件,最后将多个文件集中到application。我们使用导入文件的功能。
需求:项目集成redis,数据库mysql。将redis,数据库单独放到独立的配置文件。
-
step1:在 resources 创建自定义conf 目录,在conf中创建redis.yml, db.yml
-
step2: application.yml 导入多个配置
-
step3:创建类,读取两个文件的配置项
java@Service public class MultiConfigService { @Value("${spring.redis.host}") private String redisHost; @Value("${spring.datasource.druid.master.url}") private String dbUrl; public void printConfig() { System.out.println("redis 的 ip:" + redisHost + ",数据库 url;" + dbUrl); } }
5.7 多环境配置
Spring Boot 规定环境文件的名称 application-{profile}.properties(yml)。其中 profile 为自定义的环境名称,推荐使用dev表示开发 ,test表示测试。prod表示生产,feature表示特性。总是profile名称是自定义的。SpringBoot会加载application 以及 application-{profile}两类文件,不是只单独加载application-{profile}。
需求: 项目使用多环境配置,准备一个开发环境,一个测试环境
-
step1:在 resources 创建环境配置文件
-
step2: 激活环境
ymlspring: config: # 导入多个配置文件,","作为分隔符 import: conf/db.yml,conf/redis.yml #激活环境,与on-profile名称保持一致 profiles: active: dev
-
step3: 创建读取配置项的类
java@Service public class MulitEnvService { @Value("${myapp.memo}") private String memo; public void print() { System.out.println(memo); } }
-
step4: 单元测试
java@SpringBootTest public class TestDemo { @Autowired private MulitEnvService mulitEnvService; @Test void test04() { mulitEnvService.print(); } }
六、绑定Bean
- @Value 绑定单个属性,当属性较多时不方便,SpringBoot提供了另一种属性的方法。将多个配置项绑定到Bean 的属性,提供强类型的Bean。Bean能够访问到配置数据。
- 基本原则:标准的JavaBean有无参数构造方法,包含属性的访问器。配合
@ConfigurationProperties
注解一起使用。Bean的static 属性不支持。 - @ConfigurationProperties 能够配置多个简单类型属性,同时支持Map,List,数组类型。对属性还能验证基本格式。
6.1 简单的属性绑定
-
step1:查看application 配置。目前使用的是application.yml
-
step2: 创建 Bean,定义name,age, port 属性
java@Configuration(proxyBeanMethods = false) @ConfigurationProperties(prefix = "app") public class AppBean { private String name; private Integer age; private Integer port; // set | get方法 ,toString() }
@ConfigurationProperties 声明在类上,表示绑定属性到此类。prefix 表示前缀,是配置文件中多个key的公共前缀。这些key以"."作为分隔符。例如app.name,app:name等。 prefix="app", 将文件中app开始的key都找到,调用与key相同名称的
setXXX方法
。如果有给属性赋值成功。没有的忽略。 -
step3:单元测试
java@SpringBootTest public class TestDemo { @Autowired private AppBean appBean; @Test void test05() { System.out.println("appBean.toString()=" + appBean.toString()); } }
6.2 嵌套Bean
- 需求:Bean中包含其他Bean作为属性,将配置文件中的配置项绑定到Bean以及引用类型的成员。Bean的定义无特殊要求。在原来的app的配置中,增加security相关配置,包含username,password两个属性。
-
step1:定义两个Bean
java@Configuration(proxyBeanMethods = false) @ConfigurationProperties(prefix = "app") public class AppBean { private String name; private Integer age; private Integer port; private Security security; //set|get方法,toString() } public class Security { private String username; private String password; //set|get方法,toString() }
-
step2:定义application.yml
ymlapp: name: Lession01 age: 25 port: 8002 security: username: root password: 123456
-
step3:单元测试
java@SpringBootTest public class TestDemo { @Autowired private AppBean appBean; @Test void test06() { System.out.println("appBean.toString()=" + appBean.toString()); } }
6.3 扫描注解
@ConfigurationProperties
注解起作用,还需要@EnableConfigurationProperties
或@ConfigurationPropertiesScan
。这个注解是专门寻找@ConfigurationProperties注解的,将他的对象注入到Spring容器。在启动类上
使用扫描注解。
java
/**
*扫描@ConfigurationProperties所在的包名
*不扫描@Component
*/
@ConfigurationPropertiesScan({"com.liming.pk1"})
@SpringBootApplication
public class Lession01Application {
public static void main(String[] args) {
SpringApplication.run(Lession01Application.class, args);
}
}
6.4 处理第三方库对象
- 上面的例子都是在源代码中使用@ConfigurationProperties注解,如果某个类需要在配置文件中提供数据,但是没有源代码。此时@ConfigurationProperties结合@Bean一起在方法上面使用。
- 比如现在有一个Security类是第三方库中的类,现在要提供它的username,password属性值。
-
step1:application.yml添加新的配置
ymlsecurity: username: common password: abc123
-
step2:创建配置类
java@Configuration public class ApplicationConfig { @ConfigurationProperties(prefix = "security") @Bean public Security createSecurity() { return new Security(); } }
-
step3:单元测试
java@SpringBootTest public class TestDemo { @Autowired private Security security; @Test void test07() { System.out.println("security=" + security); } }
6.5 集合Map,List以及Array
-
step1:创建保存数据的Bean
javapublic class User { private String name; private String sex; private Integer age; //set|get,toString } class MyServer { private String title; private String ip; //set|get,toString } @ConfigurationProperties class CollectionConfig { private List<MyServer> servers; private Map<String, User> users; private String[] names; //set|get,toString }
-
step2:修改application.yml,配置数据
yml#集合以及数组 #List<String>names names: - lisi - zhangsan #List<MyServer>servers servers: - title: 华北服务器 ip: 202.168.32.6 - title: 西南服务器 ip: 109.78.23.113 - title: 华东服务器 ip: 165.21.34.179 #Map<String,User>users users: user1: name: 张三 sex: 男 age: 23 user2: name: 赵倩 sex: 女 age: 26
"-"表示集合一个成员,因为成员是对象,需要属性名称指定属性值。List与数组前面加入"-"表示一个成员。Map直接指定key和value,无需"-"。
-
step3:启动类,增加扫描包
java@ConfigurationPropertiesScan({"其他包","com.liming.pk1"})
-
step4:单元测试
java@SpringBootTest public class TestDemo { @Autowired private CollectionConfig collectionConfig; @Test void test08() { String str = collectionConfig.toString(); System.out.println("str=" + str); } }
6.6 指定数据源文件
application做配置是经常使用的,除以以外我们能够指定某个文件作为数据来源。
@PropertySource
是注解,用以加载指定的properties文件。@PropertySource与@Configuration一同使用,其他注解还有@Value,@ConfigurationProperties。
需求:一个组织信息,在单独的properties文件提供组织的名称,管理者和成员数量
-
step1:创建Group类,表示组织
java@Configuration @ConfigurationProperties(prefix = "group") @PropertySource(value = "classpath:/group-info.properties") public class Group { private String name; private String leader; private Integer members; //set|get,toString }
-
step2:在 resources 目录下的任意位置创建properties 文件,我们创建group-info.properties,放在 resources 根目录
-
step3: 单元测试
java@SpringBootTest public class TestDemo { @Autowired private Group group; @Test void test09() { System.out.println("group = " + group.toString()); } }
七、创建对象三种方式
将对象注入到Sprin容器,可以通过如下方式:
- 传统的XML配置文件(了解即可)
- JavaConfig技术,
@Configuration
与@Bean
- 创建对象的注解,
@Controller
,@Service
,@Repository
,@Component
SpringBoot不建议使用xml文件的方式,自动配置已经解决了大部分xml中的工作了。如果需要xml提供bean的声明,@ImportResource加载xml注册Bean。