百积木文档
开发指南平台应用、模块与 Bundle 开发模块开发

InterfaceMap 与 ServiceReferenceMap

声明一组具名 Interface 服务槽位,通过 ServiceReferenceMap 绑定同一 Runtime 中的多个目标服务。

InterfaceMap 用于声明“键到接口”的模块属性类型;对应的属性值必须是 ServiceReferenceMap。每个 valueMap 条目都是一个逻辑 ServiceReference,由调用模块自定义的稳定键 选择,同一个属性可以因此绑定多个符合接口契约的 Runtime 服务。

类型和值不能混用

InterfaceMap 只出现在 propertyDefinition[].type 中;ServiceReferenceMap 只出现在属性值、 defaultValue 编译结果和 Runtime 配置中。协议名称区分大小写,不能写成 interfaceMapInterfaceMAP,也不能把 valueMap 直接当作属性值顶层。

位置@type主要字段用途
模块属性定义InterfaceMapvalueInterface约束每个映射值必须实现的接口
逻辑属性值ServiceReferenceMapvalueMap保存键到目标服务完整 businessId 的绑定
生命周期回调ServiceReferenceMapvalueMap保留映射结构,并把每个逻辑引用展开为可调用引用

在 module.json 中声明

下面的 channels 属性允许调用模块按 primarybackup 等业务键选择多个 Channel 服务。 valueInterface 与单值 Interface 的定义结构相同;其中的方法是调用方编译期的期望契约。

{
  "propertyDefinition": [
    {
      "name": "channels",
      "type": {
        "@type": "InterfaceMap",
        "valueInterface": {
          "@type": "Interface",
          "name": "Channel",
          "methods": [
            {
              "name": "send",
              "returnType": {
                "@type": "DataType",
                "type": "object",
                "nullable": false
              },
              "paramDefinitions": [
                {
                  "name": "payload",
                  "type": {
                    "@type": "DataType",
                    "type": "object",
                    "nullable": false
                  },
                  "required": true
                }
              ]
            }
          ],
          "events": []
        },
        "nullable": false
      },
      "required": true,
      "defaultValue": "{}"
    }
  ]
}
  • valueInterface 描述所有映射值共同遵守的接口,不为不同键分别声明不同接口。
  • 映射键是调用模块自己的稳定业务键,不是模块名、Bundle 名、目标 businessId 或方法名。
  • 空默认值写成 "{}";模块版本编译后会形成空的 ServiceReferenceMap。不要在定义中加入 Runtime 地址、token 或某个部署环境的可变服务 ID。
  • 如果安装时就有明确且可移植的目标,可以在 defaultValue 的 JSON 对象中写入 ServiceReference 条目;目标随安装结果变化时,应保持空默认值并在安装后配置。

需要复用公开 Type Definition 时,valueInterface 也可以使用受 Bundle typeDefinitionDependencies 约束的 RefType。引用格式和版本范围见 Type Definition

配置 ServiceReferenceMap

安装后先从目标工作区的 Runtime 服务目录读取每个目标服务的完整 businessId 和当前方法定义,再创建 properties.json

{
  "channels": {
    "@type": "ServiceReferenceMap",
    "valueMap": {
      "primary": {
        "@type": "ServiceReference",
        "serviceId": "<primaryChannelBusinessId>"
      },
      "backup": {
        "@type": "ServiceReference",
        "serviceId": "<backupChannelBusinessId>"
      }
    }
  }
}

执行当前 CLI 的正式模块属性命令:

baijimu runtime app properties update \
  <callerBusinessId> \
  --workspace-id <workspaceId> \
  --properties @properties.json
  • --properties 是模块属性的顶层部分更新;未出现的其他模块属性保持不变。
  • channels 一旦出现,本次提交的整个 ServiceReferenceMap 就是它的新值。要保留旧条目,必须把这些条目 一起放入本次 valueMap,不能只提交新增键并假设平台会做映射内合并。
  • 清空映射时提交 {"@type":"ServiceReferenceMap","valueMap":{}}。不要提交裸 {}、数组、 null,也不要添加 empty_editingEntries 等非协议字段。
  • 每个 serviceId 都必须是同一 Runtime 中可解析的完整 businessId。Bundle dependencies 只保证安装 闭包和顺序,不替代这里的实际属性绑定。

属性写入时 Runtime 会校验所有嵌套引用并收敛相应访问关系。任一目标无法解析或引用无法授权时,本次配置 更新会明确失败,不会只保存可用的部分。

生命周期回调收到的结构

安装时的 BEFORE_DEPLOY 或安装后修改属性触发的 ON_CONFIG_UPDATE 会保持 ServiceReferenceMap.valueMap 结构,同时把每个逻辑 ServiceReference 展开为 ExternalServiceReference

{
  "channels": {
    "@type": "ServiceReferenceMap",
    "valueMap": {
      "primary": {
        "@type": "ExternalServiceReference",
        "url": "https://<runtime-service-base>/<primaryChannelBusinessId>",
        "serviceId": "<primaryChannelBusinessId>",
        "token": "<opaque-reference-token>"
      },
      "backup": {
        "@type": "ExternalServiceReference",
        "url": "https://<runtime-service-base>/<backupChannelBusinessId>",
        "serviceId": "<backupChannelBusinessId>",
        "token": "<opaque-reference-token>"
      }
    }
  }
}

模块后端必须按整组值原子替换本地敏感配置,并通过相应条目的 urltoken 调用目标方法。不得自行 拼接 Runtime 网关地址、解析 token、绕过 Runtime 直连目标 Hosted Backend,也不得把展开后的值写回 模块属性。完整调用和请求级用户委托分别见 模块服务间调用协议Runtime 用户委托

与 Interface 和 InterfaceList 的区别

属性类型属性值选择方式
InterfaceServiceReference单个目标服务
InterfaceMapServiceReferenceMap.valueMap由调用模块定义的稳定键选择目标服务
InterfaceListServiceReferenceList.valueList按数组顺序遍历目标服务

不要因为当前只有一个目标就把 ServiceReference 塞进 InterfaceMap,也不要依赖 JSON 对象键的顺序来 表达优先级;需要有序选择时使用 InterfaceList

验证清单

  1. 当前不可变模块版本的 propertyDefinition 中存在 InterfaceMap,且字段名是 valueInterface
  2. 每个候选目标 Bundle 已安装到同一 Runtime,目标完整 businessId、方法和 paramDefinitions 已回读。
  3. properties.json 使用 ServiceReferenceMap.valueMap,每个值都是只含目标 serviceIdServiceReference
  4. 属性更新命令成功;失败时保留原错误并修正全部无效条目,不拆成部分成功或添加本地兜底。
  5. 生命周期 Endpoint 在 BEFORE_DEPLOYON_CONFIG_UPDATE 收到相同键集合,且每个值都已展开为 ExternalServiceReference;验证时不得输出 token。
  6. 模块后端按键选择引用并通过 Runtime 网关调用真实目标方法;删除或替换条目后停止使用旧引用并清除 本地副本。

本页内容