☰
如何编写一个SpringBoot项目告警推送的Starter:TaoToken统一Key接入与配置骨架
2026/9/26 15:32:06 网站建设 项目流程

1. 为什么要把告警推送做成一个 Starter

线上服务最怕的不是报错,而是报错了没人知道。接口偶发 500、某个请求耗时从 100ms 涨到 2s、JVM 堆内存持续爬升、慢 SQL 越来越多,这些问题在彻底爆发前其实都有信号,只是没人盯着看。如果每个业务项目都自己写一套「捕获异常 → 拼消息 → 调 webhook」的代码,重复不说,配置还散落在各处,改一个阈值要翻好几个仓库。

告警推送 Starter 要解决的就是这件事:把异常捕获、慢请求统计、状态码监控、JVM 指标采集这些通用能力封装成一个自动装配的组件,业务项目只要引入依赖、填一个 webhook 地址,启动后就具备基础告警能力。它适合中小团队快速搭起告警链路,也适合已有 Prometheus/Grafana 的团队补一个「实时推送」的入口。

这篇会交付一套可复制的 Starter 骨架:目录结构、spring.factories与 AutoConfiguration 写法、application.yml配置项,以及用 TaoToken 统一 Key 接入告警通道的示例。最后给出本地启动验证告警发送的完整步骤,照着做就能跑通。

2. TaoToken 统一 Key 接入前置准备

多工具告警通道最烦的是 Key 管理:飞书一个 webhook、钉钉一个 access_token、企业微信一个 key,散在配置文件里,换环境就要改一遍。TaoToken 提供统一 Key 的方式,把模型对话、编码 Agent、API 调用这些能力收敛到一个 Key 上,告警通道的接入凭证也可以走同一套管理逻辑,减少配置漂移。

你需要先拿到一个可用的 Key。打开官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 注册后进入控制台,在 API Keys 页面创建一个 Key。这个 Key 后面会写进 Starter 的配置里,用于统一鉴权。

创建 Key 的入口在这里:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,Key 管理页面是 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 基础地址是 https://taotoken.net/api (这个不加 UTM)。

注意:Key 只放在服务端配置或环境变量里,不要提交到 Git,也不要在前端代码里出现。建议用${TAOTOKEN_API_KEY}这种占位方式注入。

如果你后面还要做长期编码或 Agent 相关的告警联动,可以了解 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。需要直接对话验证模型是否通,用模型对话页面:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。

3. Starter 目录结构与自动装配骨架

先看整体结构。Maven 多模块拆法,核心逻辑和自动装配分开,业务方按需引入:

alert-push-starter/ ├── alert-push-core/ # 核心模型与推送逻辑 │ └── src/main/java/com/example/alert/core/ │ ├── AlertMessage.java # 告警消息模型 │ ├── AlertPublisher.java # 推送接口 │ └── channel/ # 各通道实现 ├── alert-push-spring-boot-starter/ # 自动装配 │ └── src/main/ │ ├── java/com/example/alert/starter/ │ │ ├── AlertAutoConfiguration.java │ │ ├── AlertProperties.java │ │ └── AlertTemplate.java │ └── resources/META-INF/ │ └── spring.factories └── alert-push-demo/ # 本地验证示例

AlertProperties负责绑定application.yml里的配置项,用@ConfigurationProperties声明:

package com.example.alert.starter; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "alert.push") public class AlertProperties { private boolean enabled = true; private String webhook; private String webhookFormat = "feishu"; private String serviceName = "unknown-service"; private String environment = "dev"; private String apiKey; private String apiBase = "https://taotoken.net/api"; private Dedupe dedupe = new Dedupe(); private ExceptionConfig exception = new ExceptionConfig(); private RequestConfig request = new RequestConfig(); // getter / setter 省略,实际项目用 Lombok @Data 即可 public static class Dedupe { private boolean enabled = true; private int cooldownSeconds = 300; // getter / setter } public static class ExceptionConfig { private boolean enabled = true; private int stackTraceMaxLines = 20; // getter / setter } public static class RequestConfig { private boolean enabled = true; private long slowThresholdMs = 1000; // getter / setter } }

自动装配类把 Properties、Publisher、Template 串起来,并用@ConditionalOnProperty控制开关:

package com.example.alert.starter; import com.example.alert.core.AlertPublisher; import com.example.alert.core.channel.FeishuPublisher; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @EnableConfigurationProperties(AlertProperties.class) @ConditionalOnProperty(prefix = "alert.push", name = "enabled", havingValue = "true", matchIfMissing = true) public class AlertAutoConfiguration { @Bean @ConditionalOnMissingBean public AlertPublisher alertPublisher(AlertProperties props) { FeishuPublisher publisher = new FeishuPublisher(); publisher.setWebhook(props.getWebhook()); publisher.setApiKey(props.getApiKey()); publisher.setApiBase(props.getApiBase()); return publisher; } @Bean @ConditionalOnMissingBean public AlertTemplate alertTemplate(AlertPublisher publisher, AlertProperties props) { return new AlertTemplate(publisher, props); } }

spring.factories是自动装配的入口,Spring Boot 2.x 用这个文件,3.x 可以换成AutoConfiguration.imports:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.alert.starter.AlertAutoConfiguration

如果是 Spring Boot 3.x,在src/main/resources/META-INF/spring/下建org.springframework.boot.autoconfigure.AutoConfiguration.imports,内容直接写类名:

com.example.alert.starter.AlertAutoConfiguration

AlertTemplate是对外暴露的调用入口,业务代码注入它就能手动发告警,同时它内部也负责去重逻辑:

package com.example.alert.starter; import com.example.alert.core.AlertMessage; import com.example.alert.core.AlertPublisher; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class AlertTemplate { private final AlertPublisher publisher; private final AlertProperties props; private final Map<String, Long> lastSentAt = new ConcurrentHashMap<>(); public AlertTemplate(AlertPublisher publisher, AlertProperties props) { this.publisher = publisher; this.props = props; } public void send(String title, String content) { String key = title + "|" + content; if (props.getDedupe().isEnabled()) { long now = System.currentTimeMillis(); Long last = lastSentAt.get(key); if (last != null && now - last < props.getDedupe().getCooldownSeconds() * 1000L) { return; } lastSentAt.put(key, now); } AlertMessage msg = new AlertMessage(); msg.setServiceName(props.getServiceName()); msg.setEnvironment(props.getEnvironment()); msg.setTitle(title); msg.setContent(content); publisher.publish(msg); } }

4. application.yml 配置项与 TaoToken Key 接入示例

配置项按「总开关 → 通道 → 去重 → 异常 → 请求」的顺序组织,最简配置只要三行:

alert: push: enabled: true webhook: https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxx webhook-format: feishu

完整配置带上 TaoToken 统一 Key 和各类阈值:

alert: push: enabled: true webhook: https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxx webhook-format: feishu service-name: ${spring.application.name} environment: ${spring.profiles.active:dev} api-key: ${TAOTOKEN_API_KEY} api-base: https://taotoken.net/api dedupe: enabled: true cooldown-seconds: 300 exception: enabled: true stack-trace-max-lines: 20 request: enabled: true slow-threshold-ms: 1000

几个关键参数对照:

配置项作用建议值
enabled总开关true
webhook-format通道类型feishu / dingtalk / wecom
api-keyTaoToken 统一 Key环境变量注入
dedupe.cooldown-seconds同类告警冷却窗口300
request.slow-threshold-ms慢请求阈值1000
exception.stack-trace-max-lines堆栈截断行数20

api-key走环境变量注入,本地启动时这样设置:

export TAOTOKEN_API_KEY="你的Key"

Windows PowerShell 用:

$env:TAOTOKEN_API_KEY="你的Key"

提示:api-base固定为https://taotoken.net/api,不要带 UTM 参数,那是给网页链接用的,API 调用不需要。

5. 本地启动验证告警发送

验证分三步:起服务、触发告警、看结果。

第一步,在 demo 模块里写一个测试 Controller,模拟异常和慢请求:

package com.example.alert.demo; import com.example.alert.starter.AlertTemplate; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/demo") public class DemoController { private final AlertTemplate alertTemplate; public DemoController(AlertTemplate alertTemplate) { this.alertTemplate = alertTemplate; } @GetMapping("/ok") public String ok() { return "ok"; } @GetMapping("/error") public String error() { throw new NullPointerException("demo 空指针告警"); } @GetMapping("/slow") public String slow(long millis) throws InterruptedException { Thread.sleep(millis); return "slow " + millis; } @GetMapping("/manual") public String manual() { alertTemplate.send("手动告警", "这是一条通过 AlertTemplate 发出的测试消息"); return "sent"; } }

第二步,启动 demo 服务,默认端口 18089:

cd alert-push-demo mvn spring-boot:run

看到日志里出现AlertAutoConfiguration装配成功的记录,说明 Starter 生效了。

第三步,触发告警并观察:

curl http://localhost:18089/demo/error curl "http://localhost:18089/demo/slow?millis=1500" curl http://localhost:18089/demo/manual

/demo/error会触发异常告警,/demo/slow?millis=1500因为超过 1000ms 阈值触发慢请求告警,/demo/manual走AlertTemplate手动发送。控制台会打印推送日志,飞书群里能看到对应消息。

如果只想验证 Key 是否可用,不依赖 webhook,可以先用模型对话页面发一条测试:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,确认 Key 鉴权通过后再接告警通道。

6. 本篇常见错误排查

自动装配没生效,AlertTemplate注入失败。先检查spring.factories路径是否为src/main/resources/META-INF/spring.factories,Spring Boot 3.x 则要确认用的是AutoConfiguration.imports。再看alert.push.enabled是否被设成了 false,@ConditionalOnProperty的matchIfMissing = true只在配置项缺失时生效。

配置项绑定不上,webhook为 null。@ConfigurationProperties(prefix = "alert.push")的前缀要和 yml 里的层级完全对应,yml 缩进用空格不用 Tab。如果用了@EnableConfigurationProperties但没在自动装配类上加,Properties 不会被注册。

告警发出去了但群里没消息。先确认 webhook 地址完整,飞书机器人地址以/open-apis/bot/v2/hook/开头。再看webhook-format和实际通道是否匹配,格式填错会导致消息体结构不对,接口返回 400。用 curl 直接打一次 webhook 地址,排除网络和机器人配置问题。

同类告警只收到一条。这是去重生效了,cooldown-seconds默认 300 秒。调试阶段可以临时设成 0 或关掉dedupe.enabled,上线前再打开。

Key 鉴权失败返回 401。检查api-key是否通过环境变量正确注入,echo $TAOTOKEN_API_KEY确认非空。Key 前后不要带空格或引号。如果 Key 泄露过,去 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 重新生成一个。

慢请求告警不触发。确认request.enabled为 true,slow-threshold-ms小于实际请求耗时。如果请求路径在exclude-paths里,会被跳过,检查有没有把测试路径误加进去。

接入相关的完整说明在文档页:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,遇到装配或鉴权问题优先对照文档排查。

7. 下一步:把告警链路接到 Coding Plan

Starter 跑通后,告警入口就打通了。接下来可以做的扩展方向:把告警消息和日志查询、指标采集串起来,收到异常后自动拉取上下文再回推分析结果。这类联动如果涉及编码 Agent 或长期运行的自动化任务,用 Coding Plan 会更顺:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。

需要管理多个服务的 Key 和配额,去控制台:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。新建 Key 在 API Keys 页面:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。

我实测下来,Starter 这类组件的价值不在代码多复杂,而在于「接入成本足够低」。业务方引入依赖、填一个 webhook、启动,就能收到第一条告警,这个体验比写一堆文档管用。先把异常和慢请求这两个最高频的场景跑通,后面再按需加 SQL 监控、JVM 指标、状态码告警,链路自然就长出来了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询