SpringBoot3 基础教程之一快速入门

大纲

开发环境要求

环境 & 工具版本
SpringBoot3.0.5+
IDEA2021.2.1+
JDK17+
Maven3.5+
Tomcat10.0+
Servlet5.0+
GraalVM Community22.3+
Native Build Tools0.9.19+

提示

SpringBoot 3 依赖 JDK 17,采用全新的 Spring 6,Maven 的支持也提高到了 3.5,Gradle 提高到了 7.3,版本管理器默认也换成了 Gradle。值得一提的是,IDEA 2022.x 版本以上都可以支持 JDK 17。

SpringBoot 介绍

SpringBoot 可以简单、快速地创建一个独立的、生产级别的 Spring 应用(SpringBoot 的底层实现是 Spring)。大多数 SpringBoot 应用只需要编写少量配置,即可快速整合 Spring 平台以及第三方技术。SpringBoot 的特性如下:

  • 快速创建独立 Spring 应用
  • 直接嵌入 Tomcat、Jetty、Undertow,无需部署 war
  • 提供可选的 starter,简化应用的整合
  • 按需自动配置 Spring 以及第三方库
  • 提供生产级特性:如监控指标、健康检查、外部化配置等
  • 无代码生成、无 XML 配置文件

SpringBoot 快速体验

学习目标

浏览器发送 /hello 请求,服务器端返回 Hello,Spring Boot 3!

创建 Maven 项目

创建 Maven 项目,SpringBoot 项目一般都需要继承自 spring-boot-starter-parent

1
2
3
4
5
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.5</version>
</parent>

或者引入 spring-boot-dependencies,这适用于项目已经拥有 Parent 依赖包的场景

1
2
3
4
5
6
7
8
9
10
11
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.0.5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

依赖继承关系

继承 spring-boot-starter-parent 的时候,其实也算是继承自 spring-boot-dependencies,这是因为 parent 其实也是继承 dependencies,同时 parent 里面增加了一些插件,并指定了 Maven 的编译版本。

导入启动器

导入 Web 启动器,目的是引入 Spring MVC、Tomcat 等。

1
2
3
4
5
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

主启动程序

添加 @SpringBootApplication 注解,声明这是一个 SpringBoot 应用程序。

1
2
3
4
5
6
7
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {
SpringApplication.run(MainApplication.class,args);
}
}

业务控制器

1
2
3
4
5
6
7
8
9
10
@RestController
public class HelloController {

@GetMapping("/hello")
public String hello(){

return "Hello,Spring Boot 3!";
}

}

项目打包

在 Maven 的配置文件中添加打包插件后,执行 mvn clean package 命令可以将项目打成可执行的 Jar 包,并可以使用 java -jar xxx.jar 命令直接启动 SpringBoot 项目。

1
2
3
4
5
6
7
8
9
<build>
<plugins>
<!-- SpringBoot应用打包插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

代码测试

浏览器访问 http://127.0.0.1:8080/hello,若正常返回 Hello,Spring Boot 3!,则说明第一个 SpringBoot 3 应用启动成功。

代码下载

本章节所需的案例代码,可以直接从 GitHub 下载对应章节 spring-boot3-01

SpringBoot 特性总结

简化整合

导入相关的场景启动器,即可拥有相关的功能,默认支持的所有场景启动器可参照 官方文档

  • 官方提供的场景启动器:命名为 spring-boot-starter-*
  • 第三方提供的场景启动器:命名为 *-spring-boot-starter

简化配置

  • 配置基本都有默认值
  • 能写的所有配置信息都可以在 官方文档 获取到
  • 集中式管理配置,只需要修改 application.properties 这个文件就可以

简化部署

可以将项目打包为可执行的 Jar 包,并通过 java -jar xxx.jar 命令直接运行项目。

简化运维

支持外部化配置(往 Jar 包所在目录下放一个 application.properties 文件)、监控、健康检查。

SpringBoot 常用注解

SpringBoot 摒弃 XML 的配置方式,改为全注解驱动开发。

组件注册

注解介绍

常用的组件注册注解:

  • @Configuration、@SpringBootConfiguration
  • @Bean、@Scope
  • @Controller、 @Service、@Repository、@Component
  • @Import
  • @ComponentScan

使用案例

组件注册的步骤

  • 1、使用 @Configuration 注解编写一个配置类
  • 2、在配置类中,自定义方法往容器中注册组件,并配合使用 @Bean 注解
  • 3、或使用 @Import 注解导入第三方的组件
  • 第一种组件注册方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration
public class UserConfiguration {

/**
* 注册组件,组件在容器中的名称默认是方法名,且默认是单实例
*/
@Bean
public User user() {
User user = new User();
user.setId(1L);
user.setName("Peter");
return user;
}

}
  • 第二种组件注册方式
1
2
3
4
5
6
7
8
/**
* 注册组件,组件在容器中的名称默认是全类名,且默认是单实例
*/
@Import(User.class)
@Configuration
public class UserConfiguration {

}

