Spring Boot 应用(官网文档解读)
Spring Boot 启动方式
SpringApplication.run(MyApplication.class, args);
Spring Boot 故障分析器
在Spring Boot 项目启动发生错误的时候,我们通常可以看到上面的内容,即 APPLICATION FAILED TO START,以及后面的错误描述。这个功能是通过众多的FailureAnalyzer 故障分析器beans 实现来处理的。我们可以在Spring Boot 中的spring.factories 配置文件中看到 Failure Analyzers bean 的具体实现类。
Spring Boot 自定义故障分析器
-
创建一个自定义错误
package person.wend.springbootlearnexample2.failureanalyzer;import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
import org.springframework.boot.diagnostics.FailureAnalysis;public class CustomFailureAnalyzer extends AbstractFailureAnalyzer<CustomStartupException> {@Overrideprotected FailureAnalysis analyze(Throwable rootFailure, CustomStartupException cause) {// 错误描述String description = "自定义启动错误:" + cause.getMessage();// 操作建议String action = "请检查相关配置或联系系统管理员。";return new FailureAnalysis(description, action, cause);}
}
-
创建一个自定义故障分析器类
package person.wend.springbootlearnexample2.failureanalyzer;import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
import org.springframework.boot.diagnostics.FailureAnalysis;public class CustomFailureAnalyzer extends AbstractFailureAnalyzer<CustomStartupException> {@Overrideprotected FailureAnalysis analyze(Throwable rootFailure, CustomStartupException cause) {// 错误描述String description = "自定义启动错误:" + cause.getMessage();// 操作建议String action = "请检查相关配置或联系系统管理员。";return new FailureAnalysis(description, action, cause);}
}
-
在META-INF\spring.factories 配置文件中注册该bean
org.springframework.boot.diagnostics.FailureAnalyzer=\ person.wend.springbootlearnexample2.failureanalyzer.CustomFailureAnalyzer
- 启动报错示例
延迟初始化
SpringApplication允许应用程序延迟初始化。启用延迟初始化后,Bean 将在需要时创建,而不是在应用程序启动期间创建。因此,启用延迟初始化可以减少应用程序启动所需的时间。在 Web 应用程序中,启用延迟初始化将导致许多与 Web 相关的 Bean 在收到 HTTP 请求之前不会被初始化。
延迟初始化的缺点是,它会延迟发现应用程序的问题。如果延迟初始化配置错误的 bean,则启动期间将不再发生故障,并且问题仅在初始化 bean 时才会显现出来。还必须注意确保 JVM 具有足够的内存来容纳应用程序的所有 bean,而不仅仅是那些在启动期间初始化的 bean。出于这些原因,默认情况下不启用延迟初始化,建议在启用延迟初始化之前对 JVM 的堆大小进行微调。
实现延迟初始化的方式
-
配置文件
spring: main: lazy-initialization: true
-
启动项目时配置
public static void main(String[] args) {SpringApplication springApplication = new SpringApplication(SpringBootLearnExample2Application.class);springApplication.setLazyInitialization(true);}
-
使用注解@Lazy(true)
自定义横幅
在Spring Boot 中,我们可以使用banner.txt定义自定义横幅,一般将banner.txt 放在resource文件夹即可。以下是关于自定义横幅的属性列表:
-
spring.banner.location:定义banner.txt 的文件位置
-
spring.banner.charset:定义banner.txt 的编码类型
-
banner.txt可以使用Environment 配置中的任何属性,以及支持一些默认的属性
-
变量 描述 ${application.version}
应用程序版本号 ${application.formatted-version}
应用程序格式化的版本号 ${spring-boot.version}
您正在使用的 Spring Boot 版本。例如
3.4.2
。${spring-boot.formatted-version}
您正在使用的 Spring Boot 格式化的版本号
${Ansi.NAME}
(或者${AnsiColor.NAME}
,${AnsiBackground.NAME}
,${AnsiStyle.NAME}
)AnsiPropertySource
类是 Spring Boot 框架里用于处理 ANSI(美国国家标准化组织)转义序列相关属性源的类,主要在处理控制台输出样式方面发挥作用。${application.title}
应用程序标题
编程方式实现横幅
- 启动类增加Banner配置
springApplication.setBanner(…)
- 自定义Banner 类
package person.wend.springbootlearnexample.config;import org.springframework.boot.Banner;
import org.springframework.core.env.Environment;import java.io.PrintStream;public class CustomBanner implements Banner {@Overridepublic void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {StringBuilder banner = new StringBuilder();banner.append("==================================================\n");banner.append("* *\n");banner.append("* Welcome to My Custom App *\n");banner.append("* *\n");banner.append("==================================================\n");out.println(banner.toString());}
}
-
实现效果
关闭横幅
springApplication.setBannerMode(Banner.Mode.OFF);
SpringApplicationBuilder
我们可以使用 SpringApplicationBuilder 来构建SpringBoot 的启动类。
new SpringApplicationBuilder().sources(Parent.class).child(Application.class).bannerMode(Banner.Mode.OFF).run(args);
-
sources(Parent.class)
:指定父上下文的主配置类为Parent.class
,Spring Boot 会根据这个类来创建和初始化父应用上下文。 -
child(Application.class)
:创建一个子应用上下文,并将Application.class
作为子上下文的主配置类。子上下文会继承父上下文的 Bean 定义,并且可以有自己独立的配置。 -
bannerMode(Banner.Mode.OFF)
:设置启动时不显示 Spring Boot 的 Banner。 -
run(args)
:启动应用,同时启动父上下文和子上下文。
Spring Boot 可用性状态概述
Spring Boot 支持 “存活”(Liveness)和 “就绪”(Readiness)两种可用性状态。当应用部署在如 Kubernetes 这样的平台上时,可通过这些状态向平台提供自身的可用性信息。若使用 Spring Boot 的 “actuator” 支持,这些状态会作为健康端点组暴露出来,也可通过注入 ApplicationAvailability
接口到自定义 Bean 中获取可用性状态。
存活状态(Liveness State)
-
含义:表明应用的内部状态是否允许其正常工作,或者在当前出现故障时能否自行恢复。若存活状态不佳,意味着应用处于无法恢复的状态,平台基础设施应重启该应用。
-
判断依据:通常不应基于外部检查(如健康检查)来确定存活状态,因为外部系统(如数据库、Web API、外部缓存)故障可能会导致平台大规模重启和级联故障。Spring Boot 应用的内部状态主要由
Spring ApplicationContext
表示,一旦应用上下文成功刷新,就认为应用处于有效状态,即存活。
就绪状态(Readiness State)
-
含义:表示应用是否准备好处理流量。若就绪状态不佳,告知平台目前不应将流量路由到该应用。这通常发生在应用启动期间(如
CommandLineRunner
和ApplicationRunner
组件正在处理时),或者应用认为自身过于繁忙无法处理额外流量时。 -
判断依据:一旦调用了应用和命令行运行器,就认为应用已就绪。启动期间预期运行的任务应通过
CommandLineRunner
和ApplicationRunner
组件执行,而不是使用@PostConstruct
等 Spring 组件生命周期回调。
使用示例
- 添加 spring-boot-actuator依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- 创建一个 Bean 来注入
ApplicationAvailability
接口,并检查存活和就绪状态:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.availability.ApplicationAvailability;
import org.springframework.boot.availability.LivenessState;
import org.springframework.boot.availability.ReadinessState;
import org.springframework.stereotype.Component;@Component
public class AvailabilityChecker {private final ApplicationAvailability applicationAvailability;@Autowiredpublic AvailabilityChecker(ApplicationAvailability applicationAvailability) {this.applicationAvailability = applicationAvailability;}public void checkAvailability() {LivenessState livenessState = applicationAvailability.getLivenessState();ReadinessState readinessState = applicationAvailability.getReadinessState();System.out.println("Liveness State: " + livenessState);System.out.println("Readiness State: " + readinessState);}
}
- 在主类中调用检查方法
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class MyApplication implements CommandLineRunner {@Autowiredprivate AvailabilityChecker availabilityChecker;public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}@Overridepublic void run(String... args) throws Exception {availabilityChecker.checkAvailability();}
}
管理应用程序可用性状态
-
应用程序组件可以随时通过注入接口ApplicationAvailability并调用其方法来检索当前可用性状态。更常见的是,应用程序希望监听状态更新或更新应用程序的状态。
-
Spring Boot通过 Actuator Health Endpoints 为 Kubernetes 提供了“活跃度”和“就绪度”的 HTTP 探测。
-
例如,我们可以将应用程序的“就绪”状态导出到文件,以便 Kubernetes“exec Probe”可以查看此文件:
@Component
public class MyReadinessStateExporter {@EventListenerpublic void onStateChange(AvailabilityChangeEvent<ReadinessState> event) {switch (event.getState()) {case ACCEPTING_TRAFFIC -> {// create file /tmp/healthy}case REFUSING_TRAFFIC -> {// remove file /tmp/healthy}}}}
-
当应用程序崩溃且无法恢复时,我们还可以更新应用程序的状态:
@Component
public class MyLocalCacheVerifier {private final ApplicationEventPublisher eventPublisher;public MyLocalCacheVerifier(ApplicationEventPublisher eventPublisher) {this.eventPublisher = eventPublisher;}public void checkLocalCache() {try {// ...}catch (CacheCompletelyBrokenException ex) {AvailabilityChangeEvent.publish(this.eventPublisher, ex, LivenessState.BROKEN);}}}
应用程序事件监听器
-
在Spring Boot项目中,我们一般可以使用ContextRefreshedEvent来监听一个事件。
ContextRefreshedEvent
是 Spring 框架中的一个事件,当ApplicationContext
被初始化或者刷新时会发布该事件。 -
我们可以使用SpringApplication.addListeners(…)或SpringApplicationBuilder.listeners(…)注册一个监听器。
-
我们也可以通过在 META-INF/spring.factories添加监听器的方式注册一个监听器的Bean。
示例代码
package person.wend.springbootlearnexample2.event;import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;@Component
public class ContextRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {// 获取事件源,即 ApplicationContextvar applicationContext = event.getApplicationContext();// 可以在这里执行一些初始化操作,比如获取 Bean 等System.out.println("ContextRefreshedEvent 事件被触发,ApplicationContext 已刷新。");System.out.println("当前 ApplicationContext 中的 Bean 数量: " + applicationContext.getBeanDefinitionCount());}
}
Spring Boot 事件触发顺序
Spring Boot 应用在运行过程中,各类事件按照以下顺序依次执行:
-
ApplicationStartingEvent:应用启动时触发,此时仅完成监听器和初始化器的注册,其他处理工作尚未开展。
-
ApplicationEnvironmentPreparedEvent:当明确了应用上下文要使用的环境配置,但上下文还未创建时触发该事件。
-
ApplicationContextInitializedEvent:应用上下文准备完毕,且上下文初始化器完成调用,但 Bean 定义尚未加载时触发此事件。
-
ApplicationPreparedEvent:Bean 定义加载完成后,上下文刷新操作启动之前触发该事件。
-
ApplicationStartedEvent:上下文刷新完成,但应用程序和命令行运行器还未调用时触发此事件。
-
AvailabilityChangeEvent(LivenessState.CORRECT):在
ApplicationStartedEvent
之后立即触发,表明应用处于存活状态。 -
ApplicationReadyEvent:应用程序和命令行运行器调用完成后触发此事件。
-
AvailabilityChangeEvent(ReadinessState.ACCEPTING_TRAFFIC):在
ApplicationReadyEvent
之后立即触发,意味着应用已准备好处理请求。 -
ApplicationFailedEvent:若应用在启动过程中出现异常,则触发该事件。
上面的列表仅包括绑定到SpringApplication的SpringApplicationEvents。除此之外,以下事件也在ApplicationPreparedEvent之后和ApplicationStartedEvent之前发布:
-
WebServer就绪后发送WebServerInitializedEvent。ServletWebServerInitializedEvent和ReactiveWebServerIninitializedEvent分别是servlet和反应式变体。
-
刷新ApplicationContext时发送ContextRefreshedEvent。
Web环境
SpringApplication试图代表您创建正确类型的ApplicationContext。用于确定WebApplicationType的算法如下:
-
如果存在Spring MVC,则使用AnnotationConfigServletWebServerApplicationContext
-
如果Spring MVC不存在,并且Spring WebFlux存在,则使用AnnotationConfigReactiveWebServerApplicationContext
-
否则,将使用AnnotationConfigApplicationContext
这意味着,如果您在同一应用程序中使用SpringMVC和SpringWebFlux中的新WebClient,则默认情况下将使用Spring MVC。
-
您可以通过调用setWebApplicationType(WebApplicationType)轻松地覆盖它。
-
还可以完全控制通过调用setApplicationContextFactory(…)修改使用的ApplicationContext类型。
ApplicationArguments 访问应用程序命令参数
ApplicationArguments
是 Spring Boot 中的一个接口,用于在应用启动时访问传递给应用的命令行参数。以下从功能、使用场景、使用方式等方面详细介绍其作用。
主要功能
-
解析命令行参数:
ApplicationArguments
接口可以将传递给 Spring Boot 应用的命令行参数解析为选项参数(以--
开头的参数)和非选项参数,方便开发者对不同类型的参数进行处理。 -
提供参数访问方法:该接口提供了一系列方法,用于获取选项参数的名称、值,以及非选项参数的列表,开发者可以根据需要灵活使用这些方法。
使用场景
-
配置应用行为:通过命令行参数可以动态配置应用的行为,例如指定应用的运行模式(开发模式、生产模式)、数据库连接信息等。
-
传递自定义参数:在应用启动时传递一些自定义的参数,用于执行特定的任务或进行初始化操作。
-
测试和调试:在测试和调试过程中,可以通过命令行参数传递不同的配置,方便对应用进行测试和排查问题。
示例代码
import org.springframework.boot.ApplicationArguments;
import org.springframework.stereotype.Component;@Component
public class MyCommandLineArgsHandler {public MyCommandLineArgsHandler(ApplicationArguments args) {// 获取所有选项参数的名称System.out.println("选项参数名称: " + args.getOptionNames());// 检查是否包含某个选项参数if (args.containsOption("debug")) {System.out.println("应用以调试模式启动。");}// 获取某个选项参数的值if (args.containsOption("port")) {System.out.println("指定的端口号: " + args.getOptionValues("port"));}// 获取非选项参数的列表System.out.println("非选项参数: " + args.getNonOptionArgs());}
}
ACommandLineRunner
CommandLineRunner
接口位于 org.springframework.boot
包下,是一个函数式接口,只包含一个抽象方法 run
,定义如下:
package org.springframework.boot;@FunctionalInterface
public interface CommandLineRunner {void run(String... args) throws Exception;
}
run
方法接收一个 String
数组参数 args
,这个参数包含了应用程序启动时传递的命令行参数。该方法会在 Spring 应用上下文完全初始化之后被调用。
- 使用示例:
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;@Component
public class MyCommandLineRunner implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {System.out.println("应用启动后执行的代码逻辑...");for (String arg : args) {System.out.println("命令行参数: " + arg);}}
}
ApplicationRunner
ApplicationRunner
接口同样位于 org.springframework.boot
包下,也是一个函数式接口,其抽象方法 run
接收一个 ApplicationArguments
类型的参数,定义如下:
package org.springframework.boot;import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;@FunctionalInterface
public interface ApplicationRunner extends Ordered {void run(ApplicationArguments args) throws Exception;
}
ApplicationArguments
是一个封装了命令行参数的对象,它提供了更方便的方法来处理选项参数和非选项参数。
- 使用示例
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;@Component
public class MyApplicationRunner implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {System.out.println("应用启动后执行的代码逻辑...");System.out.println("选项参数: " + args.getOptionNames());System.out.println("非选项参数: " + args.getNonOptionArgs());}
}
使用场景
-
数据初始化:在应用启动后,你可能需要初始化一些数据到数据库或者缓存中,比如加载配置文件、初始化字典数据等。
-
资源预热:提前加载一些常用的资源,以减少后续请求的响应时间,例如预热缓存、初始化连接池等。
-
启动脚本:执行一些启动时的脚本任务,如检查系统环境、创建必要的文件目录等。
两者的区别
-
参数类型:
CommandLineRunner
的run
方法接收的是一个String
数组,需要开发者自己解析命令行参数;而ApplicationRunner
的run
方法接收的是一个ApplicationArguments
对象,它对命令行参数进行了封装,提供了更方便的方法来处理选项参数和非选项参数。 -
使用场景:如果只是简单地处理命令行参数,
CommandLineRunner
就足够了;如果需要更复杂的参数处理,如区分选项参数和非选项参数,ApplicationRunner
会更合适。
@Order 控制顺序执行
如果程序中存在多个CommandLineRunnner 或者 ApplicationRunner,我们可以使用@Order注解来控制bean 类的最终执行顺序。
应用程序退出
在 Spring Boot 中,SpringApplication.exit()
方法用于优雅地关闭 Spring Boot 应用程序。该方法会执行一系列的关闭操作,包括:
-
触发
DisposableBean
接口的destroy()
方法,让实现该接口的 Bean 有机会进行资源清理。 -
调用
SmartLifecycle
接口的stop()
方法,停止那些实现了该接口的生命周期组件。 -
关闭
ApplicationContext
,释放相关资源。
SpringApplication.exit()
方法会返回一个退出码(int
类型),这个退出码可以用于指示应用程序的退出状态,通常 0
表示正常退出,非 0
表示异常退出。
使用场景
-
程序正常结束:当应用程序完成了它的任务,需要正常关闭时,可以调用该方法。例如,一个定时任务应用在完成所有任务后,主动退出。
-
异常处理:在应用程序遇到严重错误,无法继续运行时,可以调用该方法并返回一个非
0
的退出码,以指示应用程序异常退出。 -
自动化测试:在自动化测试中,测试完成后可以调用该方法关闭应用程序,确保资源被正确释放。
示例代码
正常退出
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplication
public class NormalExitExample implements CommandLineRunner {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(NormalExitExample.class, args);}@Overridepublic void run(String... args) throws Exception {System.out.println("应用程序开始执行任务...");// 模拟执行一些任务Thread.sleep(2000);System.out.println("任务执行完成,准备退出应用程序。");// 获取当前的应用上下文ConfigurableApplicationContext context = SpringApplication.run(NormalExitExample.class, args);// 调用 exit 方法正常退出应用程序,返回退出码 0int exitCode = SpringApplication.exit(context, () -> 0);System.exit(exitCode);}
}
异常退出
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplication
public class ExceptionExitExample implements CommandLineRunner {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(ExceptionExitExample.class, args);}@Overridepublic void run(String... args) throws Exception {System.out.println("应用程序开始执行任务...");try {// 模拟抛出异常throw new RuntimeException("发生了严重错误!");} catch (RuntimeException e) {System.err.println("捕获到异常: " + e.getMessage());System.err.println("准备异常退出应用程序。");// 获取当前的应用上下文ConfigurableApplicationContext context = SpringApplication.run(ExceptionExitExample.class, args);// 调用 exit 方法异常退出应用程序,返回退出码 1int exitCode = SpringApplication.exit(context, () -> 1);System.exit(exitCode);}}
}
ExitCodeGenerator 定义退出代码
@Beanpublic ExitCodeGenerator exitCodeGenerator() {return () -> 42;}public static void main(String[] args) {System.exit(SpringApplication.exit(SpringApplication.run(SpringBootLearnExample2Application.class, args)));}
管理功能
我们可以通过指定 spring.application.admin.enabled
属性可开启应用的管理相关功能,开启后会在平台的 MBeanServer 上暴露 SpringApplicationAdminMXBean
,可用于远程管理 Spring Boot 应用,对服务包装器实现也有帮助。
应用程序启动追踪
在应用启动期间,SpringApplication
和 ApplicationContext
会执行众多与应用生命周期、Bean 生命周期及应用事件处理相关的任务。借助 ApplicationStartup
,Spring 框架允许使用 StartupStep
对象跟踪应用的启动序列,这些数据可用于性能分析或帮助更好地理解应用启动过程。
在设置 SpringApplication
实例时可选择 ApplicationStartup
的实现类。例如,可使用 BufferingApplicationStartup
,代码示例展示了如何配置该实现类。
@SpringBootApplication
public class MyApplication {public static void main(String[] args) {SpringApplication application = new SpringApplication(MyApplication.class);application.setApplicationStartup(new BufferingApplicationStartup(2048));application.run(args);}}
-
具体实现类介绍
-
FlightRecorderApplicationStartup
:由 Spring 框架提供,它将 Spring 特定的启动事件添加到 Java Flight Recorder 会话中,用于分析应用程序并关联 Spring 上下文生命周期与 JVM 事件。配置后,可通过启用 Java Flight Recorder 来记录数据。 -
BufferingApplicationStartup
:Spring Boot 自带的实现类,用于缓冲启动步骤并将其输出到外部指标系统。应用程序可在任何组件中获取该类型的 Bean。
-
-
额外配置:Spring Boot 还可配置暴露一个启动端点,以 JSON 文档形式提供启动跟踪信息。
虚拟线程
在 Java 21 及更高版本中,Spring Boot 支持使用虚拟线程。虚拟线程是 Java 平台引入的轻量级线程,它旨在简化并发编程,提高应用程序的吞吐量和资源利用率。与传统的操作系统线程相比,虚拟线程的创建和销毁成本更低,能够在相同的硬件资源下处理更多的并发任务。
-
启用虚拟线程:要在 Spring Boot 应用中启用虚拟线程,需要设置
spring.threads.virtual.enabled
属性为true
。 -
线程池配置的变化:当启用虚拟线程后,配置线程池的属性将不再生效。这是因为虚拟线程是在 JVM 全局的平台线程池上进行调度,而不是在专用的线程池上。
-
处理守护线程问题:虚拟线程是守护线程,这意味着如果 JVM 中的所有线程都是守护线程,JVM 将退出。例如,当使用
@Scheduled
注解的 Bean 来保持应用程序运行时,可能会出现问题。因为调度器线程是虚拟线程,也就是守护线程,无法使 JVM 保持运行。为了解决这个问题,可以设置spring.main.keep-alive
属性为true
,确保即使所有线程都是虚拟线程,JVM 也能保持运行。
示例代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;@SpringBootApplication
@EnableScheduling
public class VirtualThreadExampleApplication {public static void main(String[] args) {SpringApplication application = new SpringApplication(VirtualThreadExampleApplication.class);// 模拟在代码中设置属性application.setDefaultProperties(java.util.Map.of("spring.threads.virtual.enabled", "true","spring.main.keep-alive", "true"));application.run(args);}
}@Component
class ScheduledTask {@Scheduled(fixedRate = 5000)public void performTask() {System.out.println("Scheduled task is running...");}
}
在上述示例中,我们启用了虚拟线程和定时任务,并设置了 spring.main.keep-alive
属性为 true
,以确保 JVM 不会因为虚拟线程是守护线程而提前退出。
参考文献
SpringApplication :: Spring Boot
相关文章:
Spring Boot 应用(官网文档解读)
Spring Boot 启动方式 SpringApplication.run(MyApplication.class, args); Spring Boot 故障分析器 在Spring Boot 项目启动发生错误的时候,我们通常可以看到上面的内容,即 APPLICATION FAILED TO START,以及后面的错误描述。这个功能是通过…...
基于ffmpeg+openGL ES实现的视频编辑工具-添加转场(九)
在视频编辑的广阔领域中,转场效果无疑是提升视频流畅性与观赏性的关键要素。巧妙运用转场,能够让不同视频片段之间的衔接更为自然,同时赋予视频独特的创意魅力。本文将深入探讨如何借助 ffmpeg 和 openGL ES 技术,在视频编辑工具中实现丰富多样的转场效果。 一、转场技术原…...
库的制作与原理(一)
1.库的概念 库是写好的,现成的可以复用的代码。本质上库是一种可执行的二进制形式,可以被操作系统载入内存执行。库有俩种:静态库 .a[Linux] .lib[windows] 动态库 .so[Linux] .dll[windows] 就是把.c文件变成.o文件,把…...
Java List 自定义对象排序 Java 8 及以上版本使用 Stream API
从 Java 8 开始,你可以使用 Stream API 对 List 进行排序,这种方式更加简洁和灵活。 以下是一个示例代码: import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors;// 自定…...
单元测试的策略有哪些,主要包括什么?
单元测试的策略及主要内容 单元测试(Unit Testing)是指对软件系统中的最小可测试单元(通常是一个函数、方法或类)进行验证,以确保其行为符合预期。常见的单元测试策略可以分为基于代码的策略和基于数据的策略…...
《深度剖析:AI与姿态估计技术在元宇宙VR交互中的应用困境》
在元宇宙的宏大版图里,虚拟现实(VR)交互是构建沉浸式体验的关键支柱,而人工智能(AI)与姿态估计技术的融合,本应成为提升交互体验的强大引擎。但在实际应用中,它们面临着诸多复杂且棘…...
基于YOLO11深度学习的糖尿病视网膜病变检测与诊断系统【python源码+Pyqt5界面+数据集+训练代码】
《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…...
【QT 网络编程】HTTP协议(二)
文章目录 🌟1.概述🌟2.代码结构概览🌟3.代码解析🌸Http_Api_Manager - API管理类🌸Http_Request_Manager- HTTP请求管理类🌸ThreadPool - 线程池🌸TestWindow- 测试类 🌟4.运行效果&…...
mysql之规则优化器RBO
文章目录 MySQL 基于规则的优化 (RBO):RBO 的核心思想:模式匹配与规则应用RBO 的主要优化规则查询重写 (Query Rewrite) / 查询转换 (Query Transformation)子查询优化 (Subquery Optimization) - RBO 的重中之重非相关子查询 (Non-Correlated Subquery)…...
Python天梯赛10分题-念数字、求整数段和、比较大小、计算阶乘和
007-念数字 输入一个整数,输出每个数字对应的拼音。当整数为负数时,先输出fu字。十个数字对应的拼音如下: 0: ling 1: yi 2: er 3: san 4: si 5: wu 6: liu 7: qi 8: ba 9: jiu输入格式: 输入在一行中给出一个整数,如&…...
如何进行文档类图像的校正?
可以使用OpenCV实现的图像校正算法,包含透视校正和旋转校正的步骤,并附有详细注释。 具体如下: import cv2 import numpy as npdef order_points(pts):"""将四个点按左上、右上、右下、左下顺序排列"""rect …...
GPIO外设
一、GPIO简介 GPIO,general-purpos IO port,通用输入输出引脚,所有的GPIO引脚都有基本的输入输出功能。 最基本的输出功能:STM32控制引脚输出高、低电平,实现开关控制;最基本的输入功能:检测外部输入电平&…...
DeepSeek-R1之二_基于Open-WebUI的AI托管平台之Pyenv-win安装与配置搭建本地AI知识库
DeepSeek-R1之二_基于Open-WebUI的AI托管平台之Pyenv-win安装与配置搭建本地AI知识库 文章目录 DeepSeek-R1之二_基于Open-WebUI的AI托管平台之Pyenv-win安装与配置搭建本地AI知识库1. 官网及前提条件1. 官网2. 前提条件1. 安装了Ollama2. 通过Ollama下载与管理了DeepSeek-R1模…...
My Metronome for Mac v1.4.2 我的节拍器 支持M、Intel芯片
应用介绍 My Metronome 是一款适用于 macOS 的专业节拍器应用程序,旨在帮助音乐家、作曲家、学生和任何需要精确节奏控制的人进行练习。无论是进行乐器练习、音乐创作还是演出排练,My Metronome 都能为用户提供精准的节拍支持和灵活的功能,确…...
Windows系统本地部署DeepSeek-R1+本地知识库+联网搜索+Agent功能
本文记录了Windows11 Ollama AnythingLLM,3步快速本地部署DeepSeek-R1模型,支持联网搜索、应用本地知识库和创建Agent功能。 前言 DeepSeek-R1 知识库相关 更新时间:截至 2025年2月,当前版本的 R1 基于 2024年7月之前的数据训…...
RT-Thread+STM32L475VET6——TF 卡文件系统
文章目录 前言一、板载资源二、具体步骤1.打开CubeMX进行USB配置1.1 使用外部高速时钟,并修改时钟树1.2 打开SPI1,参数默认即可(SPI根据自己需求调整)1.3 打开串口,参数默认1.4 生成工程 2.配置SPI2.1 打开SPI驱动2.2 声明使用SPI…...
Jmeter进阶篇(34)如何解决jmeter.save.saveservice.timestamp_format=ms报错?
问题描述 今天使用Jmeter完成压测执行,然后使用命令将jtl文件转换成html报告时,遇到了报错! 大致就是说jmeter里定义了一个jmeter.save.saveservice.timestamp_format=ms的时间格式,但是jtl文件中的时间格式不是标准的这个ms格式,导致无法正常解析。对于这个问题,有如下…...
Javascript使用Sodium库实现 aead_xchacha20poly1305_ietf加密解密,以及与后端的密文交互
Node.js环境安装 sodium-native (其他库可能会出现加密解密失败,如果要使用不一样的库,请自行验证) npm install sodium-native 示例代码,使用的是 sodium-native v4.3.2 (其他版本可能会有变化,如果要使用,请自行验…...
机器学习实战(8):降维技术——主成分分析(PCA)
第8集:降维技术——主成分分析(PCA) 在机器学习中,降维(Dimensionality Reduction) 是一种重要的数据处理技术,用于减少特征维度、去除噪声并提高模型效率。主成分分析(Principal C…...
0099__Visual Studio 引入外部静态库与动态库
Visual Studio 引入外部静态库与动态库_visual studio 添加库-CSDN博客...
eclips 快捷键
eclips 快捷键 类别快捷键功能描述通用Ctrl S保存当前文件Ctrl Shift S保存所有文件Ctrl Z撤销操作Ctrl Y重做操作Ctrl X剪切Ctrl C复制Ctrl V粘贴Ctrl A全选Ctrl F查找Ctrl H打开搜索对话框Ctrl /注释/取消注释当前行或选中的代码块Ctrl Shift /添加块注释Ctrl …...
VSCode ssh远程连接内网服务器(不能上网的内网环境的Linux服务器)的终极解决方案
VSCode ssh远程连接内网服务器(不能上网的内网环境的Linux服务器) 离线下载vscode-server并安装: 如果远程端不能联网可以下载包离线安装,下载 vscode-server 的 url 需要和 vscode 客户端版本的 commit-id 对应.通过 vscode 面板的帮助->关于可以获…...
【Gin-Web】Bluebell社区项目梳理3:社区相关接口开发
本文目录 一、接口详情1. 获取分类社区列表接口2. 根据id查询社区 二、值类型与引用类型 一、接口详情 跟社区有关的接口详情如下。 1. 获取分类社区列表接口 首先是Controller层,然后跳转到Logic层业务逻辑的开发。 这是Logic层,再做一次跳转&#…...
鸟语林-论坛系统自动化测试
文章目录 一、自动化实施步骤1.1编写Web测试用例1.2 编写自动化代码1.2.1 LoginPageTest1) 能否正确打开登录页面2) 点击去注册能否跳转注册页面3) 模拟用户登录,输入多组登录测试用例 1.2.2 RegisterPageTest1) 能否成功打开注册页面2) 注册测试用例3) 点击去登录按…...
图解循环神经网络(RNN)
目录 1.循环神经网络介绍 2.网络结构 3.结构分类 4.模型工作原理 5.模型工作示例 6.总结 1.循环神经网络介绍 RNN(Recurrent Neural Network,循环神经网络)是一种专门用于处理序列数据的神经网络结构。与传统的神经网络不同,…...
c语言左值和右值的区别
在C语言中,左值(lvalue)和右值(rvalue)是互斥的概念,左值不能是右值。以下是详细的解释和总结: 1. 左值(lvalue) 定义:左值是一个表达式,表示一个…...
Scrapy:Downloader下载器设计详解
Scrapy下载器设计详解 1. 整体架构 Scrapy的下载器(Downloader)是整个爬虫框架的核心组件之一,负责处理所有网络请求的下载工作。它的主要职责是: 管理并发请求实现请求调度处理下载延迟维护下载槽(Slot) 官方文档:Settings中的Downloader配…...
细说STM32F407单片机2个ADC使用DMA同步采集各自的1个输入通道的方法
目录 一、示例说明 二、工程配置 1、RCC、DEBUG、CodeGenerator 2、USART6 3、TIM3 (1)Mode (2)参数设置 (3) TRGO (4)ADC1_IN0 1)ADCs_Common_Settings 2&a…...
【分治法】线性时间选择问题
问题描述 给定线性序列中n个元素和一个整数k,1≤k≤n,要求在线性时间中找出这n个元素中第k小的元素 常规思路 常规思路是对序列先排序,落在第k个位置的元素就是第k小的元素。 这种方法的时间复杂度不是线性的,是O(nlogn)的时间…...
redis中的Lua脚本,redis的事务机制
lua脚本的特点 lua脚本可以操作redis数据库,并且脚本中的代码满足原子性,要么全部被执行,要么全部不执行 lua脚本的语法 脚本示例 lua脚本的草稿: 最终的lua脚本 lua脚本在java里调用的方法 RedisTemplete类里有一个方法&…...
ASUS/华硕 ROG Strix GL503VM 原厂Win10系统 工厂文件 带ASUS Recovery恢复
华硕工厂文件恢复系统 ,安装结束后带隐藏分区,带一键恢复,以及机器所有的驱动和软件。 支持型号:GL503VM 系统版本:Windows 10 文件下载:点击下载 文件格式:工厂文件 安装教程:…...
Oracle 深入理解Lock和Latch ,解析访问数据块全流程
Oracle 锁机制介绍 根据保护对象的不同,单实例Oracle数据库锁可以分为以下几大类: DML lock(data locks,数据锁):用于保护数据的完整性; DDL lock(dictionary locks,字典…...
Django Admin: 动态合并数据库和预定义选项的高级过滤器实现
在 Django 管理界面中,我们经常需要为某些字段提供过滤选项。通常情况下,这些选项要么是预定义的,要么是从数据库中动态获取的。但是,有时我们需要更灵活的解决方案:当数据库为空时使用预定义选项,而当数据库有数据时,则合并预定义选项和数据库中的值。本文将详细介绍如…...
Linux文件系统
理解硬件 磁盘、服务器、机柜、机房 机械磁盘是计算机中唯一的一个机械设备 磁盘--- 外设,慢,容量大,价格便宜 磁盘物理结构 扇区是从磁盘读出和写入信息的最小单位,通常大小为 512 字节。磁头(head)数&a…...
C++标准库——时间
文章目录 chrono库durationtime_pointclocks C 风格日期和时间库参考 C 支持两种类型的时间操作: Chrono库,在chrono头文件中提供C 风格日期和时间库,std::time这种,在ctime头文件中提供 chrono库 在<chrono>中࿰…...
AutoGen 技术博客系列 八:深入剖析 Swarm—— 智能体协作的新范式
本系列博文在掘金同步发布, 更多优质文章,请关注本人掘金账号: 人肉推土机的掘金账号 AutoGen系列一:基础介绍与入门教程 AutoGen系列二:深入自定义智能体 AutoGen系列三:内置智能体的应用与实战 AutoGen系列四&am…...
【系统架构设计师】操作系统的分类
目录 1. 说明2. 批处理操作系统3. 分时操作系统4. 实时操作系统5. 网络操作系统6. 分布式操作系统7. 微型计算机操作系统8.嵌入式操作系统9.例题9.1 例题1 1. 说明 1.通常,操作系统可分为批处理操作系统、分时操作系统、实时操作系统、网络操作系统、分布式操作系统…...
25林业研究生复试面试问题汇总 林业专业知识问题很全! 林业复试全流程攻略 林业考研复试真题汇总
25 林业考研复试,专业面试咋准备?学姐来支招! 宝子们,一提到林业考研复试面试,是不是就慌得不行,感觉老师会扔出一堆超难的问题?别怕别怕,其实林业考研复试就那么些套路,…...
基于SSM的《计算机网络》题库管理系统(源码+lw+部署文档+讲解),源码可白嫖!
摘 要 《计算机网络》题库管理系统是一种新颖的考试管理模式,因为系统是用Java技术进行开发。系统分为三个用户进行登录并操作,分别是管理员、教师和学生。教师在系统后台新增试题和试卷,学生进行在线考试,还能对考生记录、错题…...
常用高压缩率的视频容器格式,并进行大比例压缩
常用的高压缩率视频容器格式,包括*.mp4 、*.mkv、*.webM等。 容器格式本身并不直接决定压缩率,而是取决于容器中所使用的视频编码格式等因素。不过,在常见的视频容器格式中,一些容器在搭配特定编码格式时,通常能表现出较高的压缩效率,以下是相关介绍: 1 MKV格式 …...
请说明C#中的List是如何扩容的?
在 C# 中,List<T>是一个动态数组,它会根据需要自动调整其容量以容纳更多的元素。 目录 1 扩容条件与扩容算法规则 2 总结 1 扩容条件与扩容算法规则 当你创建一个新的List<T>实例时,如果没有指定初始容量,它会使…...
《微软量子芯片:开启量子计算新纪元》:此文为AI自动生成
量子计算的神秘面纱 在科技飞速发展的今天,量子计算作为前沿领域,正逐渐走进大众的视野。它宛如一把神秘的钥匙,有望开启未来科技变革的大门,而微软量子芯片则是这把钥匙上一颗璀璨的明珠。 量子计算,简单来说,是一种遵循量子力学规律调控量子信息单元进行计算的新型计算…...
使用AI创建流程图和图表的 3 种简单方法
你可能已经尝试过使用 LLMs 生成图像,但你有没有想过用它们来创建 流程图和图表?这些可视化工具对于展示流程、工作流和系统架构至关重要。 通常,在在线工具上手动绘制图表可能会耗费大量时间。但你知道吗?你可以使用 LLMs 通过简…...
数字后端实现之Innovus中open net原因解析及解决方案
数字IC后端设计实现Innovus中我们经常会碰到如下的WARNING警告信息。这个log是在route或ECO Route阶段报的。这个WARNING必须要看,因为这里是报告当前设计存在open的net,即某些pin只有逻辑连接,而没有实际的物理连接。 这里正常工具应该报ERR…...
【Linux网络】认识协议(TCP/UDP)、Mac/IP地址和端口号、网络字节序、socket套接字
⭐️个人主页:小羊 ⭐️所属专栏:Linux 很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~ 目录 1、初识协议2、UDP、TCP3、Mac、IP地址4、端口号5、网络字节序6、socket 1、初识协议 协议就是一种约定。如何让不同厂商生产的计…...
vue 学习-vite api.js
/** 整机管理 * */ // 整机分类 列表 export const wholeMachineServersType params > ajaxGet({url: wholeMachine/serverstype/,params}) // 整机分类 新增 export const wholeMachineServersTypeAdd params > ajaxPost({url: wholeMachine/serverstype/,params}) /…...
Unity贴图与模型相关知识
一、贴图 1.贴图的类型与形状 贴图类型 贴图形状 2.在Unity中可使用一张普通贴图来生成对应的法线贴图(但并不规范) 复制一张该贴图将复制后的贴图类型改为Normal Map 3.贴图的sRGB与Alpha sRGB:勾选此选项代表此贴图存储于Gamma空间中…...
Elasticsearch实战应用:从“搜索小白”到“数据侦探”的进阶之路
引言:Elasticsearch——数据世界的“福尔摩斯” 大家好,今天我们要聊的是一个在数据世界中扮演“福尔摩斯”角色的工具——Elasticsearch。如果你曾经为海量数据的搜索和分析头疼不已,那Elasticsearch就是你的救星!它不仅能帮你快…...
更改visual studio 2022 默认NuGet包路径
本文章仅提供更改用户级别的NuGet包默认路径的更改,电脑级别的更改需要更改%ProgramData%\NuGet\Config\machine.config, 而且需要管理员权限,但是更改内容类似用户级别的NuGet更改。 1. 关闭VS 2. 打开NuGet配置文件路径 可通过以下两种方…...
什么是超越编程(逾编程)(元编程?)
超越编程(逾编程)(元编程?)(meta-programming) 目录 1. meta- 的词源 2. 逾编程(meta-programming) 的直实含义 2.1 定义 2.2 说明 3. 翻译成“元编程”应该是一种错误 1. meta- 的词源 这是一个源自希腊语的构词元素,其有三种含义ÿ…...