BLOGE
0.9.9-RC1在线版 · 编制 2026-11-02 · English
第 20 章 —— Spring 与生产环境接线
承诺: 读完本章后,你能够通过 Spring Boot 启动一张 BLOGE graph, 不手写 engine bean;能够读懂 health 结果;也能只用一次
GraphEngineCustomizer覆盖完成必要调整,而不接管整棵自动配置图。
学习目标
- 添加
bloge-spring依赖,让BlogeAutoConfiguration自动接线GraphEngine、OperatorRegistry、GraphLoader和编译后的List<Graph>,无需手动定义任何 bean。 - 使用
@BlogeOperator标注实现Operator、SuspendableOperator或StreamingOperator的运行时对象,让 Spring 发现并注册它们。 - 将
GraphEngine和编译后的 graph 列表注入到一个 service 类中,执行 graph 并通过 HTTP 端点返回结果。 - 把
UP + graphCount=1读成接线观察,而不是业务证明。 - 使用
GraphEngineCustomizer调整轻量引擎,并判断何时替换整个 bean 会制造不必要的责任。
前置条件
- 第 7 章 —— 设计良好的 Operator —— 在将 operator 接入 Spring 之前,你需要掌握 operator 的设计模型。
- 第 13 章 —— 持久执行 —— 运行时存储、检查点和挂起/恢复,因为 starter 会有条件地接线所有这些组件。
- 熟悉 Spring Boot 自动配置、
@ConfigurationProperties和 Spring Boot Actuator 基础。
源示例
| 文件 | 展示内容 |
|---|---|
BlogeAutoConfiguration.java | 导入 core slice 的入口自动配置 |
BlogeProperties.java | 所有 spring.bloge.* 配置属性及嵌套分组 |
BlogeOperator.java | 由 @Component 组合而成的 operator 扫描注解 |
BlogeObservabilityAutoConfiguration.java | 指标、链路追踪、MDC、健康指示器接线 |
BlogeEndpointAutoConfiguration.java | /actuator/bloge 和 /actuator/blogeStats 端点 |
BlogeAuditAutoConfiguration.java | 审计日志监听器激活 |
SessionExecutorAutoConfiguration.java | SessionExecutor 接线,包含访问守卫和监听器 |
spring-ticket-triage.bloge | starter 示例加载的最小 DSL |
SpringBootTicketTriageApplication.java | 端到端的 Spring Boot 应用,使用 starter |
SpringTicketTriageService.java | 注入 GraphEngine 和 List<Graph> 的 Service 层 |
为什么这很重要
在前面的章节中,你通过手动方式构建引擎:
var engine = GraphEngine.builder()
.registry(registry)
.executionCheckpointStore(checkpointStore)
.listeners(listeners)
.build();
这在测试和学习时没问题。但在生产环境中,需要接线的列表会迅速膨胀:拦截器、监听器、上下文载体、持久化存储、检查点编解码器、恢复配置、分片解析器、定时器服务、事件去重 —— 而且每个 bean 都有自己的条件和回退逻辑。
bloge-spring 模块处理这部分组装工作。它是一个 Spring Boot Starter,会自动配置 classpath 与属性条件已经满足的组件。把 operator 声明为 Spring bean,并将 .bloge 文件放到 classpath 后,starter 可以为这个应用切片组装一套可运行引擎。加入 bloge-durable 或 bloge-metrics-otel 后,starter 会检测并接线其中满足条件的 bean,不需要重复声明 @Bean。这只证明应用接线已经建立,不证明持久化 store、外部 effect 或生产容量已经就绪。
核心洞察: starter 并没有隐藏引擎 —— 它只是组装引擎。多数可替换的 singleton 默认值使用
@ConditionalOnMissingBean;扩展集合和 endpoint slice 有自己的条件,因此覆盖前仍要确认目标 bean 的具体合同。