条件判断

注解介绍

如果注解指定的判断条件成立,则触发指定的行为。值得一提的是,条件注解的命名规则一般为 @ConditionalOnXxx

条件注解说明
@ConditionalOnClass 如果类路径中存在这个类,则触发指定行为
@ConditionalOnMissingClass 如果类路径中不存在这个类,则触发指定行为
@ConditionalOnBean 如果容器中存在这个 Bean(组件),则触发指定行为
@ConditionalOnMissingBean 如果容器中不存在这个 Bean(组件),则触发指定行为

条件注解列表

除了上述介绍的四种条件注解,SpringBoot 还提供了以下的条件注解。

  • @ConditionalOnRepositoryType (org.springframework.boot.autoconfigure.data)
  • @ConditionalOnDefaultWebSecurity (org.springframework.boot.autoconfigure.security)
  • @ConditionalOnSingleCandidate (org.springframework.boot.autoconfigure.condition)
  • @ConditionalOnWebApplication (org.springframework.boot.autoconfigure.condition)
  • @ConditionalOnWarDeployment (org.springframework.boot.autoconfigure.condition)
  • @ConditionalOnJndi (org.springframework.boot.autoconfigure.condition)
  • @ConditionalOnResource (org.springframework.boot.autoconfigure.condition)
  • @ConditionalOnExpression (org.springframework.boot.autoconfigure.condition)
  • @ConditionalOnClass (org.springframework.boot.autoconfigure.condition)
  • @ConditionalOnEnabledResourceChain (org.springframework.boot.autoconfigure.web)
  • @ConditionalOnMissingClass (org.springframework.boot.autoconfigure.condition)
  • @ConditionalOnNotWebApplication (org.springframework.boot.autoconfigure.condition)
  • @ConditionalOnProperty (org.springframework.boot.autoconfigure.condition)
  • @ConditionalOnCloudPlatform (org.springframework.boot.autoconfigure.condition)
  • @ConditionalOnBean (org.springframework.boot.autoconfigure.condition)
  • @ConditionalOnMissingBean (org.springframework.boot.autoconfigure.condition)
  • @ConditionalOnMissingFilterBean (org.springframework.boot.autoconfigure.web.servlet)
  • @ConditionalOnInitializedRestarter (org.springframework.boot.devtools.restart)
  • @ConditionalOnGraphQlSchema (org.springframework.boot.autoconfigure.graphql)
  • @ConditionalOnJava (org.springframework.boot.autoconfigure.condition)
  • @Profile (org.springframework.context.annotation)

使用案例

使用例子

  • @ConditionalOnBean(value = 组件类型,name = 组件名字),判断容器中是否有这个类型的组件,并且名称是指定的值
  • 如果存在 FastsqlException 这个类,往容器中放一个 Cat 组件,名为 cat01,否则就往容器中放一个 Dog 组件,名为 dog01
  • 如果系统中有 Dog 这个组件,就往容器中放一个 User 组件,名为 jim,否则就放一个 User,名叫 tom
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Configuration
public class SystemConfiguration {

@ConditionalOnClass(name = "com.alibaba.druid.FastsqlException")
@Bean(name = "cat01")
public Cat cat() {
return new Cat();
}

@ConditionalOnMissingClass(value = "com.alibaba.druid.FastsqlException")
@Bean(name = "dog01")
public Dog dog() {@Import(User.class)
}

@ConditionalOnBean(value = Dog.class)
@Bean(name = "jim")
public User userJim() {
return new User();
}

@ConditionalOnMissingBean(value = Dog.class)
@Bean(name = "tom")
public User userTom() {
return new User();
}

}

属性绑定

本章节所需的案例代码,可以直接从 GitHub 下载对应章节 spring-boot3-02

注解介绍

属性绑定注解说明
@ConfigurationProperties 声明组件的属性与配置文件中的哪些前缀开始项进行绑定
@EnableConfigurationProperties 快速注册注解

@EnableConfigurationProperties 注解的使用场景

SpringBoot 只会扫描主程序类所在的包及其下面的子包。如果导入了第三方包,即使组件上标注了 @Component@ConfigurationProperties 注解,组件也不会生效。因为这些组件都扫描不进来,此时使用 @EnableConfigurationProperties 注解就可以快速进行属性绑定,并把组件注册进容器。

使用案例

将容器中任意组件(Bean)的属性值和配置文件的配置项的值进行绑定的步骤

  • 1、往容器中注册组件(@Configuration@Component@Bean
  • 2、使用 @ConfigurationProperties 声明组件和配置文件的哪些配置项进行绑定
第一种写法
  • 添加配置内容,在项目的 application.properties 配置文件中添加配置内容
1
2
3
pig.id=1
pig.age=3
pig.name=peter
  • 声明 Bean 类,通过 @Configuration 注解声明 Bean 类,并使用 @ConfigurationProperties 注解将 Bean 的属性值和配置文件的配置项的值进行绑定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@Configuration
@ConfigurationProperties(prefix = "pig")
public class PigProperties {

private Long id;

private String name;

private Integer age;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

@Override
public String toString() {
return "PigProperties{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}

}
  • 测试代码
1
2
3
4
5
6
7
8
9
10
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(MainApplication.class, args);
PigProperties properties = context.getBean(PigProperties.class);
System.out.println(properties);
}

}
  • 测试结果
