什么是Spring Boot

Spring Boot 是所有基于 Spring Framework 5.0 开发的项目。Spring Boot 的设计是为了让你尽可能快的跑起来 Spring 应用程序,并且尽可能减少你的配置文件。

设计目的: 用来简化 Spring 应用的初始搭建以及开发过程。

从最根本上来讲,Spring Boot 就是一些库的集合,它能够被任意项目所使用。它使用 “习惯优于配置” (项目中存在大量的配置,此外还内置一个习惯性的配置)的理念让你的项目快速运行起来。spring boot 其实不是什么新的框架,它默认配置了很多框架的使用方式,就像 maven 整合了所有的 jar 包,spring boot 整合了所有的框架,总结一下及几点:

  1. 为所有 Spring 开发提供一个更快更广泛的入门体验
  2. 零配置。无冗余代码生成和 XML 强制配置,遵循“约定大于配置”
  3. 集成了大量常用的第三方库的配置, Spring Boot 应用为这些第三方库提供了几乎可以零配置的开箱即用的能力
  4. 提供一系列大型项目常用的非功能性特征,如嵌入服务器等

1、SpringBoot 的特点

  • 为基于 Spring 的开发提供更快的入门体验
  • 开箱即用,没有代码生成,也无需 XML 配置。同时也可以修改默认值来满足特定的需求
  • 提供了一些大型项目中常见的非功能性特性,如嵌入式服务器、外部配置等
  • SpringBoot 不是对 Spring 功能上的增强,而是提供了一种快速使用 Spring 的方式

2、SpringBoot 的核心功能

  • 起步依赖

