踏入山门
1. SpringBoot 简介
Spring Boot 基于 Spring 开发,其本身并不提供 Spring 框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于 Spring 框架的应用程序。也就是说,SpringBoot 并不是用来替代 Spring 的解决方案,而是和 Spring 框架紧密结合用于提升 Spring 开发者的工具,其帮助开发人员把时间都集中在业务开发上。
SpringBoot 以约定大于配置的核心思想,帮开发者进行了很多默认设置,多数 SpringBoot 应用只需要很少的 Spring 配置。同时它集成了大量常用的第三方库配置,如 Redis、MongoDB、Jpa、RabbitMQ、Quartz 等,SpringBoot 应用中这些第三方库几乎可以零配置开箱即用。
Spring 是如何简化 Java 开发的?
- 基于 POJO 的轻量级和最小侵入性编程;
- 通过 IOC、依赖注入和面向接口实现松耦合;
- 基于切面(AOP)和惯例进行声明式编程;
- 通过切面和模版减少样式代码。
SpringBoot 的主要优点:
- 为所有 Spring 开发者更快的入门;
- 开箱即用,提供各种默认配置来简化项目配置;
- 内嵌式容器简化 Web 项目;
- 没有冗余代码生成和 XML 配置的要求。
2. 自动装配
2.1 Springboot 的依赖管理
对于 springboot 项目必须引入的父工程:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
该父工程本身的父工程如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
spring-boot-dependencies
中几乎声明了所有开发中常用的依赖的版本号,此即所谓自动版本仲裁机制。
2.2 场景启动器
启动器的名称:
spring-boot-starter-*
的启动器(其中*
代表某种场景),为官方提供的启动器。*-spring-boot-starter
的启动器,为第三方为我们提供的简化开发的场景启动器。
只要引入 starter,这个场景的所有常规需要的依赖都会被自动引入。
所有场景启动器最底层的依赖均为:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
2.3 依赖版本号
引入依赖默认都可以不写版本,但如果要引入非版本仲裁的 jar,需要写版本号。版本仲裁的版本号可以通过spring-boot-dependencies
父工程里对应的“规定该依赖版本的 key 名称”查看,如需修改在当前项目的 pom.xml 中重写该配置即可。
例如,父工程spring-boot-dependencies-2.5.3.pom
中规定的 mysql 版本号为<mysql.version>8.0.26</mysql.version>
,在当前项目的 pom.xml 中重新配置 mysql.version
属性,即可覆盖 spring-boot 的默认版本,如下:
<properties>
<mysql.version>5.1.43</mysql.version>
</properties>
SpringBoot 所有的自动配置功能都在spring-boot-autoconfigure
包里面。
2.4 web 项目的包扫描
默认的包结构:
主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来,无需进行以前的包扫描配置
若要改变扫描路径,可以使用两种方法进行配置:
@SpringBootApplication(scanBasePackages="com.atguigu")
@ComponentScan
指定扫描路径
事实上,
@SpringBootApplication
注解等同于@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan("com.atguigu.boot")
3. 启动类
启动类 SpringApplication 主要做了 4 件事情:
- 推断应用的类型是普通的项目还是 web 项目;
- 查找并加载所有可用初始化器,设置到 initializers 属性中;
- 找出所有的应用程序监听器,设置到 listeners 属性中;
- 推断并设置 main 方法的定义类,找到运行的主类。
4. 快速入门案例
4.1 引入依赖
所有的官方 springboot 依赖都以 spring-boot-starter 开头。
依赖主要涉及父工程和启动器。
核心依赖在父工程中:spring-boot-dependencies;在引入一些 springboot 依赖时,不需要指定版本,因为有这些版本仓库。
启动器:说白了就是 SpringBoot 的启动场景,如 spring-boot-starter-web 会帮我们自动导入 web 环境所有的依赖。springboot 会将所有的功能场景都变成一个个的启动器,当我们要使用 xxx 功能,只需找到相应的启动器 starter 即可。
<!-- 父工程 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
</parent>
<dependencies>
<!-- 启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
4.2 创建主程序
package com.kuang.helloWorld;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication // 标注这个类是一个 springboot 的应用
public class HelloworldApplication {
// 将 springboot 的应用启动
public static void main(String[] args) {
SpringApplication.run(HelloworldApplication.class, args);
}
}
@SpringBootApplication
标注一个类是一个 springboot 的应用
4.3 编写业务
@RestController
public class HelloController {
@RequestMapping("/hello")
public String handle01(){
return "Hello, Spring Boot 2!";
}
}
4.4 测试
直接运行主程序的 main 方法。
4.5 简化部署
项目的 pom 中引入以下 maven 插件,可以使得在执行mvn package
命令时,该项目打的 jar 包直接就是可执行的 jar,通过jar -jar xxx.jar
即可启动项目。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
该插件发挥的作用是,在打包时将项目相关的依赖也同时打入项目的 jar 中,而非像普通的 maven 项目那样只会将当前项目的直接代码打入 jar 包,后者在部署时若想启动项目,还需要单独部署项目中依赖的一系列 jar 包。
经测试,带该插件与不带插件打出的 jar 包分别如下:
no-plugin.jar
:$ tree no-plugin no-plugin ├── META-INF │ ├── MANIFEST.MF │ └── maven │ └── com.chuan │ └── play-spring-boot │ ├── pom.properties │ └── pom.xml ├── application-dev.yml ├── application-prod.yml ├── application-test.yml ├── application.properties ├── application.yaml ├── application.yml └── com └── chuan ├── PlaySpringBootApplication.class ├── component │ ├── LifecycleTester.class │ ├── RequestScopeTester.class │ └── SmartLifecycleTester.class ├── config │ └── ControllerHandler.class ├── controller │ └── HelloController.class └── service ├── HelloService.class └── impl └── HelloServiceImpl.class 11 directories, 17 files
with-plugin.jar
:$ tree with-plugin with-plugin ├── BOOT-INF │ ├── classes │ │ ├── application-dev.yml │ │ ├── application-prod.yml │ │ ├── application-test.yml │ │ ├── application.properties │ │ ├── application.yaml │ │ ├── application.yml │ │ └── com │ │ └── chuan │ │ ├── PlaySpringBootApplication.class │ │ ├── component │ │ │ ├── LifecycleTester.class │ │ │ ├── RequestScopeTester.class │ │ │ └── SmartLifecycleTester.class │ │ ├── config │ │ │ └── ControllerHandler.class │ │ ├── controller │ │ │ └── HelloController.class │ │ └── service │ │ ├── HelloService.class │ │ └── impl │ │ └── HelloServiceImpl.class │ ├── classpath.idx │ ├── layers.idx │ └── lib │ ├── fastjson-2.0.12.jar │ ├── fastjson2-2.0.12.jar │ ├── fastjson2-extension-2.0.12.jar │ ├── jackson-annotations-2.13.4.jar │ ├── jackson-core-2.13.4.jar │ ├── jackson-databind-2.13.4.jar │ ├── jackson-datatype-jdk8-2.13.4.jar │ ├── jackson-datatype-jsr310-2.13.4.jar │ ├── jackson-module-parameter-names-2.13.4.jar │ ├── jakarta.annotation-api-1.3.5.jar │ ├── jul-to-slf4j-1.7.36.jar │ ├── log4j-api-2.17.2.jar │ ├── log4j-to-slf4j-2.17.2.jar │ ├── logback-classic-1.2.11.jar │ ├── logback-core-1.2.11.jar │ ├── slf4j-api-1.7.36.jar │ ├── snakeyaml-1.30.jar │ ├── spring-aop-5.3.25.jar │ ├── spring-beans-5.3.25.jar │ ├── spring-boot-2.7.8.jar │ ├── spring-boot-autoconfigure-2.7.8.jar │ ├── spring-boot-jarmode-layertools-2.7.8.jar │ ├── spring-context-5.3.25.jar │ ├── spring-core-5.3.25.jar │ ├── spring-expression-5.3.25.jar │ ├── spring-jcl-5.3.25.jar │ ├── spring-web-5.3.25.jar │ ├── spring-webmvc-5.3.25.jar │ ├── tomcat-embed-core-9.0.71.jar │ ├── tomcat-embed-el-9.0.71.jar │ └── tomcat-embed-websocket-9.0.71.jar ├── META-INF │ ├── MANIFEST.MF │ └── maven │ └── com.chuan │ └── play-spring-boot │ ├── pom.properties │ └── pom.xml └── org └── springframework └── boot └── loader ├── ClassPathIndexFile.class ├── ExecutableArchiveLauncher.class ├── JarLauncher.class ├── LaunchedURLClassLoader$DefinePackageCallType.class ├── LaunchedURLClassLoader$UseFastConnectionExceptionsEnumeration.class ├── LaunchedURLClassLoader.class ├── Launcher.class ├── MainMethodRunner.class ├── PropertiesLauncher$1.class ├── PropertiesLauncher$ArchiveEntryFilter.class ├── PropertiesLauncher$ClassPathArchives.class ├── PropertiesLauncher$PrefixMatchingArchiveFilter.class ├── PropertiesLauncher.class ├── WarLauncher.class ├── archive │ ├── Archive$Entry.class │ ├── Archive$EntryFilter.class │ ├── Archive.class │ ├── ExplodedArchive$AbstractIterator.class │ ├── ExplodedArchive$ArchiveIterator.class │ ├── ExplodedArchive$EntryIterator.class │ ├── ExplodedArchive$FileEntry.class │ ├── ExplodedArchive$SimpleJarFileArchive.class │ ├── ExplodedArchive.class │ ├── JarFileArchive$AbstractIterator.class │ ├── JarFileArchive$EntryIterator.class │ ├── JarFileArchive$JarFileEntry.class │ ├── JarFileArchive$NestedArchiveIterator.class │ └── JarFileArchive.class ├── data │ ├── RandomAccessData.class │ ├── RandomAccessDataFile$1.class │ ├── RandomAccessDataFile$DataInputStream.class │ ├── RandomAccessDataFile$FileAccess.class │ └── RandomAccessDataFile.class ├── jar │ ├── AbstractJarFile$JarFileType.class │ ├── AbstractJarFile.class │ ├── AsciiBytes.class │ ├── Bytes.class │ ├── CentralDirectoryEndRecord$1.class │ ├── CentralDirectoryEndRecord$Zip64End.class │ ├── CentralDirectoryEndRecord$Zip64Locator.class │ ├── CentralDirectoryEndRecord.class │ ├── CentralDirectoryFileHeader.class │ ├── CentralDirectoryParser.class │ ├── CentralDirectoryVisitor.class │ ├── FileHeader.class │ ├── Handler.class │ ├── JarEntry.class │ ├── JarEntryCertification.class │ ├── JarEntryFilter.class │ ├── JarFile$1.class │ ├── JarFile$JarEntryEnumeration.class │ ├── JarFile.class │ ├── JarFileEntries$1.class │ ├── JarFileEntries$EntryIterator.class │ ├── JarFileEntries$Offsets.class │ ├── JarFileEntries$Zip64Offsets.class │ ├── JarFileEntries$ZipOffsets.class │ ├── JarFileEntries.class │ ├── JarFileWrapper.class │ ├── JarURLConnection$1.class │ ├── JarURLConnection$JarEntryName.class │ ├── JarURLConnection.class │ ├── StringSequence.class │ └── ZipInflaterInputStream.class ├── jarmode │ ├── JarMode.class │ ├── JarModeLauncher.class │ └── TestJarMode.class └── util └── SystemPropertyUtils.class 23 directories, 118 files
4.6 附:总的 pom.xml(一般意义)
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 父项目:继承 spring-boot-starter-parent 的依赖管理,控制版本与打包等内容 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<!-- 项目元数据信息 -->
<groupId>com.kuang</groupId>
<artifactId>springboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<!-- 项目具体依赖 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 打 jar 包的插件:配合 spring-boot-starter-parent 就可
以把 Spring Boot 应用打包成 jar 来直接运行 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
5. 配置文件
5.1 概述
SpringBoot 是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用 application.properties 或者 application.yml 进行配置。
SpringBoot 默认会从 Resources 目录下加载 application.properties 或 application.yml 文件,优先级:properties > yaml > yml。
yml 配置文件还可以编写占位符生成随机数:
person:
name: qinjiang${random.uuid} # 随机 uuid
age: ${random.int} # 随机 int
happy: false
birth: 2000/01/01
maps: { k1: v1, k2: v2 }
lists:
- code
- girl
- music
dog:
name: ${person.hello:other}_旺财
age: 1
5.2 多配置文件
在编写主配置文件时,文件名可以是application-{profile}.properties/yml
,用来指定多个环境版本,只需通过一个配置来选择需要激活的环境。
对于 properties 文件:
- 如,多个环境如下:
- application-test.properties:代表测试环境配置
- application-dev.properties:代表开发环境配置
- Springboot 不会直接启动这些配置文件,它默认使用 application.properties 主配置文件,当需要使用某个环境时就直接 application.properties 中激活:
spring.profiles.active=dev
对于 yml 文件,同 properties,但是不需要创建多个配置文件,可以使用 yaml 的多文档块功能,更加方便了(不过只在配置量少的时候推荐这种使用):
server:
port: 8081
#选择要激活的环境块
spring:
profiles:
active: test
---
server:
port: 8082
spring:
profiles: dev # 配置环境的名称
---
server:
port: 8083
spring:
profiles: test # 配置环境的名称
注:如果 yml 和 properties 同时都配置了某一项内容(如端口),并且没有激活其他环境,默认会使用 properties 文件的配置。
5.3 配置文件的加载路径
springboot 配置文件的加载位置:springboot 启动会扫描以下位置的 application.properties/yml 文件作为 springboot 的默认配置文件,优先级从高到低,高优先级的配置会覆盖低优先级的同项配置,对于不同项配置则是会进行互补:
- 项目路径下的 config/文件夹的配置;
- 项目路径下的配置文件;
- 资源路径下的 config/文件夹的配置;
- 资源路径下的配置文件;
5.4 智能提示小插件
可以添加一个依赖使编写 springboot 配置文件的时候,对自己的类(非 springboot 官方配置)也能开启智能提示:
<!--@ConfigurationProperties 注解的执行器配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>