1
PigProperties{id=1, name='peter', age=3}
第二种写法

使用 @Bean + @ConfigurationProperties 注解,将 Bean 的属性值和配置文件的配置项的值进行绑定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@ConfigurationProperties(prefix = "pig")
public class PigProperties {

private Long id;

private String name;

private Integer age;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

@Override
public String toString() {
return "PigProperties{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}

}
1
2
3
4
5
6
7
8
9
@Configuration
public class SystemConfiguration {

@Bean
public PigProperties pigProperties() {
return new PigProperties();
}

}
1
2
3
4
5
6
7
8
9
10
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(MainApplication.class, args);
PigProperties properties = context.getBean(PigProperties.class);
System.out.println(properties);
}

}
第三种写法

同样使用 @Bean + @ConfigurationProperties 注解,将 Bean 的属性值和配置文件的配置项的值进行绑定,但 @ConfigurationProperties 注解不再声明在 Bean 类上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class PigProperties {

private Long id;

private String name;

private Integer age;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

@Override
public String toString() {
return "PigProperties{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}

}
1
2
3
4
5
6
7
8
9
10
@Configuration
public class SystemConfiguration {

@Bean
@ConfigurationProperties(prefix = "pig")
public PigProperties pigProperties() {
return new PigProperties();
}

}
1
2
3
4
5
6
7
8
9
10
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(MainApplication.class, args);
PigProperties properties = context.getBean(PigProperties.class);
System.out.println(properties);
}

}
第四种写法

使用 @ConfigurationProperties + @EnableConfigurationProperties 注解,将 Bean 的属性值和配置文件的配置项的值进行绑定,不再使用 @Configuration@Component@Bean 等注解。值得一提的是,@EnableConfigurationProperties 注解可以快速进行 Bean 属性的绑定,并把 Bean 注册进容器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@ConfigurationProperties(prefix = "pig")
public class PigProperties {

private Long id;

private String name;

private Integer age;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

@Override
public String toString() {
return "PigProperties{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@SpringBootApplication
@EnableConfigurationProperties(PigProperties.class)
public class MainApplication {

public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(MainApplication.class, args);
PigProperties pigProperties = context.getBean(PigProperties.class);
System.out.println(pigProperties);

SheepProperties sheepProperties = context.getBean(SheepProperties.class);
System.out.println(sheepProperties);
}

}

SpringBoot 如何学习

SpringBoot 是框架的框架,底层基于 Spring。在企业开发中,必须能调整每一个场景的底层行为,100% 的项目一定遇到底层行为自定义的需求。

类比摄影技术

  • 傻瓜:自动配置好
  • 单反:焦距、光圈、快门、感光度....
  • 傻瓜 + 单反
  • 如何学习

    • 1、理解自动配置原理
      • 导入 starter –> xxxxAutoConfiguration 生效 –> 导入组件 –> xxxProperties –> 配置文件
    • 2、理解其他框架的底层实现
      • 拦截器
    • 3、可以随时定制化任何组件
      • 配置文件
      • 自定义组件
  • 开发级别

    • 普通开发:导入 starter,编写 Controller、Service、Mapper、偶尔修改配置文件
    • 高级开发:自定义组件、自定义配置、自定义 starter
  • 开发核心

    • 这个场景自动配置导入了哪些组件,我们能不能 Autowired 进来使用
    • 能不能通过修改配置改变组件的一些默认参数
    • 需不需要自己完全定义这个组件
    • 场景定制化

  • 最佳实践

    • 选择场景,导入到项目
      • 官方:starter
      • 第三方:去 Maven 仓库搜
    • 写配置,更改配置文件的关键项
      • 如数据库参数(连接地址、账号密码…)
    • 分析这个场景给我们导入了哪些能用的组件
      • 自动装配这些组件进行后续使用
      • 不满意 starter 提供的自动配好的默认组件
        • 定制化
        • 改配置
        • 自定义组件
  • 实践案例(整合 Redis)

    • 选场景
      • spring-boot-starter-data-redis
      • RedisAutoConfiguration 就是这个场景的自动配置类
    • 写配置
      • 分析这个场景的自动配置类开启了哪些属性绑定关系
      • @EnableConfigurationProperties(RedisProperties.class)
      • 修改 Redis 相关的核心配置
    • 分析组件
      • 分析到 RedisAutoConfiguration 往容器中注册了 StringRedisTemplate
      • 往业务代码中自动装配 StringRedisTemplate
    • 定制化
      • 修改配置文件
      • 自定义组件,自己往容器中放一个 StringRedisTemplate

参考资料