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/
作者
clxstart
发布于
2026-09-19
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。