SpringBoot 基础知识

发布时间 2023-11-05 15:06:47作者: Ferko

​#SpringBoot#​

本文基于 SpringBoot 2.0 最新稳定版 2.7.6 ;目前 SpringBoot 3.0已经发布,后续会体验新版新特性。
官网:Spring Boot

SpringBoot 程序的优点

  • 起步依赖(简化依赖配置)
  • 自动配置(简化常用工程相关配置)
  • 辅助功能(内置服务器,.....)

快速上手 SpringBoot 工程

联网初始化 SpringBoot

SpringBoot 官方初始化链接https://start.spring.io
Aliyun 初始化链接http://start.aliyun.com

国内设置 aliyun SpringBoot 初始化链接

Pasted image 20230201213127

配置如下图

Pasted image 20230201214738

选择 SpringBoot 版本 以及 需要引入的依赖 后 点击下一步

Pasted image 20230201214907

整体目录结构如下:

Pasted image 20230201215123

创建一个 Controller 进行测试

Pasted image 20230201215604

//REST模式  
@RestController  
@RequestMapping("/books")  
public class BookController {  
  
    @GetMapping  
    public String getById(){  
        System.out.println("SpringBoot is running....");  
        return "SpringBoot is running....";  
    }  
  
}

启动 SpringBoot
找到 SpringBoot 启动类,DEBUG 模式运行

Pasted image 20230201215714

日志如下图:

Pasted image 20230201215812

访问刚才写的接口 localhost:8080/books

Pasted image 20230201215851

最简单 SpringBoot 工程所包含的基础文件

  • pom.xml

Pasted image 20230201220245

  • Application 启动类
@SpringBootApplication  
public class Springboot01QuickstartApplication {  
  
    public static void main(String[] args) {  
        SpringApplication.run(Springboot01QuickstartApplication.class, args);  
    }  
  
}

手工初始化 SpringBoot

不需要联网创建,但是 maven 依赖需要联网下载,之前创建过的话,本地仓库有依赖也不需要联网

创建一个空的 Maven 模块

Pasted image 20230201221927

这里是没有启动类的,并且 pom.xml 文件中也很干净

Pasted image 20230201222058

接下来我们需要 在 pom.xml 文件中 使用 parent 标签引入 SpringBoot 的父POM

<parent>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-parent</artifactId>  
    <version>2.7.6</version>  
    <relativePath/> <!-- lookup parent from repository -->  
</parent>

父POM中包含很多依赖,且统一规定了版本,但是只是声明,如果需要使用,需要在下面进行引入才可以使用
引入我们需要的依赖 web 依赖(可以看到,无需填写版本号,也能引入依赖)

<dependencies>  
    <dependency>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter-web</artifactId>  
    </dependency>  
</dependencies>

插件目前只是打包时使用,我们暂且不用引入。

组合好的 pom.xml 文件如图:

Pasted image 20230201222614

刷新 Maven 后,创建一个新的 SpringBoot 启动类

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

同样,创建一个 controller ,启动后测试一下

@RestController  
@RequestMapping("/books")  
public class BookController {  
    @GetMapping  
    public String helloSpingBoot(){  
        String result = "Hello,SpringBoot!";  
        System.out.println(result);  
        return result;  
    }  
}

Pasted image 20230201223336

SpringBoot pom.xml 解析

spring-boot-starter-parent 规范依赖版本

  1. 开发 SpringBoot 工程要继承 spring-boot-starter-parent
  2. spring-boot-starter-parent 中定义了非常多个依赖管理
  3. 继承 parent 模块可以有效规避多个依赖使用相同技术时出现的依赖冲突
  4. spring-boot-starter-parent 仅仅是定义了依赖和版本,并未真正引入依赖,我们可以在 子pom 中按需引入,且不用显式的声明版本(如果pom爆红,也可以手动指定版本)

在所有的 SpringBoot 工程中的 pom.xml 中 都引入了 spring-boot-starter-parent 父POM

Pasted image 20230202200344

点击进入 父pom 文件,发现还有一个 spring-boot-dependencies 的 父pom 文件,这里就是管理依赖与指定版本的pom文件

Pasted image 20230202200727

spring-boot-dependencies pom 概览