起步依赖本质上是一个 Maven 项目对象模型(Project Object Model,POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。

简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。

  • 自动配置

Spring Boot 的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定 Spring 配置应该用哪个,不该用哪个。该过程是 Spring 自动完成的。

SpringBoot 快速入门

1、代码实现

① 创建 Maven 工程并在pom.xml添加 SpringBoot 的依赖

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
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.atguigu</groupId>
<artifactId>springboot_demo</artifactId>
<version>1.0-SNAPSHOT</version>

<!-- 父工程 -->
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.1.6.RELEASE</version>
</parent>

<dependencies>
<!--web起步包 虽然是web工程,但不需要打war包,直接打jar就行-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

</project>

添加 web 起步包,框架会自动导入其它相关包

也可以找到 tomcat 和 web

② 编写 SpringBoot 引导类

要通过 SpringBoot 提供的引导类起步,SpringBoot 才可以进行访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.atguigu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* @author: ShiGuang
* @create: 2021-06-09 09:07
* @description:
*/
// 声明该类是一个SpringBoot引导类
@SpringBootApplication
public class Application {
public static void main(String[] args) {
// run方法表示运行SpringBoot的引导类 run参数就是SpringBoot引导类的字节码对象
SpringApplication.run(Application.class, args);
}
}

③ 编写 Controller

在引导类同级包或者子级包中创建StartController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.atguigu.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* @author: ShiGuang
* @create: 2021-06-09 09:10
* @description:
*/
@RestController
@RequestMapping("/get")
public class StartController {
@RequestMapping("/hello")
public String hello() {
return "Hello SpringBoot!";
}
}

④ 测试

执行 SpringBoot 起步类的main方法,控制台打印日志如下

浏览器访问:http://localhost:8080/get/hello

可以看到输出结果

这样就省去了 springmvc.xml 的配置

2、SpringBoot 工程热部署

我们在开发中反复修改类、页面等资源,每次修改后都是需要重新启动才生效,这样每次启动都很麻烦,浪费了大量的时间

因此我们希望可以在修改代码后不重启就能生效

① 在 pom.xml 中添加如下配置就可以实现这样的功能,我们称之为热部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--热部署配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

② 开启 Intellij IEDA 自动编译,需要对 IDEA 进行自动编译的设置,如下:

Shift+Ctrl+Alt+/,选择 Registry

勾选 compiler.automake.allow.when.app.running

结束

3、使用 idea 快速创建 SpringBoot 项目

通过 idea 快速创建的 SpringBoot 项目的 pom.xml 中已经导入了我们选择的 web 的起步依赖的坐标

SpringBoot 原理分析

1、起步依赖原理分析

① 分析 spring-boot-starter-parent

按住 Ctrl 点击pom.xml中的spring-boot-starter-parent,跳转到了spring-boot-starter-parent的 pom.xml`,xml 部分配置如下:

按住 Ctrl 点击pom.xml中的spring-boot-starter-dependencies,跳转到了spring-boot-starter-dependenciespom.xml,xml 部分配置如下

从上面的spring-boot-starter-dependenciespom.xml中我们可以发现,一部分坐标的版本、依赖管理、插件管理已经定义好,所以我们的 SpringBoot 工程继承spring-boot-starter-parent后已经具备版本锁定等配置了(不会出现版本冲突的问题)。所以起步依赖的作用就是进行依赖的传递。

② 分析 spring-boot-starter-web

不是所有的 jar 都传递,需要指定,用到哪个 jar 包,导入哪个 jar 包

按住 Ctrl 点击 pom.xml 中的spring-boot-starter-web,跳转到了spring-boot-starter-web的 pom.xml,xml 部分配置如下

从上面的spring-boot-starter-web的 pom.xml 中我们可以发现,spring-boot-starter-web就是将 web 开发要使用的spring-webspring-webmvc等坐标进行了“打包”,这样我们的工程只要引入spring-boot-starter-web起步依赖的坐标就可以进行 web 开发了,同样体现了依赖传递的作用,同时加载 tomcat,只要启动 main 方法,就相当于起到 tomcat 进行开发;同时加载 json,支持 springmvc 的数据请求和响应。

2、自动配置原理解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.atguigu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class SpringbootDemo2Application {

public static void main(String[] args) {
ApplicationContext act = SpringApplication.run(SpringbootDemo2Application.class, args);
for (String name : act.getBeanDefinitionNames()) {
System.out.println(name);
}
}
}

运行默认自动配置加载的对象

按住 Ctrl 点击查看启动类SpringbootDemo2Application上的注解@SpringBootApplication

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
@AliasFor(
annotation = EnableAutoConfiguration.class
)
Class<?>[] exclude() default {};

... ... ...

}

重点关注最后三个注解

@SpringBootConfiguration

@SpringBootConfiguration : 表示当前类具有配置类的作用

@EnableAutoConfiguration

@EnableAutoConfiguration:自动配置:根据当前引入的依赖包,猜测需要创建的工程类型,以及工程中有可能创建的对象,根据猜测自动创建工程所需的相关实例 bean,当程序启动,会自动加载扫描所有 classpath:/META-INF/spring.factories文件 ,并且创建对应实例

详细查看:按住 Ctrl 点击查看注解 @EnableAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

Class<?>[] exclude() default {};

String[] excludeName() default {};
}

其中,@Import(AutoConfigurationImportSelector.class) 导入了 AutoConfigurationImportSelector

按住 Ctrl 点击查看 AutoConfigurationImportSelector 源码 , 下载元数据

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
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {

....................
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
....................

}

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// SpringFactoriesLoader.loadFactoryNames 方法的作用就是从META-INF/spring.factories文件中读取指定类对应的类名称列表
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
// 在META-INF/spring.factories中找不到自动配置类。需要看看文件是否正确
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}

其中,SpringFactoriesLoader.loadFactoryNames 方法的作用就是从 META-INF/spring.factories 文件中读取指定类对应的类名称列表

spring.factories 文件中有关自动配置的配置信息如下:摘抄重点,springboot 启动之后,会自动加载 dispatcherServlet

1
2
3
4
5
6
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

... ... ... ... ... ...
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
... ... ... ... ... ...

上面配置文件存在大量的以 Configuration 为结尾的类名称,这些类就是存有自动配置信息的类,而SpringApplication 在获取这些类名后再加载

我们以 DispatcherServletAutoConfiguration 为例来分析:

按住Ctrl点击 DispatcherServletAutoConfiguration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {

/*
* The bean name for a DispatcherServlet that will be mapped to the root URL "/"
*/
public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";

... ... ...
}

@ComponentScan

@componentScan (包扫描):扫描当前包及其子包下被 @Component@Controller@Service@Repository注解标记的类并纳入到 spring 容器中进行管理,所以这个注解会自动注入所有在主程序所在包下的组件。默认把当前启动类所在的包作为扫描包的起点,例如现在的测试项目,扫描 com.atguigu

3、举例自动配置

新建包 com.atguigu.pojo , 创建类 User

1
2
3
4
5
6
7
8
9
package com.atguigu.pojo;

/**
* @author: ShiGuang
* @create: 2021-06-09 19:38
* @description:
*/
public class User {
}

resources文件夹下面 新建 /META-INF/spring.factories 文件

1
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.atguigu.pojo.User

运行主程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.atguigu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class SpringbootDemo2Application {

public static void main(String[] args) {
ApplicationContext act = SpringApplication.run(SpringbootDemo2Application.class, args);
for (String name : act.getBeanDefinitionNames()) {
System.out.println(name);
}
}
}

查看结果:

SpringBoot 的配置文件

1、配置文件类型和作用

SpringBoot 是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用application.properties或者application.yml(application.yaml)进行配置。

SpringBoot 默认会从 Resources 目录下加载application.propertiesapplication.yml(application.yaml)文件

配置application.yml

1
2
3
4
5
6
# 配置tomcat 端口号
server:
port: 1888
# 配置项目所在的根目录
servlet:
context-path: /springboot_demo02

新建 controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.atguigu.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* @author: ShiGuang
* @create: 2021-06-09 19:52
* @description:
*/
@RestController
public class UserController {

@RequestMapping("/get")
public String save() {
return "success";
}
}

运行 main 程序,访问:http://localhost:1888/springboot_demo02/get

按照上面的方式找到并打开:spring-configuration-metadata.json

为什么可以在 resources 下创建application.properties或者application.yml文件呢?我们查看 springboot 的启动依赖:

点击 spring-boot-starter-parent

可以看到:除了可以使用 application.propertes 文件,也可以使用 application.yml 或者 application.yaml 文件。

2、yml 配置文件简介

YML 文件格式是 YAML (YAML Aint Markup Language)编写的文件格式,YAML 是一种直观的能够被电脑识别的的数据数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持 YAML 库的不同的编程语言程序导入,比如: C/C++, Ruby, Python, Java, Perl, C#, PHP 等。YML 文件是以数据为核心的,比传统的 xml 方式更加简洁。

YML 文件的扩展名可以使用.yml 或者.yaml

yml 配置文件的语法

① 配置普通数据

key: value

1
name: shiguang

value 之前必须有一个空格!

② 配置对象数据

key:
key1: value1
key2: value2
或者:
key: {key1: value1,key2: value2}

1
2
3
user:
username: root
password: root

在 yml 语法中,相同缩进代表同一个级别,一般按一下 tab 键

在 user 类中,通过注解 @ConfigurationProperties (prefix=“yml 配置文件中 key 的前缀”)可以将配置文件中的配置自动与实体进行映射

首先导入pom.xml依赖

1
2
3
4
5
6
<!--读取配置文件注解-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

配置 User 实体类

1
2
3
4
5
6
7
8
9
@Component
@ConfigurationProperties(value = "user")
public class User implements Serializable {

private String username;
private String password;

// 生成各种方法
... ... ...

修改 SpringbootDemo2Application

1
2
3
4
5
6
7
8
9
@SpringBootApplication
public class SpringbootDemo2Application {

public static void main(String[] args) {
ApplicationContext act = SpringApplication.run(SpringbootDemo2Application.class, args);
User user = (User) act.getBean("user");
System.out.println(user);
}
}

运行程序,查看到输出

③ 配置 Map 数据

map:
key: value1
key: value2

④ 配置数组(List、Set)数据

1
2
3
4
5
key:
- value1
- value2
或者:
key: [value1,value2]

注意:- 与 value1 之间存在一个空格

示例:

1
2
3
4
5
6
7
# 配置数据集合
city:
- beijing
- shanghai
- guangzhou
# 或者行内注入
city: [beijing,shanghai,guangzhou]

3、配置文件与配置类的属性映射方式

使用注解@Value 映射

我们可以通过@Value 注解将配置文件中的值映射到一个 Spring 管理的 Bean 的字段上

例如:

application.yml配置如下:

1
2
3
4
5
6
server:
port: 1888

user:
username: root
password: root

修改 UserController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@RestController
public class UserController {

@RequestMapping("/get")
public String save() {
return "success";
}

@Value("${user.username}")
private String username;

@Value("${user.password}")
private String password;

@RequestMapping("/getUser")
@ResponseBody
public String quick(){
//获得配置文件的信息
return "username:"+username+",password="+password;
}
}

浏览器访问地址:http://localhost:1888/getUser

页面正常显示: