# ServiceReference 声明、绑定与运行时交付

声明 Interface 属性，通过模块属性配置绑定目标服务，并由 Runtime 管理访问关系，插件按新协议解析当前引用的访问信息凭据。

`ServiceReference` 用于把调用模块的一个 `Interface` 属性绑定到同一 Runtime 内的目标服务。
这里的“绑定”就是设置模块属性值，不存在需要开发者额外调用的服务授权接口。属性写入成功后，Runtime
会根据引用自动生成来源服务到目标服务的访问关系。插件生命周期只接收无凭据的引用描述，
业务调用前按需领取当前凭据，完整方式见[生命周期与引用协议](/development/lifecycle-plugin-development/reference-protocol/)。

> **模块属性是唯一的绑定源事实**
>
> 把 `Interface` 属性设置为 `{"@type":"ServiceReference","serviceId":"完整 businessId"}`
> 即完成绑定。Bundle `dependencies` 只确保目标 Bundle 先进入安装闭包，不设置属性，也不代替绑定。

需要用稳定业务键绑定多个同接口服务时，使用 `InterfaceMap` 属性和 `ServiceReferenceMap` 值；不要把多个
目标塞进单值 `ServiceReference`。完整声明、更新和引用描述示例见
[InterfaceMap 与 ServiceReferenceMap](/development/bundle-development/module-development/interface-map/)。

## 声明 Interface 属性

调用方模块在 `module.json` 的 `propertyDefinition` 中声明 `Interface` 类型属性。接口中的方法定义是调用方
编译期的期望契约；真正调用前仍应从目标 Runtime 服务回读当前方法和 `paramDefinitions`。

```json
{
  "propertyDefinition": [
    {
      "name": "xiaoxiangService",
      "type": {
        "@type": "Interface",
        "name": "XiaoxiangService",
        "methods": [
          {
            "name": "listManagedShops",
            "returnType": {
              "@type": "DataType",
              "type": "object",
              "nullable": false
            },
            "paramDefinitions": [
              {
                "name": "params",
                "type": {
                  "@type": "DataType",
                  "type": "object",
                  "nullable": false
                }
              }
            ]
          }
        ]
      },
      "required": true,
      "defaultValue": "{\"@type\":\"ServiceReference\",\"serviceId\":\"<targetBusinessId>\"}"
    }
  ]
}
```

`defaultValue` 中的 JSON 字符串会在模块版本编译时变成类型化属性值，因此可以在安装时直接完成默认绑定。
如果目标服务由部署环境或安装结果决定，不要把可变 `businessId` 写死在源码中；安装后使用下面的模块属性
更新命令设置实际值。

逻辑属性值固定使用：

```json
{
  "@type": "ServiceReference",
  "serviceId": "<targetBusinessId>"
}
```

`serviceId` 必须是目标服务完整的 `businessId`，不是模块名、Bundle 名、方法名、Hosted Backend 地址或
调用方自行拼接的 URL。

## 安装后手动绑定或修改

当前 CLI 提供正式的默认 Runtime 模块属性命令。先把需要部分更新的属性保存为
`properties.json`；文件只包含属性对象，不包含工作区、调用服务或接口 URL：

```json
{
  "xiaoxiangService": {
    "@type": "ServiceReference",
    "serviceId": "<targetBusinessId>"
  }
}
```

执行正式命令：

```bash
baijimu runtime app properties update \
  <callerBusinessId> \
  --workspace-id <workspaceId> \
  --properties @properties.json
```

- `<workspaceId>` 决定目标工作区，`<callerBusinessId>` 是调用模块安装后的完整服务标识。
- `--properties` 接受内联 JSON 对象或 `@文件`；这是部分更新，未出现的模块属性保持不变。
- 属性名必须已经存在于当前不可变模块版本的 `propertyDefinition` 中。该命令只改属性值，不修改属性定义。
- 目标 `serviceId` 必须在同一 Runtime 中可解析；解析或访问关系生成失败时，本次配置更新失败。
- CLI 负责平台接口路径、工作区凭据和请求结构。开发者不得改用 `baijimu api` 拼接内部路径。

设置属性就是绑定；这也是手动修改绑定的正式操作，不需要另一套“ServiceReference 授权”命令或接口。

## Runtime 自动执行的步骤

安装或属性更新会按同一个源事实收敛：

```text
依赖 Bundle 已安装
  -> 写入调用模块的 ServiceReference 属性
  -> Runtime 校验调用服务、目标服务和属性定义
  -> Runtime 自动生成或更新引用访问关系
  -> 新插件生命周期接收无 token 的 references 描述
  -> 插件在每次业务操作前按授权属性解析当前引用的访问信息凭据
  -> 当前操作通过 Runtime 网关调用目标服务
```

安装或配置更新中的校验失败会让对应操作失败；引用访问解析失败则停止当前业务操作。
开发者不需要在依赖安装与生命周期回调之间手工插入授权操作。

## 运行时交付边界

生命周期回调的 `references` 保留逻辑 `ServiceReference` 及其 Map/List 结构，不含地址或密钥。
插件保存安装定位，在业务调用前按授权属性解析当前引用。响应中的 `reference` 给出当前目标关系，
`access[serviceId]` 给出当前 Runtime 网关 `url` 和调用 `token`，只用于本次操作，不持久化。HTTP 方法的 `position: "property"` 映射不参与这条链路。
完整请求格式和 `xiaoxiangService.listManagedShops(params)` 的调用方式见
[模块服务间调用协议](/development/bundle-development/module-development/service-to-service-calls/)。

引用 token 只授权来源服务、目标服务和方法，不携带最终用户。需要代表当前用户调用时，外部后端另外转发
Runtime 在本次业务请求中注入的短期 Actor assertion；该值不是逻辑引用字段，也不通过
生命周期保存。见
[Runtime 用户委托](/development/bundle-development/module-development/actor-delegation/)。

调用模块不得：

- 在独立后端自行把逻辑 `ServiceReference` 转换为地址、推导凭据或自行拼接 Runtime 网关地址。
- 绕过 Runtime 网关，直接调用目标 Hosted Backend 的 Controller 或部署地址。
- 把生命周期请求中的操作 `userId` 保存成后续业务调用的固定最终用户身份。
- 把请求级 Actor assertion 保存到引用配置、数据库、缓存、队列或后台任务。
- 输出、记录或依赖 token 的内部格式。

## CLI 中两个历史参数

当前 `baijimu bundle module create --help` 仍显示 `--module-dependencies` 和
`--dependency-definition`，因此文档不宣称它们已从 CLI 删除。

这两个模块创建输入既不能替代 Bundle Manifest `dependencies`，也不能替代上面的模块属性设置接口。

## 验证清单

1. 依赖 Bundle 和调用 Bundle 已安装到同一 Runtime。
2. 调用模块当前版本声明了目标 `Interface` 属性。
3. 目标服务完整 `businessId` 和目标方法存在。
4. 使用 `baijimu runtime app properties update` 写入逻辑 `ServiceReference`，确认命令成功。
5. 检查插件收到当前无凭据引用描述；在业务操作前领取该属性的当前引用，验证授权与返回结构，不输出 token。
6. 调用模块后端使用本次领取的引用通过 Runtime 网关调用目标方法。
7. 修改或清除引用后，下一次操作重新解析当前引用的访问信息；撤销后不能再使用旧凭据。

不得为了验证而拼接内部网关地址、复用非公开凭据或直连目标 Hosted Backend。