<?xml version="1.0" encoding="UTF-8"?>  
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">  
  <modelVersion>4.0.0</modelVersion>  
  <groupId>org.springframework.boot</groupId>  
  <artifactId>spring-boot-dependencies</artifactId>  
  <version>2.7.6</version>  
  <packaging>pom</packaging>  
  <name>spring-boot-dependencies</name>  
  <description>Spring Boot Dependencies</description>  

  <properties>  
	<activemq.version>5.16.5</activemq.version>
	...省略更多版本信息
  </properties>

  <dependencyManagement>  
	<dependencies>
		<dependency>  
			<groupId>org.apache.activemq</groupId>  
			<artifactId>activemq-amqp</artifactId>  
			<version>${activemq.version}</version>  
		</dependency>
		...省略更多依赖信息
	<dependencies>
  </dependencyManagement>
  
  <pluginManagement>  
	<plugins>  
	    <plugin>  
	      <groupId>org.codehaus.mojo</groupId>  
	      <artifactId>build-helper-maven-plugin</artifactId>  
	      <version>${build-helper-maven-plugin.version}</version>  
	    </plugin>
	</plugins> 
	...省略更多插件信息
  </pluginManagement>  
</project>

可以看到这里使用 properties 定义了很多依赖和插件的版本信息,然后使用 dependencyManagement 和
pluginManagement 标签 用来管理依赖和插件的版本,子项目引入后无需声明版本号。

Maven 中的dependencyManagement元素提供了一种管理依赖版本号的方式。在dependencyManagement元素中声明所依赖的jar包的版本号等信息,那么所有子项目再次引入此依赖jar包时则无需显式的列出版本号。Maven会沿着父子层级向上寻找拥有dependencyManagement 元素的项目,然后使用它指定的版本号。

spring-boot-starter 快速配置依赖

  1. 通过依赖传递的性质,只需引入一个功能的 spring-boot-start,就能自动引入功能所需要的所有依赖。
  2. 通过 spring-boot-start ,可以减少依赖配置,快速配置。

以 spring-boot-starter-web 为例
Pasted image 20230202203514

点击进入发现是一个pom文件
查看依赖元素,是在这里引入了 springmvc 以及 web 依赖

Pasted image 20230202203623

在 spring-boot-starter-web 中还引入了另一个starter -> spring-boot-starter-tomcat,点击进入,同样是一个pom ,查看依赖,原来是在这里引入了 tomcat 的相关依赖。

Pasted image 20230202203828


SpringBoot 启动引导类

  1. SpringBoot 的引导类是工程的执行入口,运行 main 方法就可以启动项目
  2. SpringBoot 工程运行后会初始化 Spring 容器,扫描引导类所在包下的所有组件,加载为bean
  3. 自动配置非常牛掰!!!!

SpringBoot启动类 获取 Spring 容器

Pasted image 20230202204851|550

SpringApplication.run() 方法可以返回 spring 容器对象,通过容器对象可以获取 bean

@SpringBootApplication  
public class Application {  
    public static void main(String[] args) {  
        // 获取到 Spring 容器  
        ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args);  
  
        // 通过容器获取 bean       
        BookController bean = ctx.getBean(BookController.class);  
        System.out.println("bean======>" + bean);  
    }  
}

Pasted image 20230202205137

@SpringBootApplication 注解

@SpringBootApplication 是一个复合注解

Pasted image 20230202205517

@SpringBootConfiguration 配置类

其实就是一个配置类

Pasted image 20230202205614

@EnableAutoConfiguration 自动配置

这个非常重要,原理解析后面会详细介绍

Pasted image 20230202205832

@ComponentScan 组件包扫描

默认配置扫描 SpringBoot 启动当前包下的所有组件

Pasted image 20230202210033

内嵌 Tomcat web容器

  1. SpringBoot 默认支持三款 web服务器:Tomcat、Jetty、Undertow;默认使用 Tomcat。
  2. 内嵌 Tomcat web容器的工作原理是将 Tomcat 服务器作为对象运行,并将该对象交给 Spring 容器管理
  3. 内嵌 Tomcat web容器是 SpringBoot 辅助功能之一

在查看 spring-boot-starter-web pom依赖时,我们就发现了 spring-boot-starter-tomcat 里面引入了 Tomcat 容器相关的依赖。

Pasted image 20230202203828

更换其他 web 服务器

Jetty 比 Tomcat 更加轻量级,可扩展性更强(相较于 Tomcat),谷歌应用引擎(GAE)已经全面切换为 Jetty

