3035 字
约 10 分钟
1
🚀 SpringBoot Runtime
2026-09-19
无标签
🚀 第16章 SpringBoot Runtime
掌握应用启动、运行时管理和生命周期控制 💻 查看完整代码 - 在线IDE体验 学习目标
📋 学习目标
- 应用启动流程- SpringBoot启动机制
- 生命周期管理- Bean生命周期控制
- 运行时监控- 应用状态监控
- 优雅关闭- 应用安全停止
- 性能调优- JVM参数优化
- 故障排查- 运行时问题诊断
运行时核心概念
🔍 运行时核心概念
- 应用上下文- ApplicationContext管理
- Bean生命周期- 创建、初始化、销毁
- 事件机制- 应用事件发布订阅
- 健康检查- 应用健康状态
- 优雅关闭- 资源清理机制
- 热部署- 开发时自动重启
应用启动配置
📦 应用启动配置
# application.yml 运行时配置
spring:
# 应用基本信息
application:
name: springboot-runtime-demo
# 主配置
main:
# 允许Bean定义覆盖
allow-bean-definition-overriding: true
# 允许循环引用
allow-circular-references: false
# Web应用类型
web-application-type: servlet
# 延迟初始化
lazy-initialization: false
# 生命周期配置
lifecycle:
# 优雅关闭超时时间
timeout-per-shutdown-phase: 30s
# 任务执行配置
task:
execution:
pool:
core-size: 8
max-size: 16
queue-capacity: 100
keep-alive: 60s
thread-name-prefix: "async-task-"
shutdown:
await-termination: true
await-termination-period: 60s
# 任务调度配置
task:
scheduling:
pool:
size: 4
thread-name-prefix: "scheduled-task-"
shutdown:
await-termination: true
await-termination-period: 60s
# 服务器配置
server:
port: 8080
# 优雅关闭
shutdown: graceful
# Tomcat配置
tomcat:
# 连接超时
connection-timeout: 20000ms
# 最大连接数
max-connections: 8192
# 线程配置
threads:
max: 200
min-spare: 10
# 接受队列大小
accept-count: 100
# 管理端点配置
management:
endpoints:
web:
exposure:
include: health,info,metrics,env,beans,configprops
endpoint:
health:
show-details: always
shutdown:
enabled: true
health:
defaults:
enabled: true
# 日志配置
logging:
level:
cn.bugstack.springframework.boot.runtime: DEBUG
org.springframework.boot: INFO
org.springframework.context: DEBUG
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
file:
name: logs/runtime-demo.log
max-size: 10MB
max-history: 30
应用启动流程
🔄 SpringBoot启动流程
1创建SpringApplication 初始化SpringApplication实例,设置主配置类 2准备Environment 加载配置文件,设置环境变量和系统属性 3创建ApplicationContext 根据应用类型创建相应的上下文 4加载Bean定义 扫描并注册所有Bean定义到容器 5刷新上下文 实例化Bean,处理依赖注入 6启动完成 发布ApplicationReadyEvent事件 应用生命周期管理
🎯 应用生命周期管理
// RuntimeApplication.java - 主启动类
@SpringBootApplication
@EnableScheduling
@EnableAsync
@Slf4j
public class RuntimeApplication {
public static void main(String[] args) {
// 创建SpringApplication
SpringApplication app = new SpringApplication(RuntimeApplication.class);
// 设置启动参数
app.setDefaultProperties(getDefaultProperties());
// 添加启动监听器
app.addListeners(new ApplicationStartupListener());
// 设置Banner模式
app.setBannerMode(Banner.Mode.CONSOLE);
// 启动应用
ConfigurableApplicationContext context = app.run(args);
// 注册关闭钩子
context.registerShutdownHook();
log.info("应用启动完成,端口: {}",
context.getEnvironment().getProperty("server.port"));
}
/**
* 设置默认属性
*/
private static Properties getDefaultProperties() {
Properties properties = new Properties();
properties.setProperty("spring.application.name", "runtime-demo");
properties.setProperty("server.port", "8080");
return properties;
}
}
// ApplicationStartupListener.java - 启动监听器
@Component
@Slf4j
public class ApplicationStartupListener implements ApplicationListener{
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationStartingEvent) {
log.info("应用开始启动...");
} else if (event instanceof ApplicationEnvironmentPreparedEvent) {
log.info("环境准备完成");
} else if (event instanceof ApplicationContextInitializedEvent) {
log.info("应用上下文初始化完成");
} else if (event instanceof ApplicationPreparedEvent) {
log.info("应用准备完成");
} else if (event instanceof ApplicationStartedEvent) {
log.info("应用启动完成");
} else if (event instanceof ApplicationReadyEvent) {
log.info("应用就绪,可以接收请求");
} else if (event instanceof ApplicationFailedEvent) {
log.error("应用启动失败");
}
}
}
// LifecycleBean.java - 生命周期Bean
@Component
@Slf4j
public class LifecycleBean implements InitializingBean, DisposableBean,
ApplicationContextAware, BeanNameAware {
private ApplicationContext applicationContext;
private String beanName;
/**
* 构造函数
*/
public LifecycleBean() {
log.info("LifecycleBean 构造函数执行");
}
/**
* 设置Bean名称
*/
@Override
public void setBeanName(String name) {
this.beanName = name;
log.info("setBeanName: {}", name);
}
/**
* 设置应用上下文
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
log.info("setApplicationContext 执行");
}
/**
* 属性设置后执行
*/
@PostConstruct
public void postConstruct() {
log.info("@PostConstruct 执行");
}
/**
* InitializingBean接口方法
*/
@Override
public void afterPropertiesSet() throws Exception {
log.info("afterPropertiesSet 执行");
}
/**
* 自定义初始化方法
*/
@Bean(initMethod = "customInit")
public void customInit() {
log.info("customInit 执行");
}
/**
* 销毁前执行
*/
@PreDestroy
public void preDestroy() {
log.info("@PreDestroy 执行");
}
/**
* DisposableBean接口方法
*/
@Override
public void destroy() throws Exception {
log.info("destroy 执行");
}
/**
* 自定义销毁方法
*/
public void customDestroy() {
log.info("customDestroy 执行");
}
}
// RuntimeService.java - 运行时服务
@Service
@Slf4j
public class RuntimeService {
@Autowired
private ApplicationContext applicationContext;
/**
* 获取应用信息
*/
public MapgetApplicationInfo() {
Mapinfo = new HashMap<>();
// 应用名称
info.put("applicationName",
applicationContext.getEnvironment().getProperty("spring.application.name"));
// 启动时间
info.put("startTime",
applicationContext.getStartupDate());
// Bean数量
info.put("beanCount",
applicationContext.getBeanDefinitionCount());
// 活跃配置
info.put("activeProfiles",
applicationContext.getEnvironment().getActiveProfiles());
// JVM信息
Runtime runtime = Runtime.getRuntime();
MapjvmInfo = new HashMap<>();
jvmInfo.put("totalMemory", runtime.totalMemory());
jvmInfo.put("freeMemory", runtime.freeMemory());
jvmInfo.put("maxMemory", runtime.maxMemory());
jvmInfo.put("availableProcessors", runtime.availableProcessors());
info.put("jvm", jvmInfo);
return info;
}
/**
* 获取Bean信息
*/
public ListgetBeanNames() {
return Arrays.asList(applicationContext.getBeanDefinitionNames());
}
/**
* 检查Bean是否存在
*/
public boolean containsBean(String beanName) {
return applicationContext.containsBean(beanName);
}
/**
* 获取Bean类型
*/
public ClassgetBeanType(String beanName) {
return applicationContext.getType(beanName);
}
}
运行时架构图示
🎨 运行时架构图示
Application应用层
↓
SpringBoot框架层
↓
JVM虚拟机层
↓
OS操作系统
分层架构:应用层 → SpringBoot框架 → JVM → 操作系统
每层都有相应的监控和管理机制 生命周期阶段
📍 生命周期阶段
- Starting- 应用开始启动
- Environment Prepared- 环境准备完成
- Context Initialized- 上下文初始化
- Prepared- 应用准备完成
- Started- 应用启动完成
- Ready- 应用就绪状态
监控指标
📊 监控指标
- 内存使用- 堆内存、非堆内存
- 线程状态- 活跃线程、阻塞线程
- GC信息- 垃圾回收统计
- 类加载- 已加载类数量
- CPU使用率- 处理器使用情况
- 网络连接- 连接数、请求数
运行时监控
🔧 运行时监控
// RuntimeMonitor.java - 运行时监控
@Component
@Slf4j
public class RuntimeMonitor {
private final MeterRegistry meterRegistry;
private final MemoryMXBean memoryMXBean;
private final ThreadMXBean threadMXBean;
private final GarbageCollectorMXBean[] gcMXBeans;
public RuntimeMonitor(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.memoryMXBean = ManagementFactory.getMemoryMXBean();
this.threadMXBean = ManagementFactory.getThreadMXBean();
this.gcMXBeans = ManagementFactory.getGarbageCollectorMXBeans()
.toArray(new GarbageCollectorMXBean[0]);
// 注册自定义指标
registerCustomMetrics();
}
/**
* 注册自定义指标
*/
private void registerCustomMetrics() {
// 内存使用指标
Gauge.builder("jvm.memory.heap.used")
.description("Used heap memory")
.register(meterRegistry, this,
monitor -> monitor.memoryMXBean.getHeapMemoryUsage().getUsed());
Gauge.builder("jvm.memory.heap.max")
.description("Max heap memory")
.register(meterRegistry, this,
monitor -> monitor.memoryMXBean.getHeapMemoryUsage().getMax());
// 线程数指标
Gauge.builder("jvm.threads.live")
.description("Live threads")
.register(meterRegistry, this,
monitor -> monitor.threadMXBean.getThreadCount());
Gauge.builder("jvm.threads.daemon")
.description("Daemon threads")
.register(meterRegistry, this,
monitor -> monitor.threadMXBean.getDaemonThreadCount());
}
/**
* 获取内存信息
*/
public MapgetMemoryInfo() {
MapmemoryInfo = new HashMap<>();
MemoryUsage heapUsage = memoryMXBean.getHeapMemoryUsage();
MemoryUsage nonHeapUsage = memoryMXBean.getNonHeapMemoryUsage();
// 堆内存信息
Mapheap = new HashMap<>();
heap.put("init", heapUsage.getInit());
heap.put("used", heapUsage.getUsed());
heap.put("committed", heapUsage.getCommitted());
heap.put("max", heapUsage.getMax());
memoryInfo.put("heap", heap);
// 非堆内存信息
MapnonHeap = new HashMap<>();
nonHeap.put("init", nonHeapUsage.getInit());
nonHeap.put("used", nonHeapUsage.getUsed());
nonHeap.put("committed", nonHeapUsage.getCommitted());
nonHeap.put("max", nonHeapUsage.getMax());
memoryInfo.put("nonHeap", nonHeap);
return memoryInfo;
}
/**
* 获取线程信息
*/
public MapgetThreadInfo() {
MapthreadInfo = new HashMap<>();
threadInfo.put("totalStarted", threadMXBean.getTotalStartedThreadCount());
threadInfo.put("live", threadMXBean.getThreadCount());
threadInfo.put("peak", threadMXBean.getPeakThreadCount());
threadInfo.put("daemon", threadMXBean.getDaemonThreadCount());
// 线程状态统计
ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(
threadMXBean.getAllThreadIds());
MapstateCount = new HashMap<>();
for (ThreadInfo info : threadInfos) {
if (info != null) {
Thread.State state = info.getThreadState();
stateCount.merge(state, 1, Integer::sum);
}
}
threadInfo.put("states", stateCount);
return threadInfo;
}
/**
* 获取GC信息
*/
public List> getGcInfo() {
List> gcInfo = new ArrayList<>();
for (GarbageCollectorMXBean gcBean : gcMXBeans) {
Mapgc = new HashMap<>();
gc.put("name", gcBean.getName());
gc.put("collectionCount", gcBean.getCollectionCount());
gc.put("collectionTime", gcBean.getCollectionTime());
gc.put("memoryPoolNames", Arrays.asList(gcBean.getMemoryPoolNames()));
gcInfo.add(gc);
}
return gcInfo;
}
/**
* 获取系统信息
*/
public MapgetSystemInfo() {
MapsystemInfo = new HashMap<>();
Runtime runtime = Runtime.getRuntime();
systemInfo.put("availableProcessors", runtime.availableProcessors());
systemInfo.put("totalMemory", runtime.totalMemory());
systemInfo.put("freeMemory", runtime.freeMemory());
systemInfo.put("maxMemory", runtime.maxMemory());
// 操作系统信息
OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
systemInfo.put("osName", osBean.getName());
systemInfo.put("osVersion", osBean.getVersion());
systemInfo.put("osArch", osBean.getArch());
if (osBean instanceof com.sun.management.OperatingSystemMXBean) {
com.sun.management.OperatingSystemMXBean sunOsBean =
(com.sun.management.OperatingSystemMXBean) osBean;
systemInfo.put("processCpuLoad", sunOsBean.getProcessCpuLoad());
systemInfo.put("systemCpuLoad", sunOsBean.getSystemCpuLoad());
systemInfo.put("totalPhysicalMemory", sunOsBean.getTotalPhysicalMemorySize());
systemInfo.put("freePhysicalMemory", sunOsBean.getFreePhysicalMemorySize());
}
return systemInfo;
}
/**
* 定时监控任务
*/
@Scheduled(fixedRate = 60000) // 每分钟执行一次
public void monitorRuntime() {
MapmemoryInfo = getMemoryInfo();
MapthreadInfo = getThreadInfo();
log.info("运行时监控 - 堆内存使用: {}MB/{MB, 线程数: {}",
((Map) memoryInfo.get("heap")).get("used") / 1024 / 1024,
((Map) memoryInfo.get("heap")).get("max") / 1024 / 1024,
threadInfo.get("live"));
}
}
// HealthIndicator.java - 自定义健康检查
@Component
public class CustomHealthIndicator implements HealthIndicator {
@Autowired
private RuntimeMonitor runtimeMonitor;
@Override
public Health health() {
try {
MapmemoryInfo = runtimeMonitor.getMemoryInfo();
Mapheap = (Map) memoryInfo.get("heap");
// 检查内存使用率
double memoryUsage = (double) heap.get("used") / heap.get("max");
if (memoryUsage > 0.9) {
return Health.down()
.withDetail("memory", "Memory usage too high: " +
String.format("%.2f%%", memoryUsage * 100))
.build();
} else if (memoryUsage > 0.8) {
return Health.up()
.withDetail("memory", "Memory usage warning: " +
String.format("%.2f%%", memoryUsage * 100))
.build();
} else {
return Health.up()
.withDetail("memory", "Memory usage normal: " +
String.format("%.2f%%", memoryUsage * 100))
.build();
}
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.build();
}
}
}
优雅关闭
🛡️ 优雅关闭机制
// GracefulShutdownConfig.java - 优雅关闭配置
@Configuration
@Slf4j
public class GracefulShutdownConfig {
/**
* 配置优雅关闭
*/
@Bean
public GracefulShutdown gracefulShutdown() {
return new GracefulShutdown();
}
/**
* 自定义Tomcat连接器
*/
@Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.addConnectorCustomizers(gracefulShutdown());
return tomcat;
}
/**
* 优雅关闭实现
*/
private static class GracefulShutdown implements TomcatConnectorCustomizer,
ApplicationListener{
private volatile Connector connector;
private final int waitTime = 30;
@Override
public void customize(Connector connector) {
this.connector = connector;
}
@Override
public void onApplicationEvent(ContextClosedEvent event) {
if (connector == null) {
return;
}
log.info("开始优雅关闭,等待{}秒...", waitTime);
// 停止接收新请求
connector.pause();
Executor executor = connector.getProtocolHandler().getExecutor();
if (executor instanceof ThreadPoolExecutor) {
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
threadPoolExecutor.shutdown();
try {
if (!threadPoolExecutor.awaitTermination(waitTime, TimeUnit.SECONDS)) {
log.warn("线程池未能在{}秒内正常关闭,强制关闭", waitTime);
threadPoolExecutor.shutdownNow();
} else {
log.info("线程池已优雅关闭");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
threadPoolExecutor.shutdownNow();
}
}
}
}
}
// ShutdownHook.java - 关闭钩子
@Component
@Slf4j
public class ShutdownHook {
@Autowired
private RuntimeService runtimeService;
@EventListener
public void handleContextClosedEvent(ContextClosedEvent event) {
log.info("应用开始关闭...");
// 清理资源
cleanupResources();
// 保存状态
saveApplicationState();
log.info("应用关闭完成");
}
/**
* 清理资源
*/
private void cleanupResources() {
try {
// 关闭数据库连接池
// 清理缓存
// 关闭消息队列连接
// 等等...
log.info("资源清理完成");
} catch (Exception e) {
log.error("资源清理失败", e);
}
}
/**
* 保存应用状态
*/
private void saveApplicationState() {
try {
MapappInfo = runtimeService.getApplicationInfo();
// 保存应用状态到文件或数据库
log.info("应用状态保存完成");
} catch (Exception e) {
log.error("应用状态保存失败", e);
}
}
}
// RuntimeController.java - 运行时控制器
@RestController
@RequestMapping("/runtime")
@Slf4j
public class RuntimeController {
@Autowired
private RuntimeService runtimeService;
@Autowired
private RuntimeMonitor runtimeMonitor;
@Autowired
private ApplicationContext applicationContext;
/**
* 获取应用信息
*/
@GetMapping("/info")
public ResponseEntity> getApplicationInfo() {
Mapinfo = runtimeService.getApplicationInfo();
return ResponseEntity.ok(info);
}
/**
* 获取内存信息
*/
@GetMapping("/memory")
public ResponseEntity> getMemoryInfo() {
MapmemoryInfo = runtimeMonitor.getMemoryInfo();
return ResponseEntity.ok(memoryInfo);
}
/**
* 获取线程信息
*/
@GetMapping("/threads")
public ResponseEntity> getThreadInfo() {
MapthreadInfo = runtimeMonitor.getThreadInfo();
return ResponseEntity.ok(threadInfo);
}
/**
* 获取GC信息
*/
@GetMapping("/gc")
public ResponseEntity>> getGcInfo() {
List> gcInfo = runtimeMonitor.getGcInfo();
return ResponseEntity.ok(gcInfo);
}
/**
* 获取系统信息
*/
@GetMapping("/system")
public ResponseEntity> getSystemInfo() {
MapsystemInfo = runtimeMonitor.getSystemInfo();
return ResponseEntity.ok(systemInfo);
}
/**
* 触发GC
*/
@PostMapping("/gc")
public ResponseEntitytriggerGc() {
System.gc();
log.info("手动触发GC");
return ResponseEntity.ok("GC triggered");
}
/**
* 获取Bean列表
*/
@GetMapping("/beans")
public ResponseEntity> getBeans() {
ListbeanNames = runtimeService.getBeanNames();
return ResponseEntity.ok(beanNames);
}
/**
* 优雅关闭应用
*/
@PostMapping("/shutdown")
public ResponseEntityshutdown() {
log.info("收到关闭请求,开始优雅关闭...");
// 异步执行关闭操作
new Thread(() -> {
try {
Thread.sleep(1000); // 给响应时间
((ConfigurableApplicationContext) applicationContext).close();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
return ResponseEntity.ok("Application shutdown initiated");
}
}
性能调优对比表
📊 JVM参数调优对比
| 参数类型 | 参数 | 说明 | 推荐值 |
|---|---|---|---|
| 内存设置 | -Xms / -Xmx | 初始堆大小 / 最大堆大小 | -Xms2g -Xmx2g |
| 新生代 | -Xmn | 新生代大小 | -Xmn512m |
| 垃圾回收 | -XX:+UseG1GC | 使用G1垃圾回收器 | 推荐大内存应用 |
| GC日志 | -XX:+PrintGCDetails | 打印GC详细信息 | 生产环境建议开启 |
| OOM处理 | -XX:+HeapDumpOnOutOfMemoryError | OOM时生成堆转储 | 必须开启 |
| 远程调试 | -agentlib:jdwp | 开启远程调试 | 开发环境使用 |
最佳实践
💡 运行时最佳实践
🎯 性能优化合理设置JVM参数- 根据应用特点调整内存和GC监控关键指标- 内存、线程、GC、CPU使用率优雅关闭机制- 确保资源正确释放健康检查- 实时监控应用健康状态故障恢复- 自动重启和故障转移机制
# JVM启动参数示例
java -server \
-Xms2g -Xmx2g \
-Xmn512m \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+PrintGCDetails \
-XX:+PrintGCTimeStamps \
-XX:+PrintGCApplicationStoppedTime \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/logs/heapdump.hprof \
-Djava.awt.headless=true \
-Dfile.encoding=UTF-8 \
-Duser.timezone=Asia/Shanghai \
-jar springboot-runtime-demo.jar
# Docker运行示例
docker run -d \
--name runtime-demo \
--memory=4g \
--cpus=2 \
-p 8080:8080 \
-v /logs:/app/logs \
-e JAVA_OPTS="-Xms2g -Xmx2g -XX:+UseG1GC" \
springboot-runtime-demo:latest
# Kubernetes部署示例
apiVersion: apps/v1
kind: Deployment
metadata:
name: runtime-demo
spec:
replicas: 3
selector:
matchLabels:
app: runtime-demo
template:
metadata:
labels:
app: runtime-demo
spec:
containers:
- name: runtime-demo
image: springboot-runtime-demo:latest
ports:
- containerPort: 8080
resources:
requests:
memory: "2Gi"
cpu: "1"
limits:
memory: "4Gi"
cpu: "2"
env:
- name: JAVA_OPTS
value: "-Xms2g -Xmx2g -XX:+UseG1GC"
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 60
periodSeconds: 30
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
下一章节
🎉 恭喜完成第16章学习!
你已经掌握了SpringBoot Runtime的核心技能,接下来学习测试框架和测试策略! 🚀 下一章:SpringBoot Test 🏠 返回课程首页
🚀 SpringBoot Runtime
http://www.clxhxhhr.top/posts/2884/ 评论
0 条
还没有评论,先写一条吧。