🚀 第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 Map getApplicationInfo() { Map info = 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(); Map jvmInfo = 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 List getBeanNames() { return Arrays.asList(applicationContext.getBeanDefinitionNames()); } /** * 检查Bean是否存在 */ public boolean containsBean(String beanName) { return applicationContext.containsBean(beanName); } /** * 获取Bean类型 */ public Class getBeanType(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 Map getMemoryInfo() { Map memoryInfo = new HashMap<>(); MemoryUsage heapUsage = memoryMXBean.getHeapMemoryUsage(); MemoryUsage nonHeapUsage = memoryMXBean.getNonHeapMemoryUsage(); // 堆内存信息 Map heap = 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); // 非堆内存信息 Map nonHeap = 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 Map getThreadInfo() { Map threadInfo = 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()); Map stateCount = 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) { Map gc = 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 Map getSystemInfo() { Map systemInfo = 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() { Map memoryInfo = getMemoryInfo(); Map threadInfo = 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 { Map memoryInfo = runtimeMonitor.getMemoryInfo(); Map heap = (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 { Map appInfo = 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() { Map info = runtimeService.getApplicationInfo(); return ResponseEntity.ok(info); } /** * 获取内存信息 */ @GetMapping("/memory") public ResponseEntity> getMemoryInfo() { Map memoryInfo = runtimeMonitor.getMemoryInfo(); return ResponseEntity.ok(memoryInfo); } /** * 获取线程信息 */ @GetMapping("/threads") public ResponseEntity> getThreadInfo() { Map threadInfo = 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() { Map systemInfo = runtimeMonitor.getSystemInfo(); return ResponseEntity.ok(systemInfo); } /** * 触发GC */ @PostMapping("/gc") public ResponseEntity triggerGc() { System.gc(); log.info("手动触发GC"); return ResponseEntity.ok("GC triggered"); } /** * 获取Bean列表 */ @GetMapping("/beans") public ResponseEntity> getBeans() { List beanNames = runtimeService.getBeanNames(); return ResponseEntity.ok(beanNames); } /** * 优雅关闭应用 */ @PostMapping("/shutdown") public ResponseEntity shutdown() { 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 🏠 返回课程首页