Pasted image 20230202211520

启动后日志:

Pasted image 20230202211816

之前 Tomcat 的日志:

Pasted image 20230202211938

SpringBoot 配置文件

配置文件优先级

properties > yml > yaml
三种配置文件共存,会共存、叠加,相同的配置,优先级高的会覆盖掉优先级低的,不相同的配置则会共同存在。保留下来

properties 配置文件

键值对形式

Pasted image 20230202214505

yml 配置文件

后缀名:yaml / yml 均可,推荐使用 yml,yml 优先级 > yaml
详细介绍参考:yaml 配置文件

Pasted image 20230202221505

官方配置查询文档

官网:Spring | Home

Pasted image 20230202221746

找到你对应版本的 SpringBoot ,点击阅读文档

Pasted image 20230202221819

找到 application properties 即可

Pasted image 20230202222018

所有配置都在这里:

Pasted image 20230202222132

yaml 配置绑定

单一配置绑定 @Value("${}")

注意:yaml的值为基本类型(数字、字符串)及其包装类,可以直接解析转换,绑定特殊类型(List、Map、日期等),需要额外处理。

@RestController  
@RequestMapping("/books")  
public class BookController {  
  
    @Value("${chart}")  
    private String chart;  
    @Value("${chart2.str}")  
    private String str;  
    @Value("${list1[0]}")  
    private Integer item;  
    @Value("#{'${list2}'.split(',')}")  
    private List<Integer> list;  
    @Value("#{${map2}}")  
    private Map<String,String> map;  
    @Value("${datetime}")  
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")  
    private LocalDateTime dateTime;  
  
    @GetMapping  
    public String helloSpingBoot(){  
        String result = "Hello,SpringBoot! Current DateTime:"+dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));  
        System.out.println(result);// Hello,SpringBoot! Current DateTime:2023-02-07 20:04:30  
        System.out.println(dateTime);// 2023-02-07T20:04:30  
        System.out.println(chart);// 普通字符串  
        System.out.println(str);// 层级展示  
        System.out.println(item);// 1  
        System.out.println(list);// [1, 2, 3, 4, 5]  
        System.out.println(map);// {name=zhangsan, sex=male}  
        return result;  
    }  
}

如果一定要使用 @Value 注解读取,List、Map 在 yaml 中需要使用行内写法,然后在注解内使用 SpEL表达式;

list2: 1,2,3,4,5  
map2: '{"name": "zhangsan", "sex": "male"}'
@Value("#{'${list2}'.split(',')}")  
private List<Integer> list;

@Value("#{${map1}}")  
private Map<String,String> map;

或者使用注解 @ConfigurationProperties 注解,定义一个配置类 Bean,定义属性用来接收特殊类型,下面会介绍

SpringBoot 环境变量 Environment

使用 @Autowired 注解 自动注入 Environment,通过getProperty()方法获取配置文件中的值。

注意: 行外写法获取的值均为 null

# 列表 行外写法  
list1:  
  - 1  
  - 2  
  - 3  
  - 4  
  - 5
# Map 或 对象 行外写法  
map1:  
  name: "zhangsan"  
  sex: "male"
@RestController  
@RequestMapping("/books")  
public class BookController {  
  
    @Autowired  
    private Environment environment;  
  
	@GetMapping("/env")  
	public String environment(){  
	    String result = environment.getProperty("datetime");  
	    System.out.println(environment.getProperty("list1"));// null 行外写法获取为null  
	    System.out.println(environment.getProperty("list2"));// 1,2,3,4,5  
	    System.out.println(environment.getProperty("map1"));// null 行外写法获取为null  
	    System.out.println(environment.getProperty("map2"));// {"name": "zhangsan", "sex": "male"}  
	    System.out.println(environment.getProperty("chart2.str"));// 层级展示  
	    System.out.println(environment.getProperty("datetime"));// 2023-02-07 20:04:30  
	    return result;  
	}
}

配置属性类 @ConfigurationProperties

使用 @Component 定义为 Bean
使用 @ConfigurationProperties(prefix = "datesource") 绑定 yaml 配置
注意:prefix 或 value 不能使用驼峰命名

datasource:  
  driver: com.mysql.jdbc.Driver  
  url: jdbc:mysql://localhost:3306/springboot  
  username: root  
  password: root666
