📦 应用启动配置
# 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
🔧 运行时监控
// 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
🛡️ 优雅关闭机制
// 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");
}
}