一、前言
在N年前整理过 Spring Boot 的入门教程,当时还是 1.x 的内容。如今 Spring Boot 已经升级到 3.x 版本,不过版本之间的使用差距不大,此次发布文章仅当作常规知识以及新版本功能的补充。
如果你已经掌握 Spring 和 SpringMVC 知识,但还不熟 Spring Boot 内容的读者,您可以尝试阅读本篇文章,如有不清楚的地方,可以留言评论,笔者看到自会补充说明。
二、快速入门
开发环境: jdk >= 17, maven >= 3.6.3
场景:简单实现 web 项目,浏览器发起请求,服务端做出响应
2.1 搭建项目
- 使用IDEA创建一个空项目
- 打开 pom.xml 文件引入 Spring Boot 3 依赖
1 | <!-- spring boot 项目最根本的依赖 --> |
- 创建启动类
1 | @SpringBootApplication |
- 创建控制器
1 | @RestController |
- 启动项目
在 MainAppliction 类中右键点击 Run 'MainAppliction' 即可启动。
- 测试
通过查看IDEA的控制台,我们可以知道启动的 web 项目默认使用 8080 端口,请求的的根路径为 /。
因此,我们使用浏览器访问 http://localhost:8080/hello 即可得到 Hello World 的响应。
至此,一个简单的 web 项目就搭建成功了。
2.2 常用注解
Spring Boot 摈弃的 XML 配置方式,改用全注解驱动。
为了方便看懂下文的案例,在这里提前介绍 Spring Boot 常用注解。
@SpringBootApplication:只能标记在一个类上,表示该类中声明的 Main 方法为项目启动入口
@ComponentScan:标记在类上,可以配置需要被 Spring 容器扫描的路径
@Configuration:标记在类上,表示该类为配置类
@Bean:标记在方法上,表示方法返回的对象会被 Spring 容器管理成为一个 bean,需要配合 @Configuration 使用
@Import:标记在类上,可以配置其类的 class,表示将其他类与当前配置类一起被 Spring 容器扫描和管理
@EnableAutoConfiguration:标记在类上,表示开启自动配置
@EnableConfigurationProperties:标记在类上,表示启动配置属性功能
@ConfigurationProperties:标记在类上,表示该类会根据绑定关系将配置文件的属性封装到类对象中,需要配合 @EnableConfigurationProperties 使用
@ConditionalOnClass:标记在类/方法上,如果类路径中存在这个类,则触发指定行为
@ConditionalOnMissingClass:标记在类/方法上,如果类路径中不存在这个类,则触发指定行为
@ConditionalOnBean:标记在类/方法上,如果容器中存在这个Bean(组件),则触发指定行为
@ConditionalOnMissingBean:标记在类/方法上,如果容器中不存在这个Bean(组件),则触发指定行为
2.3 组件注册
在传统的 Spring 项目中,如果需要注册组件,我们通常会在类上标记 @Service
,@Repository
,@Component
这类注解,然后配置需要扫描的类路径即可让 Spring 容器管理这些组件。
而在 Spring Boot 中同样可以上边的方式使用,不过已经不使用 XML 作为主配置文件来配置扫描路径,而是使用 @ComponentScan
来代替。
其中 @SpringBootApplication
作为一个组合注解,它底层就包含 @ComponentScan
注解,其默认扫描范围是被 @SpringBootApplication
标记的类路径以及其子路径。
换句话说,除了启动类会被 Spring 管理,启动类所在的路径和子路径都会被 Spring 扫描,被扫描到的类标记了 @Service
,@Repository
,@Component
这类注解都会被 Spring 容器管理。
然而实际开发中,我们并不单单自己实现功能,更多时候会使用第三方的依赖。将第三方库引入项目后,我们是没法在他们的类上标记注解让 Spring 管理。
因此 Spring 团队提供了一些注解来解决这类问题,以下提供两个方案实现对第三方组件的注册:
- 使用
@Configuration
和@Bean
注册
1 | @Configuration |
- 使用
@Configuration
和@Import
注册
1 | @Configuration |
2.4 条件注册
通过 @ComponentScan
扫描包路径的类并创建和管理 Bean 非常简单,但是如果被扫描的类很多,维护的 Bean 就多,进而会影响项目的启动以及内存资源。
如果只希望个别的类被 Spring 容器管理,那么就可以采用条件注册方式声明 Bean。
场景:如果项目引入 druid 数据库连接池,那就注册 MyBatis 相关组件;如果没有引入,则注册 JDBC 组件
1 | @Configuration |
其中,com.alibaba.druid.DruidRuntimeException
为 druid 依赖中的一个异常类。如果系统加载到该类,那么 Spring 就会创建 MyBatisService,否则创建 JDBCService。
同理,如果是根据是否存在某个 Bean 来判断注册哪个组件,我们可以使用 @ConditionalOnBean
或 @ConditionalOnMissingBean
。
三、配置文件
为了方便统一维护配置数据(应用名称、端口、数据库连接等),避免硬编码,Spring Boot 也需要额外的配置文件解决前边的问题。
3.1 文件格式
其中,固定名称的配置文件为 application.properties 或 application.yml
配置文件通常是放在项目中的 src/main/resources 目录中。
- 如果使用 .properties 格式的配置文件,数据内容格式如下:
1 | #应用名称 |
- 如果使用 .yml 格式的配置文件,数据内容格式如下:
1 | #应用名称 |
细节:两个配置文件可以同时存在,系统优先加载 yml 文件后加载 properties 文件,因此如果两种配置文件都定义相同的配置,那么 properties 文件中的配置会覆盖 yml 文件中的配置。
3.2 自定义配置
其中上边的配置参数是 Spring Boot 给我们封装好的,其实我们可以在配置文件中自定义配置。
我们以 application.properties 文件为例:
1 | user.name=jack |
自定义好配置后,我们可以使用三种方式获取配置:
- 使用 @Value 注解
1 | @RestController |
- 使用 Environment API
1 | @RestController |
- 使用对象封装
1 | @Component |
其中,需要在 @ConfigurationProperties
中设置好配置的前缀,类中则声明配置.
最后的属性名称。
3.3 复杂配置
如果封装的对象中定义复杂属性如下:
1 | @Component |
那么配置文件应该如下书写如下。
application.properties 文件格式:
person.name=张三
person.age=66
person.likes[0]=唱
person.likes[1]=跳
person.address[0].province=江苏省
person.address[0].city=苏州市
person.address[1].province=浙江省
person.address[1].city=杭州市
person.income.firstIncome.name=rap
person.income.firstIncome.money=2
person.income.secondIncome.name=篮球
person.income.secondIncome.money=2
其中, firstIncome 和 secondIncome 为自定义,表示 Map 的 key,或者可以理解为指向 Income 对象的引用名。
application.yml 文件格式:
person:
name: 张三
age: 66
likes: ['唱', '跳']
address:
- province: 江苏省
city: 苏州市
- province: 浙江省
city: 杭州市
income:
firstIncome:
name: rap
money: 2
secondIncome:
name: 篮球
money: 2
或者
person:
name: 张三
age: 66
likes[0]: 唱
likes[1]: 跳
address[0]:
province: 江苏省
city: 苏州市
address[1]:
province: 浙江省
city: 杭州市
income:
firstIncome:
name: rap
money: 2
secondIncome:
name: 篮球
money: 2
yml文件配置细节:
- 针对封装属性名为驼峰标识,建议 yml 文件中使用 - 拼接,如: registerDay 属性在配置文件中定义为 registery-day
- 配置文件中的属性值为字符串,可以直接书写,也可以加单引号或双引号,其中单引号不会转义,双引号则会
四、Profiles
Spring Profiles 提供一种隔离配置的方式,使其仅在特定环境生效。
上文介绍了 application.properties 配置文件的用法,但在实际开发中我们会搭建开发、测试、生产环境,不同的环境配置各不相同,因此需要多个配置文件来维护参数。
4.1 指定环境
Spring Profiles 针对配置文件提供了 application-{profile}.properties 的文件命名规范来区分不同环境的配置。
比如我们在开发中创建四个配置文件,application.properties, application-dev.properties, application-testroperties, application-prod.properties。
其中,application.properties 用于设置公共配置,其他三个文件分别用于设置开发,测试,生产环境下的配置。
注意:profile 为任意名称,只要确保唯一即可。
这些文件可以共存,在项目启动过程中,application.properties 一定会被加载使用,而系统是如何知道加载剩余的哪个配置文件呢?
4.2 激活配置文件
Spring Boot 提供了两种方式:
- 方式一:
在 application.properties 中设置激活的环境配置
spring.profiles.active=dev
- 方式二:
在启动项目时设置命令参数:
java -jar your-application.jar --spring.profiles.active=dev
使用任意一种方式启动项目,都会加载 application.properties 和 application-dev.properties 两个文件。
如果两个配置文件中设置了相同的配置(如:端口号),那么 {profiles} 的配置会覆盖 application.properties 的配置。
- 效果图:
4.3 激活组件
上文的配置是告诉系统使用哪个环境的配置文件,如果我们希望不同的环境加载不同的组件是否可以实现呢?答案是肯定的。
Spring 提供了 @Profile 配合 @Component 或 @Configuration 使用可以实现不同环境的加载。
- 实战演练
组件类:
1 | public class Animal { |
1 | public class Cat extends Animal { |
1 | public class Dog extends Animal { |
配置类:
1 | @Configuration |
配置类中,我们希望当激活 dev 环境时创建 Cat 组件,当激活 test 环境时创建 Dog 组件。
- 效果图:
五、日志
Spring 底层自己定义了 commons-logging 作为内部日志接口,其支持 jul,Log4j, Log4j2,Logback 等实现。
而 Spring Boot 3 已不再支持 Log4j,默认使用 Logback 作为日志实现方案。
默认情况下,日志会按照一定的格式输出到控制台中展示。如果想要修改日志输出格式或输出位置,那么需要修改日志配置。
5.1 常见配置
#控制台日志输出格式
logging.pattern.console=
#日志文件路径
logging.file.path=
#日志文件名(路径+文件名),如果不带路径,最终会在项目的同级目录中创建对应名称的日志
logging.file.name=
#打印sql相关日志
logging.level.sql=
#打印web相关日志
logging.level.web=
#打印 com.light.boot 包路径下的日志,该路径为项目中的路径
logging.level.com.light.boot=
#logback日志存档的文件名格式,默认值为 ${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz
logging.logback.rollingpolicy.file-name-pattern=
#logback日志存档前,每个日志文件的最大大小,默认值为 10M
logging.logback.rollingpolicy.max-file-size=
#logback日志文件被删除之前,可以容纳的最大大小,默认值为 0B
logging.logback.rollingpolicy.total-size-cap=
#logback日志文件保存的最大天数,默认值为 7 天
logging.logback.rollingpolicy.max-history=
其中,logging.level.sql
和 logging.level.web=
由 SpringBoot 封装。
logging.level.sql
会打印如下路径中的日志:
org.springframework.jdbc.core,
org.hibernate.SQL,
org.jooq.tools.LoggerListener
logging.level.web=
会打印如下路径中的日志:
org.springframework.core.codec,
org.springframework.http,
org.springframework.web,
org.springframework.boot.actuate.endpoint.web,
org.springframework.boot.web.servlet.ServletContextInitializerBeans
通过上边的配置可以很好的对项目中想要的日志进行打印输出。
当然如果你对外部的日志文件配置更加熟悉,我们也可以整合使用,而且实际项目中更多时候也是使用外部的日志文件配置。
如果你使用 Logback 作为日志文件实现方案,只需在 src/main/resources 目录下创建名为 logback-spring.xml 文件,然后配置该日志相关配置即可。
如果你使用 Log4j2 作为日志文件实现方案,需要完成 2 个步骤:
- 添加依赖
1 | <dependency> |
- 在 src/main/resources 目录下创建名为 log4j2-spring.xml 文件,然后配置该日志相关配置即可。
5.2 打印日志
配制好日志相关参数后,我们只需要在代码中创建日志对象,根据需求打印即可。
1 | @RestController |
由于 SpringBoot3 默认使用 INFO 日志级别,因此最终结果只会打印 INFO,WARN,ERROR 级别的日志。
5.3 日志级别
日志级别由低到高分别是:ALL, TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF;
ALL:打印所有日志
TRACE:追踪框架详细流程日志,一般不使用
DEBUG:开发调试细节日志
INFO:关键、感兴趣信息日志
WARN:警告但不是错误的信息日志,比如:版本过时
ERROR:业务错误日志,比如出现各种异常
FATAL:致命错误日志,比如jvm系统崩溃
OFF:关闭所有日志记录
日志级别需要配合 logging.level
使用。如果使用外部日志文件,则需要在其文件中配置。
比如我们想打印项目中 service 层的代码日志,包名为 com.light.boot.service:
logging.level.com.light.boot.service=INFO
这样配置即可实现打印 INFO 级别的效果。
补充:如果设置使用某个级别日志,那么最终会打印该级别以及它之后更高级别的日志。
比如,使用 INFO 级别,最终打印 INFO, WARN, ERROR 级别日志。使用 WARN 级别,最终打印 WARN, ERROR 级别日志。
由于 Spring Boot 只是整合通用的日志接口,而具体的日志实现由对应的厂商完成,因此如果想要了解更多日志内容以及配置内容,请自行到对应的官网查阅内容。
六、打包部署
项目功能开发完成就需要打包部署到服务器上运行,而 Spring Boot 也提供了自己的打包插件。
在 pom.xml 文件中引入:
1 | <build> |
使用IDEA右侧的Maven功能项或者在终端手动命令 mvn clean pacakge
即可打出一个可执行的 jar 包。
如果想启动项目,则使用 java -jar xxx.jar
即可启动。
当然,在实际项目中启动 jar 包还需要更多的参数(jvm 堆栈、配置文件的选择等),具体内容自行网上查阅。