@Data  
@Component  
@ConfigurationProperties(prefix = "datasource")  
public class MyDataSource {  
  
    private String driver;  
    private String url;  
    private String username;  
    private String password;  
}
@RestController  
@RequestMapping("/books")  
public class BookController {  

    @Autowired  
    private MyDataSource dataSource;  
  
    @GetMapping("/config")  
    public void config(){  
        System.out.println(dataSource);  
        // 打印:
        //MyDataSource(driver=com.mysql.jdbc.Driver, url=jdbc:mysql://localhost:3306/springboot, username=root, password=root666)
    }  
}

整合第三方技术

整合 Junit

[[SpringBoot 测试相关]]

新建一个模块,引入 spring-boot-starterspring-boot-starter-test 依赖

<dependencies>  
    <dependency>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter</artifactId>  
    </dependency>  
    <dependency>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter-test</artifactId>  
    </dependency>  
</dependencies>

创建后目录结构,

ApplicationTests 测试类

类上使用 @SpringBootTest 注解,测试方法上使用 @Test 注解

注意:测试类 要与 启动类 包名保持一致,否则会报错,如果不一致,需要再 @SpringBootTest(classes = Application.class) 指定你的启动类

@SpringBootTest  
public class ApplicationTests {  
  
    /**  
     * 简单测试一下  
     */  
    @Test  
    void initTest(){  
        System.out.println("test=========");  
    }  
}

再定义一个接口与实现类 注册为 bean ,测试 SpringBoot Test 类的依赖自动注入能力

@Repository  
public class BookDaoImpl implements BookDao {  
    @Override  
    public void save() {  
	    System.out.println("BookDao保存中....");
    }  
}

将 bean 自动注入进来,运行测试方法。

@SpringBootTest  
public class ApplicationTests {  
  
    @Autowired  
    private BookDao bookDao;  
  
    @Test  
    void testBookDao(){  
        bookDao.save();  
    }  

}

运行结果:

整合 MyBatis

这里只介绍简单使用,详细见 MyBatis

引入基本依赖

<dependencies>  
    <!-- springboot 基础包 -->  
    <dependency>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter</artifactId>  
    </dependency>  
    <!-- mysql 驱动 -->  
    <dependency>  
        <groupId>mysql</groupId>  
        <artifactId>mysql-connector-java</artifactId>  
        <scope>runtime</scope>  
    </dependency>  
    <!-- mybatis -->  
    <dependency>  
        <groupId>org.mybatis.spring.boot</groupId>  
        <artifactId>mybatis-spring-boot-starter</artifactId>  
        <version>2.2.2</version>  
    </dependency>  
    <!-- 测试相关 -->  
    <dependency>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter-test</artifactId>  
        <scope>test</scope>  
    </dependency>  
    <!-- lombok -->  
    <dependency>  
        <groupId>org.projectlombok</groupId>  
        <artifactId>lombok</artifactId>  
        <version>1.18.24</version>  
    </dependency>  
</dependencies>

数据源配置

spring:  
  datasource:  
    driver-class-name: com.mysql.cj.jdbc.Driver  
    url: jdbc:mysql://192.168.33.102:3308/spring_boot?useUnicode=true&characterEncoding=UTF-8&useSSL=true  
    username: root  
    password: ferko
# 驼峰映射 createTime : create_time
mybatis:  
  configuration:  
    map-underscore-to-camel-case: true

编写 Dao 层,使用 Mapper 注解

/**  
 * 书籍  
 *  
 * @author Ferko  
 * @date 2023/02/11 07:56  
 */@Mapper  
public interface BookDao {  
  
    /**  
     * 通过主键获取书籍  
     *  
     * @param id 主键  
     * @return {@link Book }  
     */  
    @Select("select * from te_book where id = #{id}")  
    public Book getById(Long id);  
  
}

实体类

/**  
 * 书籍 实体类  
 *  
 * @author Ferko  
 * @date 2023/02/11 07:53  
 */@Data  
public class Book {  
  
    /** 主键 */  
    private Long id;  
    /** 类型 */  
    private String type;  
    /** 书籍名称 */  
    private String name;  
    /** 书籍描述 */  
    private String description;  
    /** 价格 */  
    private String price;  
    /** 创建时间 */  
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;  
    /** 更新时间 */  
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;  
}

