spring-boot
SpringBoot
Spring Boot 是一个开源的 Java 框架,它基于 Spring 框架,旨在简化基于 Spring 的应用程序的开发和配置。以下是 Spring Boot 的几个关键特点和优势
- 快速开发:Spring Boot 提供了开箱即用的配置,简化了项目的搭建过程,开发者可以在更短的时间内启动新的项目。
- 自动配置:Spring Boot 能够根据项目中存在的依赖自动配置 Spring 应用程序,减少了大量的手动配置工作,使开发者能够专注于业务逻辑。
- 独立的运行:Spring Boot 应用程序可以打成一个独立的 JAR 文件,包含内嵌的服务器(如 Tomcat、Jetty),这样可以轻松部署和运行。
- 生产就绪特性:Spring Boot 提供了一些开箱即用的功能,帮助开发者开发和监控生产环境中的应用程序,包括健康检查、度量监控、外部配置管理等。
- 广泛的生态系统:作为 Spring 的一部分,Spring Boot 可以无缝集成 Spring 生态系统中的其他项目(如 Spring Security、Spring Data、Spring Cloud 等),便于构建完整的企业级应用。
- 约定优于配置:Spring Boot 常常遵循“约定优于配置”的原则,减少了大量的配置文件和复杂的 XML 配置,提高了开发效率。
特性:
- 快速创建独立 Spring 应用
- 直接嵌入Tomcat、Jetty or Undertow
- 提供可选的 starter,简化应用整合
- 按需自动配置 Spring 以及 第三方库
- 提供生产级特性:如 监控指标、健康检查、外部化配置等
- 无代码生成、无xml; 都是基于自动配置技术
总结:简化开发,简化配置,简化整合,简化部署,简化监控,简化运维
场景启动器
场景启动器:导入相关的场景,拥有相关的功能。
- 官方提供的场景:命名为:spring-boot-starter-*
- 第三方提供场景:命名为:*-spring-boot-starter
依赖管理
maven父子继承,父项目可以锁定版本
<!--应用的父项目-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<!--我们继续追查spring-boot-starter-parent
最后发现最上层的父项目是-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
<!---这才是真正的项目管理者,他指定了所有需要的jar包版本依赖->
如何修改默认版本号
- version标签 精确声明版本
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>6.1.0</version>
</dependency>
- 子覆盖父的属性设置 mysql.version
<properties>
<java.version>17</java.version>
<mysql.version>8.0.3</mysql.version>
</properties>
自动配置 - 完整流程
自动配置流程细节梳理:
1、导入starter-web
:导入了web开发场景
- 1、场景启动器导入了相关场景的所有依赖:
starter-json
、starter-tomcat
、springmvc
- 2、每个场景启动器都引入了一个
spring-boot-starter
,核心场景启动器。 - 3、核心场景启动器引入了
spring-boot-autoconfigure
包。 - 4、
spring-boot-autoconfigure
里面囊括了所有场景的所有配置。 - 5、只要这个包下的所有类都能生效,那么相当于SpringBoot官方写好的整合功能就生效了。
- 6、SpringBoot默认却扫描不到
spring-boot-autoconfigure
下写好的所有配置类。(这些配置类给我们做了整合操作),默认只扫描主程序所在的包。
2、主程序:@SpringBootApplication
-
1、
@SpringBootApplication
由三个注解组成@SpringBootConfiguration
、@EnableAutoConfiguratio
、@ComponentScan
-
2、SpringBoot默认只能扫描自己主程序所在的包及其下面的子包,扫描不到
spring-boot-autoconfigure
包中官方写好的配置类 -
3、
**@EnableAutoConfiguration**
:SpringBoot 开启自动配置的核心。 -
-
- 是由
@Import(AutoConfigurationImportSelector.class)
提供功能:批量给容器中导入组件。
- 是由
-
- SpringBoot启动会默认加载 142个配置类。
-
- 这142个配置类来自于
spring-boot-autoconfigure
下META-INF/spring/**org.springframework.boot.autoconfigure.AutoConfiguration**.imports
文件指定的
- 这142个配置类来自于
- 项目启动的时候利用 @Import 批量导入组件机制把
autoconfigure
包下的142xxxxAutoConfiguration
类导入进来(自动配置类) - 虽然导入了
142
个自动配置类
-
-
4、按需生效:
-
- 并不是这
142
个自动配置类都能生效 - 每一个自动配置类,都有条件注解
@ConditionalOnxxx
,只有条件成立,才能生效
- 并不是这
3、**xxxxAutoConfiguration**
自动配置类
- 1、给容器中使用@Bean 放一堆组件。
- 2、每个自动配置类都可能有这个注解
@EnableConfigurationProperties(**ServerProperties**.class)
,用来把配置文件中配的指定前缀的属性值封装到xxxProperties
属性类中 - 3、以DataSourceAutoConfiguration为例:所有配置都是以
spring.datasource
开头的,配置都封装到了属性类中。 - 4、给容器中放的所有组件的一些核心参数,都来自于
**xxxProperties**
。**xxxProperties**
都是和配置文件绑定。 - 只需要改配置文件的值,核心组件的底层参数都能修改
4、写业务,全程无需关心各种整合(底层这些整合写好了,而且也生效了)
效果:
-
修改配置文件,修改底层参数
所有场景自动配置好直接使用
可以注入SpringBoot配置好的组件随时使用
属性绑定
将容器中任意组件的属性值和配置文件的配置项的值进行绑定
@ConfigurationProperties
是 Spring Framework 中的一个注解,用于将外部配置(如应用程序的属性文件、环境变量、系统属性等)绑定到 Java 对象上。这样可以方便地管理和使用配置参数
- 给容器中注册组件(@Component、@Bean)
定义属性类
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "app") //prefix配置文件中以什么为前缀的配置项
public class AppProperties {
private String name;
private String version;
// getters and setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
}
- 使用 @ConfigurationProperties 声明组件和配置文件的哪些配置项进行绑定
在配置文件中定义属性 (
application.properties
或application.yml
):
app.name=MyApplication
app.version=1.0.0
YAML 文件
YAML(YAML Ain't Markup Language)是一种人类可读的数据序列化格式,广泛用于配置文件、数据交换和存储。以下是 YAML 文件的详细介绍,包括其基本语法、结构和常见用法。
基本语法
缩进:YAML 使用空格进行缩进,通常使用两个空格。不能使用制表符(Tab)。
键值对:使用冒号(:)分隔键和值。
name: John Doe
age: 30
列表:使用短横线(-)表示列表项。
fruits:
- apple
- banana
- orange
字典:可以嵌套字典。
person:
name: John Doe
age: 30
注释:使用井号(#)添加注释。
# 这是一个注释
name: John Doe # 这是另一个注释
示例 YAML 文件
# 如果yaml和properties 同时出现相同配置,则properties的优先级更高
person:
name: 张三
age: 20
birth-day: 2019/03/04 12:00:00
like: true
child:
name: 李四
age: 18
birth-day: 2019/03/04 12:00:00
text: ["haa", "bbb", "ccc"] #数组
dogs:
- name: 旺财
age: 1
- name: 旺财2
age: 2
- {name: 旺财3, age: 3} #对象
cats:
bluecat:
name: 蓝猫
age: 1
redcat:
name: 红猫
age: 2
blackcat: {name: 黑猫, age: 3} #map
SpringApplication
自定义 banner:类路径添加banner.txt或设置spring.banner.location就可以定制 banner
banner地址: https://www.bootschool.net/ascii
自定义 SpringApplication
new SpringApplication
//自动配置
@SpringBootApplication
public class Springboot01DemoApplication {
public static void main(String[] args) {
//1、创建SpringApplication对象
SpringApplication application = new SpringApplication(Springboot01DemoApplication.class);
//2、启动
application.run(args);
}
}
new SpringApplicationBuilder
//自动配置
@SpringBootApplication
public static void main(String[] args) {
SpringApplicationBuilder builder = new SpringApplicationBuilder();
//链式调用
builder.sources(Springboot01DemoApplication.class)
.run(args);
}
}
日志系统
在 Spring Boot 应用程序中,日志系统是一个重要的组成部分,用于记录应用程序的运行状态、错误信息和调试信息。Spring Boot 默认集成了多种日志框架,并提供了简单的配置方式。
日志系统-日志框架
Spring Boot 默认使用 Logback 作为其日志框架。Logback 是一个功能强大且灵活的日志框架,支持多种日志输出方式。
SpringBoot 默认使用 slf4j + logback
除了 Logback,Spring Boot 还支持其他日志框架。
使用方式
获取一个日志记录器
//格式: 时间 级别 进程id --- 项目名 --- 线程名 --- 当前类名: 日志内容
Logger logger = LoggerFactory.getLogger(LogTest.class);
logger.trace("trace");
logger.debug("debug");
logger.info("info");
logger.warn("warn");
logger.error("error");
注解方式:@Slf4j
@Slf4j
@SpringBootTest
class ApplicationTests {
@Test
void test02() {
//级别:由低到高:ALL -- TRACE -- DEBUG -- INFO -- WARN -- ERROR -- OFF
//越打印,越粗糙; 日志有一个默认级别(INFO);只会打印这个级别之上的所有信息;
log.trace("trace");
log.debug("debug");
log.info("info");
log.warn("warn");
log.error("error");
//日志占位符{}
log.info("{}",值)
}
}
日志系统 - 日志格式
默认输出格式:
时间和日期:毫秒级精度
日志级别:ERROR, WARN, INFO, DEBUG,TRACE.
进程 ID
---: 消息分割符
线程名: 使用[]包含
Logger 名: 通常是产生日志的全类名
消息: 日志记录的内容
注意: logback 没有FATAL级别,对应的是ERROR
日志系统 - 日志级别
由低到高:ALL,TRACE, DEBUG, INFO, WARN, ERROR,FATAL,OFF;
只会打印指定级别及以上级别的日志
- ALL:打印所有日志
- TRACE:追踪框架详细流程日志,一般不使用
- DEBUG:开发调试细节日志
- INFO:关键、感兴趣信息日志
- WARN:警告但不是错误的信息日志,比如:版本过时
- ERROR:业务错误日志,比如出现各种异常
- FATAL:致命错误日志,比如jvm系统崩溃
- OFF:关闭所有日志记录
不指定级别的所有类,都使用 root 指定的级别作为默认级别==>SpringBoot日志默认级别是 INFO
指定日志级别
指定类的日志级别
#指定Application类的中的日志级别为debug
logging.level.com.chs.springboot.Application=debug
指定包下所有的日志级别
#指定mapper包的中所有的日志级别为debug
logging.level.com.chs.mapper.**=debug
指定root 的日志级别
logging.level.root=error
指定web的日志级别
logging.level.web=error
指定sql的日志级别
logging.level.sql=error
日志系统 - 日志分组
在 Spring Boot 2.4 及更高版本中,引入了日志分组的功能,允许您将多个包组合在一起,以便于管理和配置。这种方式可以让您更简单地为多个类或包设置相同的日志级别。
# 定义一个名为 tomcat 的日志组,该组将包含以下三个包
logging.group.tomcat=org.apache.catalina,org.apache.coyote,org.apache.tomcat
# 为 tomcat 日志组设置日志级别
logging.level.tomcat=trace
SpringBoot 预定义两个组
组名 | 范围 |
---|---|
web | org.springframework.core.codec, org.springframework.http, org.springframework.web, org.springframework.boot.actuate.endpoint.web, org.springframework.boot.web.servlet.ServletContextInitializerBeans |
sql | org.springframework.jdbc.core, org.hibernate.SQL, org.jooq.tools.LoggerListener |
日志系统 - 文件输出
SpringBoot 默认只把日志写在控制台,如果想额外记录到文件,可以在application.properties中添加 logging.file.name 或 logging.file.path 配置项。
logging.file.name
功能: 该属性用于指定日志文件的名称。它允许你直接定义日志文件的完整路径和文件名。
# 将日志输出到特定的文件
logging.file.name=/var/log/myapp.log
在这个示例中,所有的日志信息将被输出到
/var/log/myapp.log
文件中。如果该文件路径不存在,Spring Boot 会默认创建该文件。
logging.file.path
功能: 该属性用于指定日志文件的存储目录,而文件名则通过默认命名(spring.log)规则来生成。日志文件的名称通常为应用程序名称,并附加日期。
# 设置日志文件的存储路径
logging.file.path=/var/log/myapp/
如果同时设置了
logging.file.name
和logging.file.path
,Spring Boot 会优先使用logging.file.name
所指定的完整路径和文件名。
日志系统 - 文件归档与滚动切割
归档:每天的日志单独存到一个文档中。
切割:每个文件10MB,超过大小切割成另外一个文件。
配置项 | 描述 |
---|---|
logging.logback.rollingpolicy.file-name-pattern | 日志存档的文件名格式 默认值:${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz |
logging.logback.rollingpolicy.clean-history-on-start | 应用启动时是否清除以前存档;默认值:false |
logging.logback.rollingpolicy.max-file-size | 每个日志文件的最大大小;默认值:10MB |
logging.logback.rollingpolicy.total-size-cap | 日志文件被删除之前,可以容纳的最大大小(默认值:0B)。设置1GB则磁盘存储超过 1GB 日志后就会删除旧日志文件 |
logging.logback.rollingpolicy.max-history | 日志文件保存的最大天数;默认值:7 |
注意:环境兼容性: 在部署到不同环境(如开发、测试、生产)时,可以通过不同的配置文件(如 application-dev.properties
)来设定不同的日志路径和文件名。
- 开发:application-dev.properties
- 测试:application-test.properties
- 生产:application-prod.properties
日志系统 - 自定义配置
在 Spring Boot 中,可以通过自定义配置来满足特定日志记录需求。Spring Boot 默认使用 Logback 作为日志框架,但你可以通过配置文件对其进行详细定制。
日志系统 | 自定义 |
---|---|
Logback | logback-spring.xml / logback.xml |
Log4j2 | log4j2-spring.xml / log4j2.xml |
JDK (Java Util Logging) | logging.properties |
在 src/main/resources
目录下创建一个名为 logback.xml
的文件。这个文件将用于配置 Logback 的行为。
<?xml version="1.0" encoding="UTF-8"?>
<!--
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="false" scanPeriod="60 seconds" debug="false">
<!-- 定义日志的根目录 -->
<property name="LOG_HOME" value="/logs/potato"/>
<!-- 定义日志文件名称 -->
<property name="APP_NAME" value="com.potato.webmarket"></property>
<!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 -->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<!--
日志输出格式:
%d表示日期时间,
%thread表示线程名,
%-5level:级别从左显示5个字符宽度
%logger{50} 表示logger名字最长50个字符,否则按照句点分割。
%msg:日志消息,
%n是换行符
-->
<layout class="ch.qos.logback.classic.PatternLayout">
<!-- <!–开发环境 日志输出格式–>-->
<!-- <springProfile name="dev">-->
<!-- <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} --–> [%thread] -–> %-5level %logger{50} - %msg%n</pattern>-->
<!-- </springProfile>-->
<!-- <!–非开发环境 日志输出格式–>-->
<!-- <springProfile name="!dev">-->
<!-- <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ==== [%thread] ==== %-5level %logger{50} - %msg%n</pattern>-->
<!-- </springProfile>-->
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread]**************** %-5level %logger{50} - %msg%n</pattern>
</layout>
</appender>
<!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
<appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 指定日志文件的名称 -->
<file>${LOG_HOME}/${appName}.log</file>
<!--
当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名
TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。
-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--
滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动
%i:当文件大小超过maxFileSize时,按照i进行文件滚动
-->
<fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<!--
可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,
且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是,
那些为了归档而创建的目录也会被删除。
-->
<MaxHistory>365</MaxHistory>
<!--
当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy
-->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 日志输出格式: -->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss} [ %thread ] ------------------ [ %-5level ] [ %logger{50} : %line ] -
%msg%n
</pattern>
</layout>
</appender>
<!--
logger主要用于存放日志对象,也可以定义日志类型、级别
name:表示匹配的logger类型前缀,也就是包的前半部分
level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERROR
additivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出,
false:表示只用当前logger的appender-ref,true:
表示当前logger的appender-ref和rootLogger的appender-ref都有效
-->
<!-- hibernate logger -->
<logger name="com.potato.marketweb" level="info"/>
<!-- Spring framework logger -->
<logger name="org.springframework" level="info" additivity="false"></logger>
<!--
root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,
要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。
-->
<root level="info">
<appender-ref ref="stdout"/>
<!-- <appender-ref ref="appLogAppender"/>-->
</root>
</configuration>
如果在
src/main/resources
目录下有名为logback.xml
的文件,日志就会按照自定义的类型打印
<configuration>
<!-- 控制台应用器 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} ~~~~~~~~ %msg%n</pattern>
</encoder>
</appender>
<!-- 文件应用器 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/myapp.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} ~~|||~~~ [%thread] %-5level %logger{36} ~~~~~ %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/myapp.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<!-- 日志级别 -->
<root level="info">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
</configuration>
日志系统 – 最佳实践
1、导入任何第三方框架,先排除它的日志包,因为Boot底层控制好了日志
2、修改 application.properties 配置文件,就可以调整日志的所有行为。如果不够,可以编写日志框架自己的配置文件放在类路径下就行,比如logback-spring.xml,log4j2-spring.xml
3、如需对接专业日志系统,也只需要把 logback 记录的日志灌倒 kafka之类的中间件,这和SpringBoot没关系,都是日志框架自己的配置,修改配置文件即可
4、业务中使用slf4j-api记录日志。不要再 sout 了
Profiles环境隔离 - 基础用法
通常我们开发不可能只有一个生产环境,还会有其它的开发,测试,预发布环境等等。为了更好的管理每个环境的配置项,springboot也提供了对应的环境隔离的方法。
1. 标识环境:指定哪些组件、配置在哪个环境生效 =>@Profile 标记组件生效环境
2. 切换环境:这个环境对应的所有组件和配置就应该生效
激活环境方法
- 在application.properties或者yaml文件中配置:spring.profiles.active=环境1,环境2
- 命令行激活:java -jar xxx.jar --spring.profiles.active=环境1,环境2
环境包含
- spring.profiles.include[0]=环境1
- spring.profiles.include[1]=环境2
生效的配置 = 默认环境配置 + 激活的环境 + 包含的环境配置
项目里面这么用
- 基础的配置mybatis、log、xxx:写到包含环境中
- 需要动态切换变化的 db、redis:写到激活的环境中
Profiles环境隔离 - 分组
创建 prod 组,指定包含 db 和 mq 配置
- spring.profiles.group.prod[0]=db
- spring.profiles.group.prod[1]=mq
使用 --spring.profiles.active=prod ,激活prod,db,mq配置文件
spring.profiles.group.prod[0]=db
spring.profiles.group.prod[1]=mq
spring.profiles.active=prod
Profiles环境隔离 - 配置文件
application-{profile}.properties 可以作为指定环境的配置文件
激活这个环境,配置就会生效。最终生效的所有配置是
- application.properties:主配置文件,任意时候都生效
- application-{profile}.properties:指定环境配置文件,激活指定环境生效
profile优先级 > application
spring.profiles.active=dev #设置环境为dev环境
生效的配置文件有:主配置文件和dev环境的配置文件
外部化配置
在 Spring Boot 中,外部化配置允许你将应用程序的配置信息与代码分离,使得在不同环境(如开发、测试、生产)中能方便地修改配置而无需重新编译应用程序。
外部配置优先于内部配置
可以在打包好后的jar包同级目录创建application.properties;
可以在打包好后的jar包同级目录创建config目录,在目录里面创建application.properties;
可以在打包好后的jar包同级目录创建config目录在config目录里面再创建一个目录,在这个目录里面创建application.properties;
命令行>config/*/application.properties;>config/application.properties;>application.properties;
单元测试 - 测试注解
@Test :表示方法是测试方法。
@ParameterizedTest :表示方法是参数化测试,下方会有详细介绍
@RepeatedTest :表示方法可重复执行,下方会有详细介绍
@DisplayName :为测试类或者测试方法设置展示名称
@BeforeEach :表示在每个单元测试之前执行
@AfterEach :表示在每个单元测试之后执行
@BeforeAll :表示在所有单元测试之前执行
@AfterAll :表示在所有单元测试之后执行
@Tag :表示单元测试类别,类似于JUnit4中的@Categories
@Disabled :表示测试类或测试方法不执行,类似于JUnit4中的@Ignore
@Timeout :表示测试方法运行如果超过了指定时间将会返回错误
@ExtendWith :为测试类或测试方法提供扩展类引用
单元测试 - 断言机制
方法 | 说明 |
---|---|
assertEquals | 判断两个对象或两个原始类型是否相等 |
assertNotEquals | 判断两个对象或两个原始类型是否不相等 |
assertSame | 判断两个对象引用是否指向同一个对象 |
assertNotSame | 判断两个对象引用是否指向不同的对象 |
assertTrue | 判断给定的布尔值是否为 true |
assertFalse | 判断给定的布尔值是否为 false |
assertNull | 判断给定的对象引用是否为 null |
assertNotNull | 判断给定的对象引用是否不为 null |
assertArrayEquals | 数组断言 |
assertAll | 组合断言 |
assertThrows | 异常断言 |
assertTimeout | 超时断言 |
fail | 快速失败 |
断言:判断字符串是否等于hello
@Slf4j
@SpringBootTest
class ApplicationTests {
@Test
public void test01(){
String str = "hello";
Assertions.assertEquals("hello",str); //断言:判断字符串是否等于hellollo
}
}
可观测性
可观测性(Observability)是指应用程序在生产环境中运行时,能够收集和分析其内部状态与行为的能力。它使得开发和运维团队能够有效监控应用性能,诊断问题,并在出现异常时采取措施。
可观测性的核心组成部分
- 日志(Logging):
- 日志是记录应用程序运行情况的重要手段,通常包括信息、警告、错误等各种级别的日志。
- 日志应详细且结构化,以便于后续分析和查询。
- 指标(Metrics):
- 指标是应用程序量化性能和健康状况的数值,例如请求处理时间、系统负载、内存使用情况等。
- 指标通常以时间序列的方式存储,并可以通过可视化工具(如Grafana、Prometheus)进行展示。
- 追踪(Tracing):
- 追踪用于分析请求在系统中流动的路径,从而了解各个组件之间的调用关系和延迟。
- 分布式追踪工具(如OpenTelemetry、Jaeger)能够帮助开发者跟踪跨多个服务的请求处理流程。
SpringBoot 提供了 actuator 模块,可以快速暴露应用的所有指标
导入: spring-boot-starter-actuator
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
配置配置文件
management.endpoints.web.exposure.include=*
可观测性 - Endpoints
端点名 | 描述 |
---|---|
auditevents | 暴露当前应用程序的审核事件信息。需要一个AuditEventRepository组件 |
beans | 显示应用程序中所有Spring Bean的完整列表 |
caches | 暴露可用的缓存 |
conditions | 显示自动配置的所有条件信息,包括匹配或不匹配的原因 |
configprops | 显示所有@ConfigurationProperties |
env | 暴露Spring的属性ConfigurableEnvironment |
flyway | 显示已应用的所有Flyway数据库迁移。需要一个或多个Flyway组件。 |
health | 显示应用程序运行状况信息 |
httptrace | 显示HTTP跟踪信息(默认情况下,最近100个HTTP请求-响应)。需要一个HttpTraceRepository组件 |
info | 显示应用程序信息 |
integrationgraph | 显示Spring integrationgraph 。需要依赖spring-integration-core |
loggers | 显示和修改应用程序中日志的配置 |
liquibase | 显示已应用的所有Liquibase数据库迁移。需要一个或多个Liquibase组件。 |
metrics | 显示当前应用程序的“指标”信息 |
mappings | 显示所有@RequestMapping路径列表 |
scheduledtasks | 显示应用程序中的计划任务 |
sessions | 允许从Spring Session支持的会话存储中检索和删除用户会话。需要使用Spring Session的基于Servlet的Web应用程序 |
shutdown | 使应用程序正常关闭。默认禁用 |
startup | 显示由ApplicationStartup收集的启动步骤数据。需要使用SpringApplication进行配置BufferingApplicationStartup |
threaddump | 执行线程转储 |
heapdump | 返回hprof堆转储文件 |
jolokia | 通过HTTP暴露JMX bean(需要引入Jolokia,不适用于WebFlux)。需要引入依赖jolokia-core |
logfile | 返回日志文件的内容(如果已设置logging.file.name或logging.file.path属性)。支持使用HTTPRange标头来检索部分日志文件的内容 |
prometheus | 以Prometheus服务器可以抓取的格式公开指标。需要依赖micrometer-registry-prometheus |
Spring-Boot生命周期监听
SpringApplicationRunListener
SpringApplicationRunListener
是 Spring 框架中的一个接口,它是 Spring Boot 的启动过程中的一个重要扩展点。通过实现这个接口,开发人员可以在 Spring Boot 应用启动的不同阶段执行特定的逻辑。这对于需要在应用启动之前或期间进行某些初始化工作、环境配置、预处理等需求的场景非常有用。
pringApplicationRunListener
接口定义了一些方法,主要包括:
starting:当 Spring 应用上下文(SpringApplication
)开始启动时调用。
environmentPrepared:在环境(Environment
)准备好之后被调用,允许开发者在应用运行之前对环境进行调整。
contextPrepared:当应用上下文准备好,但尚未刷新时调用。这是一个可以进行上下文配置和初始化的机会。
contextLoaded:当应用上下文加载后(即上下文已刷新完成时)调用。这时已经可以访问上下文中的各种 Bean。
finished:当应用启动完成并且上下文被完全加载和初始化后调用。这通常是释放资源或执行最后的清理工作的位置。
使用示例(全阶段 )
实现接口SpringApplicationRunListener
并在构造函数中处理 SpringApplication
和 String[]
类型的参数。
实现方法:重写需要的方法以添加自定义逻辑。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
public class CustomSpringApplicationRunListener implements SpringApplicationRunListener {
public CustomSpringApplicationRunListener(SpringApplication application, String[] args) {
// 构造函数,进行初始化
}
@Override
public void starting() {
System.out.println("Application is starting...");
}
@Override
public void environmentPrepared(SpringApplication application, ConfigurableEnvironment environment) {
System.out.println("Environment is prepared.");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("Application context is prepared.");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("Application context is loaded.");
}
@Override
public void finished(ConfigurableApplicationContext context, SpringApplicationExitCodeGenerator exitCodeGenerator) {
System.out.println("Application has finished running.");
}
}
注册 Listener:在 src/main/resources/META-INF/spring.factories
文件中添加如下内容以注册自定义的监听器:
org.springframework.boot.SpringApplicationRunListener=\
com.example.CustomSpringApplicationRunListener
生命周期监听器
监听器 | 感知阶段 | 配置方式 |
---|---|---|
BootstrapRegistryInitializer | 特定阶段:引导初始化 | 1、META-INF/spring.factories 2、application.addBootstrapRegistryInitializer() |
ApplicationContextInitializer | 特定阶段:ioc容器初始化 | 1、META-INF/spring.factories 2、application.addInitializers() |
ApplicationListener | 全阶段 | 1、META-INF/spring.factories 2、SpringApplication.addListeners(…) 3、@Bean 或 @EventListener |
SpringApplicationRunListener | 全阶段 | META-INF/spring.factories |
ApplicationRunner | 特定阶段:感知应用就绪 | @Bean |
CommandLineRunner | 特定阶段:感知应用就绪 | @Bean |
最佳实践:
1、应用启动后做事:ApplicationRunner、CommandLineRunner
2、事件驱动开发:ApplicationListener
CommandLineRunner(感知应用就绪)
CommandLineRunner
是 Spring Boot 提供的一个功能接口,可以在 Spring Boot 应用程序启动后执行特定的逻辑。它允许开发者在应用启动时根据命令行参数执行代码,通常用于执行初始化任务、加载数据或启动某些服务。
使用方法
实现接口:创建一个类并实现 CommandLineRunner
接口。
重写 run 方法:在 run
方法中编写你希望在应用启动时执行的逻辑。
注册为 Spring Bean:将该类声明为 Spring Bean (例如使用 @Component
注解),Spring 会自动在应用启动时调用它的 run
方法。
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("Application started with command-line arguments: " + String.join(", ", args));
// 这里可以执行其他的初始化逻辑,例如存储数据到数据库
}
}
Spring-Boot生命周期事件
Spring Boot生命周期事件是指在Spring Boot应用程序的不同阶段(例如启动、运行和停止)中,Spring框架触发的特定事件。
主要生命周期事件
ApplicationStartedEvent:应用程序启动后触发的事件。通常在应用上下文被创建后但尚未刷新时发生。
ApplicationEnvironmentPreparedEvent:应用环境准备好后触发。可以在此事件中根据需要修改环境属性。
ApplicationContextInitializedEvent:应用上下文初始化后触发。所有的bean定义已经加载,但上下文还没有刷新。
ApplicationPreparedEvent:应用准备好后触发。此时应用上下文已经准备好,但尚未刷新。
ApplicationStartedEvent:应用程序已完全启动并且所有的beans都已经实例化的事件。
ApplicationReadyEvent:应用程序已经完全启动,且上下文已经完全刷新,所有的beans也已经准备好。此时可以进行处理请求等操作。
ApplicationFailedEvent:应用启动失败时触发的事件。可以在此事件中进行错误处理或记录。
ApplicationReadyEvent:应用程序已启动并准备接受请求后触发的事件。这是一个很好的时机来启动那些依赖于应用程序的功能。
ApplicationContextClosedEvent:当应用程序上下文关闭时触发的事件。该事件在所有的beans都被销毁后触发。
事件驱动开发
定义事件:
- 任意事件:任意类可以作为事件类,建议命名 xxxEvent
@Data //定义一个事件
public class SendSuccessEvent {
private String message;
public SendSuccessEvent(String message) {
this.message = message;
}
}
- 系统事件:继承 ApplicationEvent的类的实例
import org.springframework.context.ApplicationEvent;
public class CustomEvent extends ApplicationEvent {
private String message;
public CustomEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
}
事件发布:
- 组件实现 ApplicationEventPublisherAware
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
@Component
public class UserService implements ApplicationEventPublisherAware {
private ApplicationEventPublisher eventPublisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.eventPublisher = applicationEventPublisher;
}
public void registerUser(String message) {
// 发布事件
UserRegisteredEvent event = new UserRegisteredEvent(this, message);
eventPublisher.publishEvent(event);
}
}
- 自动注入 ApplicationEventPublisher
@Slf4j
@RestController
public class UserController {
@Autowired
ApplicationEventPublisher publisher;
//同步阻塞式;
//事件/消息驱动;
@PutMapping("/send")
public String login(String message){
//做事;同步调用
SendSuccessEvent event = new SendSuccessEvent(message);
//1.发送事件
publisher.publishEvent(event);
// 2.发布事件
UserRegisteredEvent event = new UserRegisteredEvent(this, message);
eventPxublisher.publishEvent(event);
return "发送成功";
}
}
监听事件:
通过实现 ApplicationListener
接口,或者使用 @EventListener
注解的方式。
组件 + 方法标注@EventListener
@Slf4j
@Service
public class UserPointsService {
@Async //异步
@EventListener(SendSuccessEvent.class)
public void listen(SendSuccessEvent event){
log.info("监听到 SendSuccessEvent 事件");
givePoints(event.getmessage());
}
public void givePoints(String message) {
log.info(message);
}
}
通过实现 ApplicationListener
接口
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class UserRegisteredListener implements ApplicationListener<UserRegisteredEvent> {
@Override
public void onApplicationEvent(UserRegisteredEvent event) {
//event 传递的消息
//事件处理逻辑
}
}
异步事件处理:
结合 Spring 的异步处理机制,可以实现事件的异步发布和处理,提高应用的响应能力。
@Async //异步
自动配置原理
入门理解
应用关注的三大核心:场景、配置、组件
自动配置流程细节梳理:
1、导入starter-web
:导入了web开发场景
- 1、场景启动器导入了相关场景的所有依赖:
starter-json
、starter-tomcat
、springmvc
- 2、每个场景启动器都引入了一个
spring-boot-starter
,核心场景启动器。 - 3、核心场景启动器引入了
spring-boot-autoconfigure
包。 - 4、
spring-boot-autoconfigure
里面囊括了所有场景的所有配置。 - 5、只要这个包下的所有类都能生效,那么相当于SpringBoot官方写好的整合功能就生效了。
- 6、SpringBoot默认却扫描不到
spring-boot-autoconfigure
下写好的所有配置类。(这些配置类给我们做了整合操作),默认只扫描主程序所在的包。
2、主程序:@SpringBootApplication
-
1、
@SpringBootApplication
由三个注解组成@SpringBootConfiguration
、@EnableAutoConfiguration
、@ComponentScan
-
2、SpringBoot默认只能扫描自己主程序所在的包及其下面的子包,扫描不到
spring-boot-autoconfigure
包中官方写好的配置类 -
3、
**@EnableAutoConfiguration**
:SpringBoot 开启自动配置的核心。 -
-
- 是由
@Import(AutoConfigurationImportSelector.class)
提供功能:批量给容器中导入组件。
- 是由
-
- SpringBoot启动会默认加载 152个配置类。
-
- 这152个配置类来自于
spring-boot-autoconfigure
下META-INF/spring/**org.springframework.boot.autoconfigure.AutoConfiguration**.imports
文件指定的
- 这152个配置类来自于
- 项目启动的时候利用 @Import 批量导入组件机制把
autoconfigure
包下的152xxxxAutoConfiguration
类导入进来(自动配置类) - 虽然导入了
152
个自动配置类
-
-
4、按需生效:
-
- 并不是这
152
个自动配置类都能生效 - 每一个自动配置类,都有条件注解
@ConditionalOnxxx
,只有条件成立,才能生效
- 并不是这
3、**xxxxAutoConfiguration**
自动配置类
- 1、给容器中使用@Bean 放一堆组件。
- 2、每个自动配置类都可能有这个注解
@EnableConfigurationProperties(**ServerProperties**.class)
,用来把配置文件中配的指定前缀的属性值封装到xxxProperties
属性类中 - 3、以DataSourceAutoConfiguration为例:所有配置都是以
spring.datasource
开头的,配置都封装到了属性类中。 - 4、给容器中放的所有组件的一些核心参数,都来自于
**xxxProperties**
。**xxxProperties**
都是和配置文件绑定。 - 只需要改配置文件的值,核心组件的底层参数都能修改
4、写业务,全程无需关心各种整合(底层这些整合写好了,而且也生效了)
核心流程总结:
- 导入
starter
,就会导入autoconfigure
包。 - autoconfigure 包里面 有一个文件
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
,里面指定的所有启动要加载的自动配置类 @EnableAutoConfiguration
会自动的把上面文件里面写的所有自动配置类都导入进来。xxxAutoConfiguration 是有条件注解进行按需加载- xxxAutoConfiguration 给容器中导入一堆组件,组件都是从 xxxProperties 中提取属性值
- xxxProperties 又是和配置文件进行了绑定
效果:
修改配置文件,修改底层参数
所有场景自动配置好直接使用
可以注入SpringBoot配置好的组件随时使用
SPI机制
- Java中的SPI(Service Provider Interface)是一种软件设计模式,用于在应用程序中动态地发现和加载组件。SPI的思想是,定义一个接口或抽象类,然后通过在classpath中定义实现该接口的类来实现对组件的动态发现和加载。
- SPI的主要目的是解决在应用程序中使用可插拔组件的问题。例如,一个应用程序可能需要使用不同的日志框架或数据库连接池,但是这些组件的选择可能取决于运行时的条件。通过使用SPI,应用程序可以在运行时发现并加载适当的组件,而无需在代码中硬编码这些组件的实现类。
- 在Java中,SPI的实现方式是通过在
META-INF/services
目录下创建一个以服务接口全限定名为名字的文件,文件中包含实现该服务接口的类的全限定名。当应用程序启动时,Java的SPI机制会自动扫描classpath中的这些文件,并根据文件中指定的类名来加载实现类。 - 通过使用SPI,应用程序可以实现更灵活、可扩展的架构,同时也可以避免硬编码依赖关系和增加代码的可维护性。
在SpringBoot中也有SPI,META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
在resource文件中创建META-INF/spring目录并创建
org.springframework.boot.autoconfigure.AutoConfiguration.imports
在文件中写入需要被自动加载全类名=>Java的SPI机制会自动扫描classpath中的这些文件,并根据文件中指定的类名来加载实现类。
com.chs.robot.starter.RobotAutoConfiguration
功能开关
-
自动配置:全部都配置好,什么都不用管。 自动批量导入
-
- 项目一启动,spi文件中指定的所有都加载。
-
@EnableXxxx
:手动控制哪些功能的开启; 手动导入。 -
- 开启xxx功能
- 都是利用 @Import 把此功能要用的组件导入进去
SpringBoot完整项目启动流程
生命周期启动加载流程
自定义自动配置类(starter)
- 场景:抽取聊天机器人场景,它可以打招呼。
- 效果:任何项目导入此
starter
都具有打招呼功能,并且问候语中的人名需要可以在配置文件中修改
创建
自定义starter
项目,引入spring-boot-starter
基础依赖,删除自己的启动类
<!--
自定义starter ==>项目名称:robot-spring-boot-starter
1、所有starter都需要依赖这个基础starter;spring-boot-starter
2、把所有要抽取的业务组件都抽取到这个starter中;
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
编写模块功能,引入模块所有需要的依赖。
//Controller模块
@RestController
public class RobotController {
@Autowired
RobotService robotService;
@GetMapping("/robot/hello")
public String sayHello(){
String msg = robotService.sayHello();
return msg;
}
}
//Service模块
@Service
public class RobotServiceImpl implements RobotService {
@Autowired
RobotProperties robotProperties;
@Override
public String sayHello() {
return "我是机器人【"+robotProperties.getName()+"】,使用底层大模型:【"+robotProperties.getModel()+"】;我们开始聊天吧";
}
}
//配置类模块
@Component
@ConfigurationProperties(prefix = "robot")
@Data
public class RobotProperties {
private String name;
private String model;
}
编写
xxxAutoConfiguration
自动配置类,帮其他项目导入这个模块需要的所有组件
@EnableConfigurationProperties(RobotProperties.class) //开启自动配置类和配置文件的绑定,并把配置类放到容器中
@Configuration //把这个场景要用的所有组件导入到容器中
public class RobotAutoConfiguration {
@Bean
public RobotController robotController() {
return new RobotController();
}
@Bean
public RobotService robotService() {
return new RobotServiceImpl();
}
}
第一层抽取:编写一个自动配置类,别人导入我的starter,
无需关心需要给容器中导入哪些组件,只需要导入自动配置类,
自动配置类帮你给容器中导入所有这个场景要用的组件
@import(RobotAutoConfiguration.class)
第二层抽取:只需要标注功能开关注解。@EnableRobot
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(RobotAutoConfiguration.class) //导入bean
public @interface EnableRobot {
}
第三层抽取:只需要导入starter,所有功能就绪
在
resources\META-INF\spring\
中创建org.springframework.boot.autoconfigure.AutoConfiguration.imports
中写入:自动配置类的全类名:指定的启动要加载的自动配置类
com.chs.robot.starter.RobotAutoConfiguration
使用:导依赖就能直接使用
<dependency>
<groupId>com.chs</groupId>
<artifactId>robot-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
通过配置文件修改传递的参数
robot.name="坤坤AI"
robot.model=chatgpt250
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南