Skip to content

框架级错误通知 ​

一、背景介绍 ​

在实际生产环境中,应用启动阶段的异常(例如数据库连接失败、Redis 连接异常、注解扫描失败、服务启动失败等)如果不能被及时感知,往往会导致问题发现滞后。

TioBoot 提供了框架级通知能力,可以在应用启动的关键阶段捕获异常并通过自定义通知通道发送告警信息,从而实现启动即感知、失败即通知。

本文将详细介绍:

  • 如何实现自定义框架级通知发送器
  • 如何在启动类中正确配置通知发送器
  • 启动失败时的通知示例
  • 使用过程中的关键注意事项

二、框架级通知触发时机 ​

TioBoot 在以下阶段发生异常时,会触发框架级通知:

  • 数据库(DataSource)初始化失败
  • Redis 连接失败
  • 注解扫描异常
  • 服务启动失败
  • TioBoot 配置类执行异常

通知内容通常包含:

  • 时间
  • 运行环境
  • 应用名称
  • 异常级别
  • 服务器 IP
  • 完整堆栈信息
  • 错误描述

三、自定义通知发送器实现 ​

3.1 NotificationSender 实现类 ​

下面示例展示了一个基于 飞书(Lark Suite)Webhook 的框架级通知发送器实现。

java
import nexus.io.tio.boot.admin.utils.TioVirtualThreadUtils;
import nexus.io.tio.utils.notification.NotificationSender;
import nexus.io.tio.utils.environment.EnvUtils;
import nexus.io.tio.utils.notification.LarksuiteNotificationUtils;
import nexus.io.tio.utils.notification.NotifactionWarmModel;

import lombok.extern.slf4j.Slf4j;
import okhttp3.Response;

@Slf4j
public class MyNotificationSender implements NotificationSender {

  @Override
  public boolean send(NotifactionWarmModel model) {
    final String webHookUrl = EnvUtils.get("warm.notification.webhook.url");
    if (webHookUrl != null) {
      try (Response response = LarksuiteNotificationUtils.sendWarm(webHookUrl, model)) {
        if (!response.isSuccessful()) {
          log.error("Faild to push :{}", response.body().string());
          return false;
        }
      } catch (Exception e) {
        log.error(e.getMessage(), e);
        return false;
      }
    }
    return true;
  }

  @Override
  public boolean sendAsync(NotifactionWarmModel model) {
    TioVirtualThreadUtils.submit(() -> {
      send(model);
    });
    return true;
  }
}

3.2 设计说明 ​

  • send 同步发送通知,适用于启动阶段的重要错误通知。

  • sendAsync 使用虚拟线程异步发送,避免阻塞主流程。

  • WebHook 地址通过 EnvUtils 动态读取,支持多环境配置。


四、在启动类中启用系统通知 ​

4.1 启动类配置示例 ​

必须在应用启动前设置 NotificationSender,否则启动阶段无法获取通知实现。

java
package nexus.io.manim;

import nexus.io.annotation.AComponentScan;
import nexus.io.manim.config.MvAdminAppConfig;
import nexus.io.manim.notification.MyNotificationSender;
import nexus.io.tio.boot.TioApplication;
import nexus.io.tio.boot.server.TioBootServer;

@AComponentScan("nexus.io.manim.controller")
public class CanvasApp {

  public static void main(String[] args) {
    long start = System.currentTimeMillis();

    TioBootServer server = TioBootServer.me();
    server.setNotificationSender(new MyNotificationSender());

    TioApplication.run(CanvasApp.class, new MvAdminAppConfig(), args);

    long end = System.currentTimeMillis();
    System.out.println((end - start) + "(ms)");
  }
}

4.2 关键点说明 ​

  • server.setNotificationSender(new MyNotificationSender())必须在 TioApplication.run 之前调用

  • 通知发送器在 TioApplicationContext 启动阶段就会被使用


五、启动失败通知示例 ​

当数据库连接失败时,系统会自动推送如下通知信息:

- Time : 2026-01-24 18:27:09 +08:00
- App Env : dev
- App Group Name : app.group.name
- Name : TioApplicationContext
- Level : LeveL 0
- Device : 192.168.3.219
- Stack Trace :
com.zaxxer.hikari.pool.HikariPool$PoolInitializationException:
Failed to initialize pool: FATAL: password authentication failed for user "postgres"
    at com.zaxxer.hikari.pool.HikariPool.throwPoolInitializationException(HikariPool.java:596)
    at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:582)
    at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:115)
    at com.zaxxer.hikari.HikariDataSource.<init>(HikariDataSource.java:81)
    at nexus.io.tio.boot.admin.config.TioAdminDbConfiguration.config(TioAdminDbConfiguration.java:61)
    at nexus.io.manim.config.MvAdminAppConfig.config(MvAdminAppConfig.java:28)
    at nexus.io.tio.boot.context.TioApplicationContext.run(TioApplicationContext.java:282)
    at nexus.io.tio.boot.TioApplication.run(TioApplication.java:27)
    at nexus.io.manim.CanvasApp.main(CanvasApp.java:27)
Caused by: org.postgresql.util.PSQLException:
FATAL: password authentication failed for user "postgres"

- Content :
Failed to run tioBootConfiguration.config()

六、重要注意事项 ​

注意事项一:必须在启动类中设置 NotificationSender ​

java
server.setNotificationSender(new MyNotificationSender());

原因:

  • TioApplicationContext 在启动早期即会使用通知能力
  • 如果未设置,启动阶段的异常将无法发送通知

注意事项二:EnvUtils.get 必须在方法内部调用 ​

java
final String webHookUrl = EnvUtils.get("warm.notification.webhook.url");

原因:

  • EnvUtils.load() 的执行时机 晚于 new MyNotificationSender()
  • 如果在构造函数或成员变量中读取配置,可能会拿到 null
  • 放在 send 方法内部可确保环境变量已加载完成

七、总结 ​

通过 TioBoot 提供的框架级通知机制,可以实现:

  • 启动即告警
  • 配置错误秒级感知
  • 启动失败无需登录服务器排查

配合企业微信、飞书、钉钉等 Webhook,可以极大提升应用的可运维性和稳定性。

如需扩展通知渠道(短信、邮件、多 Webhook),只需实现 NotificationSender 接口即可。


MIT Licensed