使用测试类

@SpringBootTest  
public class SpringBootTests {  
    @Autowired  
    private BookDao bookDao;  
  
    @Test  
    public void testDao() {  
        System.out.println(bookDao.getById(1L));  
    }  
  
}

返回结果

整合 MyBatis-Plus

第三方技术的 starter ,boot-starter 是在后面,mybatis-plus-boot-starter

引入依赖

<dependencies>  
    <!-- springboot 基础包 -->  
    <dependency>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter</artifactId>  
    </dependency>  
    <!-- mysql 驱动 -->  
    <dependency>  
        <groupId>mysql</groupId>  
        <artifactId>mysql-connector-java</artifactId>  
        <scope>runtime</scope>  
    </dependency>  
    <!-- MyBatisPlus -->  
    <dependency>  
        <groupId>com.baomidou</groupId>  
        <artifactId>mybatis-plus-boot-starter</artifactId>  
        <version>3.5.2</version>  
    </dependency>  
    <!-- 测试相关 -->  
    <dependency>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter-test</artifactId>  
        <scope>test</scope>  
    </dependency>  
    <!-- lombok -->  
    <dependency>  
        <groupId>org.projectlombok</groupId>  
        <artifactId>lombok</artifactId>  
        <version>1.18.24</version>  
    </dependency>  
</dependencies>

配置文件

spring:  
  datasource:  
    driver-class-name: com.mysql.cj.jdbc.Driver  
    url: jdbc:mysql://192.168.33.102:3308/spring_boot?useUnicode=true&characterEncoding=UTF-8&useSSL=true  
    username: root  
    password: ferko

使用之前的 dao 和 entity ,dao 继承 baseMapper<> ,可以获得 MP 定义好的通用方法,无需我们再去写

如果你的表名与实体类名不一致,记得在实体类,加入 @TableName("te_book")

或者是在配置文件 加入全局配置,前提是你所有表名前缀都一致。

/**  
 * 书籍  
 *  
 * @author Ferko  
 * @date 2023/02/11 07:56  
 */
@Mapper
@TableName("te_book")
public interface BookDao extends BaseMapper<Book> {  
  
}

测试类,使用 MP 自带的方法

@SpringBootTest  
public class SpringBootTests {  
  
    @Autowired  
    private BookDao bookDao;  
  
    @Test  
    public void test(){  
        bookDao.selectById(1L);  
    }  
}

运行结果

整合 Druid 连接池

引入依赖

<dependencies>  
    <!-- springboot 基础包 -->  
    <dependency>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter</artifactId>  
    </dependency>  
    <!-- mysql 驱动 -->  
    <dependency>  
        <groupId>mysql</groupId>  
        <artifactId>mysql-connector-java</artifactId>  
        <scope>runtime</scope>  
    </dependency>  
    <!-- mybatis -->  
    <dependency>  
        <groupId>org.mybatis.spring.boot</groupId>  
        <artifactId>mybatis-spring-boot-starter</artifactId>  
        <version>2.2.2</version>  
    </dependency>  
    <!-- druid 连接池 -->  
    <dependency>  
        <groupId>com.alibaba</groupId>  
        <artifactId>druid-spring-boot-starter</artifactId>  
        <version>1.2.15</version>  
    </dependency>  
    <!-- 测试相关 -->  
    <dependency>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter-test</artifactId>  
        <scope>test</scope>  
    </dependency>  
    <!-- lombok -->  
    <dependency>  
        <groupId>org.projectlombok</groupId>  
        <artifactId>lombok</artifactId>  
        <version>1.18.24</version>  
    </dependency>  
</dependencies>

配置文件,推荐配置二

# 配置一  
spring:  
  datasource:  
    driver-class-name: com.mysql.cj.jdbc.Driver  
    url: jdbc:mysql://192.168.33.102:3308/spring_boot?useUnicode=true&characterEncoding=UTF-8&useSSL=true  
    username: root  
    password: ferko  
    type: com.alibaba.druid.pool.DruidDataSource  
  
# 配置二 推荐  
spring:  
  datasource:  
    druid:  
      driver-class-name: com.mysql.cj.jdbc.Driver  
      url: jdbc:mysql://192.168.33.102:3308/spring_boot?useUnicode=true&characterEncoding=UTF-8&useSSL=true  
      username: root  
      password: ferko