BLOGE
0.9.9-RC1在线版 · 编制 2026-11-02 · English
附录 I —— Spring 生产参考
请在第 20 章已经跑通后使用本附录。这里是生产装配的查询面,不是第二条教程主线。
如果组件所有权仍不清楚,请回到第 20 章。
拆开来看
starter 自动配置了什么
自动配置通过 Spring Boot 3.x 的
AutoConfiguration.imports
文件注册,其中列出了十个顶层自动配置入口。下表还展开了
BlogeAutoConfiguration 内部导入的 BlogeCoreAutoConfiguration:
| 配置类 | 提供的内容 | 激活条件 |
|---|---|---|
BlogeAutoConfiguration | 入口点 — 导入 BlogeCoreAutoConfiguration | 始终激活 |
BlogeCoreAutoConfiguration | OperatorRegistry、GraphLoader、List<Graph>、租户解析器、租户过滤器 | 始终激活 |
BlogeDurableMigrationConfiguration | 显式的加密 checkpoint 迁移工具 | bloge.decrypt-checkpoints=true 且 classpath 上存在迁移类 |
BlogeGraphEngineAutoConfiguration | 通过 builder 创建 GraphEngine,包含所有 ObjectProvider 协作者 | 未启用 checkpoint 解密迁移模式时激活 |
BlogeDurableAutoConfiguration | 所有持久化存储、RecoveryConfig、RoutingStore、Flyway 迁移 | classpath 上有 bloge-durable 且存在 DataSource bean |
BlogeAuditAutoConfiguration | AuditJournalListener | spring.bloge.audit.enabled=true 且存在 AuditJournalStore bean |
SessionExecutorAutoConfiguration | 纯内存 SessionExecutor;可选的 durable session adapter 与 manager | classpath 上有 bloge-session-ext;durable bean 还要求对应类、store 与 definition lookup |
BlogeStateMachineAutoConfiguration | durable state-machine manager 与恢复接线 | classpath 上有 durable state-machine 类且 spring.bloge.state-machine.enabled=true |
BlogeEndpointAutoConfiguration | /actuator/bloge、/actuator/blogeStats | classpath 上有 spring-boot-actuator |
BlogeObservabilityAutoConfiguration | 指标、链路追踪、MDC、日志、健康指示器 | classpath 上有 bloge-metrics-otel |
BlogeEventJournalAutoConfiguration | 事件日志保留和生命周期 | classpath 上有 bloge-event-journal |
如果你要接入多轮 session 流程,可以配合阅读第 14 章 —— 多轮 Session。
那一章会把 SessionExecutorAutoConfiguration 背后真正接起来的运行时模型讲清楚:
session graph、phase / round 执行、空闲超时,以及可选的持久恢复。
@BlogeOperator 注解
定义在 BlogeOperator.java 中:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface BlogeOperator {
@AliasFor(annotation = Component.class, attribute = "value")
String value() default "";
String description() default "";
String owner() default "";
String[] tags() default {};
String promptHint() default "";
String usageExample() default "";
String constraintsDescription() default "";
}
它底层就是 @Component,所以 Spring 能发现它。BlogeAutoConfiguration.operatorRegistry() bean 方法会扫描所有标注了 @BlogeOperator 的 bean,并以注解的 value() 为键将每一个注册到 DefaultOperatorRegistry 中。
面向 agent/LLM 集成时,三个额外属性向 AI agent 描述该 operator:
promptHint告诉 agent 何时选择此 operator;usageExample给出展示该 operator 用法的 DSL 片段;constraintsDescription记录了从 schema 中不易察觉 的约束。这三个属性均为可选。
GraphEngine 是如何组装的
BlogeGraphEngineAutoConfiguration 负责创建引擎 bean,接受
tenantContextResolver 和 tenantResourcePolicy 用于多租户部署,
并提供 GraphEngineCustomizer 回调钩子,让你无需替换整个引擎 bean
即可调整它。
BlogeGraphEngineAutoConfiguration 中的 graphEngine() bean 方法对每个可选协作者都使用了 ObjectProvider:
@Bean
@ConditionalOnMissingBean
public GraphEngine graphEngine(
OperatorRegistry registry,
ObjectProvider<OperatorInterceptor> interceptors,
ObjectProvider<ExecutionListener> listeners,
ObjectProvider<CallerContextCarrier> contextCarriers,
ObjectProvider<CheckpointCodec> checkpointCodec,
ObjectProvider<VersionRoutingPolicy> versionRoutingPolicy,
ObjectProvider<TenantContextResolver> tenantContextResolver,
ObjectProvider<TenantResourcePolicy> tenantResourcePolicy,
ObjectProvider<GraphEngineCustomizer> customizers,
/* ... 更多 ObjectProvider ... */) {
GraphEngine.Builder builder = GraphEngine.builder()
.registry(registry)
.interceptors(interceptors.orderedStream().toList())
.listeners(listeners.orderedStream().toList())
.contextCarriers(contextCarriers.orderedStream().toList())
.checkpointCodec(checkpointCodec.getIfAvailable())
.versionRoutingPolicy(versionRoutingPolicy.getIfAvailable())
.tenantContextResolver(tenantContextResolver.getIfAvailable())
.tenantResourcePolicy(tenantResourcePolicy.getIfAvailable());
if (properties.getEngineMode() == BlogeProperties.EngineMode.REQUEST_RESPONSE) {
builder.requestResponseDefaults();
}
customizers.orderedStream().forEach(c -> c.customize(builder));
return builder.build();
}
这意味着你声明为 Spring bean 的 任何 OperatorInterceptor、ExecutionListener、
CallerContextCarrier、TenantContextResolver 或 TenantResourcePolicy
都会被引擎自动拾取。你永远不需要手动操作引擎的 builder。
GraphEngineCustomizer 是一个回调接口,让你在所有自动配置默认值和
engine-mode 预设应用完毕后微调 GraphEngine.Builder —— 无需替换整个引擎 bean:
@Bean
public GraphEngineCustomizer myCustomizer() {
return builder -> builder
.schedulerTimerSupport(myTimerSupport);
}
核心配置属性
声明在 BlogeProperties.java 中,前缀为 spring.bloge:
spring:
bloge:
dsl-locations: classpath:bloge/ # .bloge 文件的扫描位置
hot-reload: false # 文件监听并在变更时重新编译
default-timeout: 30s # 默认节点超时
accessor-mode: method-handle # 表达式编译模式
engine-mode: auto # 引擎预设(auto | request-response)
streaming-default-buffer-size: 16 # 流式执行缓冲区大小
engine-mode和streaming-default-buffer-size。engine-mode为引擎 builder 选择高层预设。AUTO(默认)使用标准设置;REQUEST_RESPONSE为短生命周期、请求范围内的 graph 执行应用优化默认值。streaming-default-buffer-size控制流式 graph 执行的默认背压缓冲区。
租户属性
当 spring.bloge.tenant.enabled=true 时,starter 会创建
SpringTenantContextResolver 和 SpringTenantResourcePolicy bean,
注入引擎的多租户准入控制:
spring:
bloge:
tenant:
enabled: false # 主开关
mode: header # header | security-context | static
header-name: X-Tenant-Id # 租户解析用的 HTTP 头
namespace-header-name: X-Namespace # 命名空间解析用的 HTTP 头
default-tenant: default # 回退租户 ID
default-namespace: default # 回退命名空间
max-concurrent-executions: 100 # 每租户并发上限
max-starts-per-minute: 0 # 每租户速率限制(0 = 无限制)
mode 属性决定租户的解析方式:
| 模式 | 如何解析租户 |
|---|---|
HEADER | 从 HTTP 请求头中读取 X-Tenant-Id 和 X-Namespace |
SECURITY_CONTEXT | 从 Spring Security 的 Authentication.getDetails() 中提取 tenantId / namespace |
STATIC | 始终返回 default-tenant / default-namespace |
启用租户支持后,starter 还会注册一个 TenantContextFilter —— 一个 servlet
过滤器,通过 TenantContextHolder.callWith() 将解析后的 TenantContext
绑定到当前请求线程,使整个 HTTP 请求期间的存储查询和默认 GraphContext 构造
都能看到同一个租户。
版本路由属性
spring:
bloge:
version-routing:
policy: latest # latest | pinned | canary
pinned-version: null # policy=pinned 时必填
canary-primary: null # canary 的主版本
canary-candidate: null # canary 的候选版本
canary-percentage: 10 # 路由到候选版本的流量百分比
持久化路由属性
spring:
bloge:
durable:
routing:
mode: single # single | hash | tenant
tenant-strategy: null # shared-table | separate-schema | separate-database
default-shard-id: default
fallback-shard-id: null
shard-ids: []
tenant-shards: {} # tenantId → shardId 的映射
持久化存储接线
当 classpath 上有 bloge-durable 且存在 DataSource bean 时,starter 会创建一个 durableSqlSessionFactory bean,运行 Flyway 迁移(如果 spring.bloge.durable.flyway.enabled=true,这是默认值),并注册十多个运行时存储 bean —— 每个都带有 @ConditionalOnMissingBean,所以你可以覆盖其中任何一个。完整列表包括 ExecutionStore、ExecutionCheckpointStore、WaitStore、WorkItemStore、GraphRegistryStore、RoutingStore、TaskInboxStore、EventMatcherStore、EventDeduplicationStore、ArchiveService 和 DurableControlPlaneService。
健康指示器
BlogeHealthIndicator
在至少一个 graph 被加载时报告 UP,在列表为空时报告 DOWN 并附带 "reason": "No graphs loaded"。它出现在 /actuator/health 的 bloge 组件下。
错误响应 —— RFC 9457 ProblemDetail
bloge-spring-web 在 classpath 上时,所有 BLOGE 异常都会被映射到
RFC 9457 ProblemDetail,这样客户端看到的是统一、机器可读的错误格式,
而不是堆栈。
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json
{
"type": "https://bloge.dev/problems/graph-version-mismatch",
"title": "Graph version mismatch",
"status": 422,
"detail": "Execution started against orderProcess@v3 but live registry has @v4.",
"instance": "/executions/exec-12af9",
"executionId": "exec-12af9",
"graphId": "orderProcess",
"expectedHash": "sha256:1f3a…",
"actualHash": "sha256:9c0e…"
}
BlogeProblemDetailAdvice 内置的映射:
| 异常 | HTTP 状态 | type URI 后缀 |
|---|---|---|
GraphDefinitionException | 400 | /problems/graph-definition |
GraphValidationException | 422 | /problems/graph-validation |
GraphVersionMismatchException | 422 | /problems/graph-version-mismatch |
SessionAccessDeniedException | 403 | /problems/session-access-denied |
StaleLeaseException | 409 | /problems/stale-lease |
OperatorTimeoutException | 504 | /problems/operator-timeout |
| 其他 | 500 | /problems/internal(不泄漏异常细节) |
要禁用或覆盖,自己声明一个 @RestControllerAdvice bean 即可 —— 自动配置
通过 @ConditionalOnMissingBean(BlogeProblemDetailAdvice.class) 让位。