大家好,我是小悟。
一、系统监控:你的应用需要“体检医生”
想象一下:你的SpringBoot应用就像一个996的程序员,每天24小时不间断工作。某天它突然“猝死”了,而你却不知道它是何时倒下、为何倒下、倒下前有没有喊“救命”… 这就是没有监控的可怕之处!
系统监控就像是:
- 健康手环:时刻监测应用的心跳(健康状态)
- 行车记录仪:记录每一次接口调用的“交通事故”
- 私人医生:自动诊断哪里出了问题,还能开药方(告警)
- 行为分析师:分析用户的“奇怪”操作模式
二、监控大作战详细步骤
第1步:基础依赖 - 准备“体检工具箱”
<!-- 监控全家桶套餐 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- 健康检查加强版 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- 可视化监控面板 --> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-client</artifactId> <version>2.7.0</version> </dependency> <!-- 监控指标导出到Prometheus --> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency>
第2步:配置监控权限 - 设置“诊室门禁”
# application.yml spring: application: name: my-application # 给应用起个名字,方便认领 management: endpoints: web: exposure: include: "*" # 开放所有监控端点 exclude: env,beans # 敏感信息 endpoint: health: show-details: always # 健康检查显示详细信息 probes: enabled: true # 开启K8s探针支持 prometheus: enabled: true # 开启Prometheus指标导出 metrics: export: prometheus: enabled: true tags: application: ${spring.application.name} # 给指标打标签 info: env: enabled: true # 显示环境信息 # 自定义健康检查项 info: app: name: "超级无敌SpringBoot应用" version: "v2.0.0" description: "这是一个被严密监控的应用,别想偷懒!" developer: "监控狂魔团队" motto: "没有监控的代码就是在裸奔"
第3步:自定义健康检查 - 编写“体检项目”
import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.stereotype.Component; import java.util.Random; /** * 数据库连接健康检查 * 相当于检查应用的“消化系统” */ @Component("database") public class DatabaseHealthIndicator implements HealthIndicator { private final Random random = new Random(); @Override public Health health() { boolean isHealthy = checkDatabaseConnection(); if (isHealthy) { return Health.up() .withDetail("message", "数据库连接正常,可以愉快地CRUD啦!") .withDetail("responseTime", "15ms") .withDetail("activeConnections", 25) .build(); } else { return Health.down() .withDetail("message", "数据库连接失败,快去检查水管(连接)!") .withDetail("errorCode", "DB_CONN_001") .withDetail("suggestion", "试试重启大法?") .build(); } } private boolean checkDatabaseConnection() { // 模拟检查,真实项目应该真的ping一下数据库 return random.nextInt(100) > 10; // 90%的概率健康 } } /** * 缓存健康检查 * 相当于检查应用的“短期记忆” */ @Component("cache") public class CacheHealthIndicator implements HealthIndicator { @Override public Health health() { return Health.up() .withDetail("status", "缓存运行正常") .withDetail("memoryUsage", "45%") .withDetail("hitRate", "89.7%") .withDetail("motto", "记不住的东西,交给缓存吧!") .build(); } } /** * 外部API依赖检查 * 相当于检查应用的“社交能力” */ @Component("externalApi") public class ExternalApiHealthIndicator implements HealthIndicator { @Override public Health health() { // 模拟检查第三方API boolean wechatApi = checkWechatApi(); boolean paymentApi = checkPaymentApi(); if (wechatApi && paymentApi) { return Health.up() .withDetail("wechat", "微信API:连接正常,可以愉快聊天") .withDetail("payment", "支付API:钱包鼓鼓,随时收钱") .withDetail("overall", "所有外部API都很给力!") .build(); } else { return Health.down() .withDetail("wechat", wechatApi ? "正常" : "失联中...") .withDetail("payment", paymentApi ? "正常" : "掉线了,没法收钱!") .withDetail("emergency", "快联系第三方客服!") .build(); } } private boolean checkWechatApi() { return true; // 假装检查 } private boolean checkPaymentApi() { return new Random().nextInt(100) > 5; // 95%可用率 } }
第4步:自定义监控指标 - 安装“行为记录仪”
import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Timer; import org.springframework.stereotype.Component; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; /** * 业务指标监控 * 相当于给应用安装“计步器”和“心率监测” */ @Component public class BusinessMetrics { // 用户注册计数器(统计有多少人“入坑”) private final Counter userRegistrationCounter; // 订单创建计数器(统计赚了多少钱) private final Counter orderCreationCounter; // 异常计数器(统计出了多少bug) private final Counter exceptionCounter; // 活跃用户数(看看多少人在“玩”) private final AtomicInteger activeUsers; // API响应时间计时器(看看接口是不是“拖延症”) private final Timer apiResponseTimer; // 自定义业务指标(比如:点赞数、评论数等) private final Counter likeCounter; public BusinessMetrics(MeterRegistry registry) { // 初始化所有指标 userRegistrationCounter = Counter.builder("user.registration.total") .description("用户注册总数") .tag("application", "my-app") .register(registry); orderCreationCounter = Counter.builder("order.created.total") .description("订单创建总数") .tag("application", "my-app") .register(registry); exceptionCounter = Counter.builder("exception.total") .description("异常发生总数") .tag("application", "my-app") .register(registry); activeUsers = registry.gauge("user.active.current", new AtomicInteger(0)); apiResponseTimer = Timer.builder("api.response.time") .description("API响应时间") .publishPercentiles(0.5, 0.95, 0.99) // 统计50%, 95%, 99%分位 .register(registry); likeCounter = Counter.builder("content.like.total") .description("内容点赞总数") .tag("application", "my-app") .register(registry); } // 用户注册时调用(又有人“入坑”啦!) public void incrementUserRegistration() { userRegistrationCounter.increment(); System.out.println("恭喜!又有新用户注册啦!当前总数: " + userRegistrationCounter.count()); } // 订单创建时调用(钱钱钱!) public void incrementOrderCreation(double amount) { orderCreationCounter.increment(); System.out.println("收到新订单!金额: " + amount + ",订单总数: " + orderCreationCounter.count()); } // 异常发生时调用(啊哦,出bug了) public void incrementException(String exceptionType) { exceptionCounter.increment(); System.err.println("发现bug!类型: " + exceptionType + ",bug总数: " + exceptionCounter.count()); } // 更新活跃用户数(看看谁在摸鱼) public void setActiveUsers(int count) { activeUsers.set(count); } // 记录API响应时间(看看哪个接口在偷懒) public void recordApiTime(long millis, String apiName) { apiResponseTimer.record(millis, TimeUnit.MILLISECONDS); if (millis > 1000) { System.out.println("警告!接口 " + apiName + " 响应缓慢,耗时: " + millis + "ms"); } } // 点赞时调用(收到小心心) public void incrementLike() { likeCounter.increment(); System.out.println("收到一个点赞!当前点赞数: " + likeCounter.count()); } }
第5步:AOP监控切面 - 安装“全方位摄像头”
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * 接口监控切面 * 相当于在每个接口门口安装“摄像头+计时器” */ @Aspect @Component public class MonitorAspect { @Autowired private BusinessMetrics businessMetrics; // 监控所有Controller(重点监控对象) @Pointcut("execution(* com.example.controller..*.*(..))") public void controllerPointcut() {} // 监控Service层(业务逻辑层) @Pointcut("execution(* com.example.service..*.*(..))") public void servicePointcut() {} @Around("controllerPointcut()") public Object monitorController(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); String methodName = joinPoint.getSignature().toShortString(); System.out.println("🎬 接口开始执行: " + methodName); try { Object result = joinPoint.proceed(); long executionTime = System.currentTimeMillis() - startTime; // 记录响应时间 businessMetrics.recordApiTime(executionTime, methodName); System.out.println("接口执行成功: " + methodName + ",耗时: " + executionTime + "ms"); return result; } catch (Exception e) { // 记录异常 businessMetrics.incrementException(e.getClass().getSimpleName()); System.err.println("接口执行失败: " + methodName + ",异常: " + e.getMessage()); throw e; } } @Around("servicePointcut()") public Object monitorService(ProceedingJoinPoint joinPoint) throws Throwable { String methodName = joinPoint.getSignature().toShortString(); // 检查是不是重要业务方法 if (methodName.contains("UserService.register")) { System.out.println("开始注册用户..."); } else if (methodName.contains("OrderService.create")) { System.out.println("开始创建订单..."); } try { return joinPoint.proceed(); } catch (Exception e) { System.err.println("业务方法出错: " + methodName); businessMetrics.incrementException("ServiceException"); throw e; } } }
第6步:监控告警配置 - 设置“紧急呼叫按钮”
import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.util.Date; /** * 监控告警系统 * 相当于应用的“私人医生紧急呼叫” */ @Component public class MonitorAlert { @Autowired(required = false) private JavaMailSender mailSender; @Autowired private BusinessMetrics businessMetrics; private HealthIndicator databaseHealth; // 每小时检查一次健康状态(定期体检) @Scheduled(fixedRate = 60 * 60 * 1000) public void healthCheck() { System.out.println("开始定时健康检查..."); // 检查异常数(看看是不是bug泛滥) double exceptionCount = businessMetrics.getExceptionCount(); if (exceptionCount > 100) { sendAlert("异常数超标警告", "系统异常数已达到 " + exceptionCount + ",快去修bug!"); } // 检查响应时间(看看接口是不是在偷懒) double avgResponseTime = businessMetrics.getAvgResponseTime(); if (avgResponseTime > 5000) { sendAlert("系统响应缓慢", "平均响应时间 " + avgResponseTime + "ms,用户要跑光了!"); } System.out.println("健康检查完成,一切正常!"); } // 每天发送日报(每日病情报告) @Scheduled(cron = "0 0 18 * * ?") // 每天下午6点 public void dailyReport() { String report = buildDailyReport(); System.out.println("生成日报:\n" + report); if (mailSender != null) { sendEmail("系统监控日报 - " + new Date(), report); } } private String buildDailyReport() { return """ ======== 系统监控日报 ======== 日期:%s 今日新增用户:%d 今日订单总数:%d 今日点赞数:%d 今日异常数:%d 平均响应时间:%.2f ms 系统健康状态:%s ============================ """.formatted( new Date(), businessMetrics.getTodayUserRegistrations(), businessMetrics.getTodayOrders(), businessMetrics.getTodayLikes(), businessMetrics.getTodayExceptions(), businessMetrics.getAvgResponseTime(), getOverallHealthStatus() ); } private void sendAlert(String title, String message) { System.err.println(title + ": " + message); // 发送邮件告警(如果配置了邮件) if (mailSender != null) { sendEmail("[紧急]" + title, message); } // 这里还可以集成钉钉、企业微信、短信等告警 System.out.println("已发送告警通知!"); } private void sendEmail(String subject, String text) { SimpleMailMessage message = new SimpleMailMessage(); message.setTo("dev-team@example.com"); message.setSubject(subject); message.setText(text); mailSender.send(message); } private String getOverallHealthStatus() { // 综合判断系统健康状况 if (businessMetrics.getTodayExceptions() > 50) { return "生病了,需要紧急处理"; } else if (businessMetrics.getAvgResponseTime() > 1000) { return "有点疲惫,需要优化"; } else { return "非常健康,继续努力"; } } }
第7步:可视化监控面板 - 打造“监控指挥中心”
import de.codecentric.boot.admin.server.config.EnableAdminServer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * Spring Boot Admin Server * 监控可视化面板,相当于“监控指挥中心大屏幕” */ @SpringBootApplication @EnableAdminServer public class MonitorDashboardApplication { public static void main(String[] args) { SpringApplication.run(MonitorDashboardApplication.class, args); System.out.println(""" 监控面板启动成功! 访问地址: http://localhost:8080 用户名: admin 密码: admin 在这里你可以看到: 1. 所有服务的健康状态 2. 实时性能指标 3. 告警信息 4. 日志查看 5. 动态配置管理 就像有了一个全天候的监控室! """); } }
三、访问监控端点
应用启动后,可以访问以下监控端点:
健康检查:http://localhost:8080/actuator/health 所有指标:http://localhost:8080/actuator/metrics Prometheus格式:http://localhost:8080/actuator/prometheus 应用信息:http://localhost:8080/actuator/info 环境变量:http://localhost:8080/actuator/env Bean列表:http://localhost:8080/actuator/beans 映射关系:http://localhost:8080/actuator/mappings 配置属性:http://localhost:8080/actuator/configprops
四、完整配置示例
# application-monitor.yml spring: boot: admin: client: url: http://localhost:8080 instance: name: ${spring.application.name} security: user: name: admin password: admin123 mail: host: smtp.example.com port: 587 username: monitor@example.com password: yourpassword properties: mail: smtp: auth: true starttls: enable: true # 监控告警规则 monitor: alert: enabled: true email: recipients: - dev-team@example.com - ops-team@example.com thresholds: response-time: 5000 # 5秒 error-rate: 0.05 # 5% memory-usage: 0.8 # 80% schedules: daily-report: "0 0 18 * * ?" # 每天18点 health-check: "0 */30 * * * ?" # 每30分钟
五、总结:监控让系统“透明化”
为什么要监控?(监控的五大好处)
- 预防胜于治疗
- 在用户投诉前发现问题
- 在系统崩溃前预警
- 就像给系统打了“疫苗”
- 快速定位问题
- 不再是“猜谜游戏”
- 精准定位问题根因
- 减少“重启试试”的次数
- 性能优化依据
- 知道哪里慢,才知道怎么优化
- 数据驱动的优化决策
- 告别“我感觉这个接口有点慢”
- 容量规划参考
- 知道系统能承受多少压力
- 合理规划服务器资源
- 避免“双十一”时系统崩溃
- 提升开发体验
- 实时了解系统状态
- 快速验证修复效果
- 减少半夜被叫起来修bug的概率
监控的最佳实践
- 分层监控:从基础设施到应用层全链路监控
- 关键指标:监控黄金指标(延迟、流量、错误、饱和度)
- 智能告警:避免告警疲劳,设置合理的阈值
- 可视化:一图胜千言,好的图表让人秒懂状态
- 持续改进:根据监控数据不断优化系统
最后
给你的SpringBoot应用装上监控,就像:
- 给汽车装上了仪表盘+行车记录仪+胎压监测
- 给程序员配上了智能手环+年度体检+健康教练
- 给房子安装了烟雾报警器+摄像头+智能门锁
监控不是万能的,但没有监控是万万不能的!
现在,去给你的应用装上“健康手环”,让它从此过上“透明、健康、可观测”的幸福生活吧!
温馨提示:监控虽好,也不要过度监控哦!毕竟,连上厕所都要统计时间和次数的话,系统也会感到“压力山大”的!
谢谢你看我的文章,既然看到这里了,如果觉得不错,随手点个赞、转发、在看三连吧,感谢感谢。那我们,下次再见。
您的一键三连,是我更新的最大动力,谢谢
山水有相逢,来日皆可期,谢谢阅读,我们再会
我手中的金箍棒,上能通天,下能探海