文档目录
Provider类开发

简介

本文件面向在 DouPHP 中开发“插件 Provider”的工程师,系统说明 Provider 在插件架构中的作用、接口契约、生命周期管理、事件处理模式、与 Service 层的交互方式、数据传递模式以及异常与日志的最佳实践。本项目采用“接口契约 + 具体 Provider 实现 + 注册中心自动发现 + 容器注入”的模式,将第三方登录、支付等能力以插件形式扩展,保持核心稳定、业务可插拔。

项目结构

  • 基础设施层
    • Provider 注册总线:统一在启动阶段注册各平台能力 Provider(如语言、插件查询等)。
    • 容器绑定:通过 ServiceProvider 将接口绑定到具体实现或空实现,保证调用面始终可用。
  • 插件契约层
    • 定义统一的 Provider 接口(登录、支付、轮询、对账等),约束行为与数据模型。
  • 插件实现层
    • 每个第三方能力提供一个 Provider 类,实现接口方法,内部委托给对应 Service。
  • 插件注册中心
    • 扫描 manifest.php 自动发现并实例化 Provider,缓存实例,提供 has()/provider() 等访问能力。
graph TB
subgraph "基础设施"
PR["ProviderRegistry<br/>注册总线"]
PS["PluginServiceProvider<br/>容器绑定"]
CT["Container<br/>依赖注入"]
end
subgraph "契约层"
I1["ConnectPluginProviderInterface"]
I2["PaymentPluginProviderInterface"]
I3["ReconcilablePaymentProviderInterface"]
I4["PollablePaymentProviderInterface"]
end
subgraph "实现层"
QP["QqProvider"]
GP["GoogleProvider"]
WP["WxloginProvider"]
AP["AlipayProvider"]
end
subgraph "注册中心"
R["ConnectPluginRegistry<br/>自动发现+实例缓存"]
end
PR --> PS
PS --> CT
R --> CT
QP --> I1
GP --> I1
WP --> I1
AP --> I2
I2 --> I3
I2 --> I4
R --> QP
R --> GP
R --> WP
R --> AP

核心组件

  • Provider 注册总线(ProviderRegistry)
    • 作用:在配置就绪后一次性注册所有平台能力 Provider,调用各 Provider::register(Container)。
    • 特点:轻量、无 boot 阶段,语义简单。
  • 容器绑定(PluginServiceProvider)
    • 作用:将 PluginServiceContract 绑定到真实实现或 Null 实现,确保业务调用面非空。
    • 特点:根据模块是否就绪动态选择实现,具备降级能力。
  • 插件契约(Connect/Payment/*)
    • 作用:统一抽象第三方登录、支付、轮询、对账等行为,屏蔽差异。
    • 特点:强类型 DTO 作为入参出参,便于校验与文档化。
  • 插件注册中心(ConnectPluginRegistry)
    • 作用:扫描 manifest.php 自动发现 Provider,使用容器实例化并缓存,对外提供 provider()/has()。
    • 特点:按 pluginId 索引,避免重复创建;支持运行时检查是否存在。

架构总览

Provider 在插件架构中的职责边界清晰:

  • 契约层定义最小必要能力(pluginId、meta、start/finish/notify/query/status)。
  • 实现层仅做薄封装,将请求转发给 Service,由 Service 完成复杂逻辑。
  • 注册中心负责自动发现与实例化,容器负责依赖注入。
  • 上层控制器/服务通过注册中心获取 Provider,再调用其方法,无需关心具体实现。
sequenceDiagram
participant C as "调用方(控制器/服务)"
participant R as "ConnectPluginRegistry"
participant P as "具体Provider"
participant S as "Service"
C->>R : "provider(pluginId)"
R->>R : "discover() 扫描manifest"
R->>R : "container->make(Provider)"
R-->>C : "返回Provider实例"
C->>P : "start(request)"
P->>S : "start(request)"
S-->>P : "URL/HTML"
P-->>C : "跳转地址/表单"
C->>P : "finish(payload)"
P->>S : "finish(payload)"
S-->>P : "业务跳转URL"
P-->>C : "最终跳转"

详细组件分析

第三方登录 Provider(Connect)

  • 契约要点
    • pluginId:唯一标识,对应插件 slug。
    • meta:元信息,用于后台展示与配置 schema。
    • start:发起授权,返回授权页跳转 URL。
    • finish:处理回跳,返回业务落地页 URL。
  • 典型实现
    • QQ、微信、Google 登录 Provider 均遵循同一契约,内部委托各自 Service 完成协议细节。
  • 生命周期
    • 构造时注入 Service;start/finish 为请求级生命周期,不持有状态。
  • 事件处理
    • 回调由框架路由到 finish,Provider 解析 payload 并交由 Service 处理。
classDiagram
class ConnectPluginProviderInterface {
+pluginId() string
+meta() array
+start(request) string
+finish(payload) string
}
class QqProvider {
-service
+__construct(service)
+pluginId() string
+meta() array
+start(request) string
+finish(payload) string
}
class GoogleProvider {
-service
+__construct(service)
+pluginId() string
+meta() array
+start(request) string
+finish(payload) string
}
class WxloginProvider {
-service
+__construct(service)
+pluginId() string
+meta() array
+start(request) string
+finish(payload) string
}
ConnectPluginProviderInterface <|.. QqProvider
ConnectPluginProviderInterface <|.. GoogleProvider
ConnectPluginProviderInterface <|.. WxloginProvider

支付 Provider(Payment)

  • 基础契约
    • pluginId、meta、start、notify、finish。
  • 扩展能力
    • ReconcilablePaymentProviderInterface:支持主动对账(query)。
    • PollablePaymentProviderInterface:支持前端轮询状态(status),适用于扫码支付场景。
  • 典型实现
    • 支付宝 Provider 实现了基础支付契约,并额外实现对账能力。
classDiagram
class PaymentPluginProviderInterface {
+pluginId() string
+meta() array
+start(request) string
+notify(payload) string
+finish(payload) string
}
class ReconcilablePaymentProviderInterface {
+query(request) PaymentQueryResult
}
class PollablePaymentProviderInterface {
+status(payload) string
}
class AlipayProvider {
-service
+pluginId() string
+meta() array
+start(request) string
+notify(payload) string
+finish(payload) string
+query(request) PaymentQueryResult
}
PaymentPluginProviderInterface <|-- ReconcilablePaymentProviderInterface
PaymentPluginProviderInterface <|-- PollablePaymentProviderInterface
ReconcilablePaymentProviderInterface <|.. AlipayProvider

自动发现与实例化流程

  • 启动阶段
    • ProviderRegistry 依次调用各 Provider::register(Container),完成容器绑定。
  • 运行阶段
    • ConnectPluginRegistry 构造函数中执行 discover(),扫描 PLUGIN_PATH 下各插件的 manifest.php,建立 pluginId => providerClass 映射。
    • 首次 provider(pluginId) 时通过 Container 实例化 Provider,并缓存实例;后续直接复用。
    • has(pluginId) 用于判断某插件是否可用。
flowchart TD
Start(["应用启动"]) --> RegAll["ProviderRegistry.registerAll()"]
RegAll --> Bind["各ServiceProvider.register(Container)"]
Bind --> Ready{"插件模块就绪?"}
Ready -- 是 --> UseReal["绑定真实实现"]
Ready -- 否 --> UseNull["绑定Null实现"]
UseReal --> Run["运行期"]
UseNull --> Run
Run --> Discover["ConnectPluginRegistry.discover()"]
Discover --> Map["构建 pluginId -> Class 映射"]
Map --> GetProv["provider(pluginId)"]
GetProv --> Make["Container->make(Provider)"]
Make --> Cache["缓存实例"]
Cache --> Return["返回Provider"]

依赖关系分析

  • 松耦合
    • 上层仅依赖契约与注册中心,不感知具体 Provider 实现。
  • 内聚性
    • Provider 只做薄封装,业务逻辑集中在 Service,提升内聚与可测试性。
  • 外部依赖
    • 容器(Container)负责依赖注入与实例缓存。
    • 文件系统(扫描 manifest.php)用于自动发现。
  • 潜在风险
    • 若 manifest 配置错误或缺失,discover 会跳过该插件,不会中断整体流程。
    • 未实现的接口方法会在运行时抛出异常,需通过单元测试覆盖。
graph LR
A["调用方"] --> B["ConnectPluginRegistry"]
B --> C["Container"]
C --> D["QqProvider/GoogleProvider/WxloginProvider/AlipayProvider"]
D --> E["对应Service"]

性能与可扩展性

  • 性能
    • 实例缓存:ConnectPluginRegistry 对 Provider 实例进行缓存,避免重复构造。
    • 懒加载:仅在需要时通过 Container 实例化 Provider。
  • 可扩展
    • 新增插件只需实现对应接口并在 manifest.php 声明,即可被自动发现。
    • 通过实现不同接口组合(如同时实现 Reconcilable 与 Pollable)扩展能力。
  • 建议
    • 保持 Provider 轻量,复杂逻辑下沉至 Service。
    • 使用 DTO 明确输入输出,减少参数歧义。
    • 对耗时操作(网络 IO)考虑异步或超时控制。

故障排查指南

  • 常见问题
    • 插件未生效:检查 manifest.php 是否存在且格式正确;确认 registerAll 已调用。
    • 无法获取 Provider:确认 pluginId 与 manifest 一致;检查 Container 是否正确注入。
    • 回调失败:核对 notify/finish 的参数结构与签名;检查 Service 内部异常与日志。
  • 定位步骤
    • 使用 has(pluginId) 快速判断插件是否被发现。
    • 在 Provider 的 start/finish/notify 入口记录关键参数与返回值。
    • 在 Service 层捕获异常并记录上下文,必要时返回友好错误码。
  • 恢复策略
    • 对于第三方不可用,优先降级(如切换备用通道或提示用户重试)。
    • 对幂等回调(notify)增加去重与重试机制。

结论

DouPHP 的 Provider 体系通过清晰的契约、自动发现与容器注入,实现了插件能力的解耦与扩展。开发者只需关注接口契约与 Service 实现,即可快速接入第三方登录与支付能力。配合注册中心的实例缓存与降级策略,系统在稳定性与性能之间取得良好平衡。

附录:实现清单与最佳实践

  • 必须实现的方法
    • 登录 Provider:pluginId、meta、start、finish。
    • 支付 Provider:pluginId、meta、start、notify、finish;可选 query、status。
  • 推荐实践
    • 构造函数仅做依赖注入,不在其中执行 IO。
    • 使用 DTO 作为方法参数与返回值,增强可读性与可维护性。
    • 在 Service 层集中处理业务逻辑与异常,Provider 保持薄封装。
    • 对敏感配置(密钥等)通过 meta.config 暴露字段,由后台统一管理。
    • 对第三方调用设置超时与重试,避免阻塞主流程。
    • 记录结构化日志,包含请求 ID、插件 ID、关键参数摘要与结果。
  • 示例参考路径
    • 登录 Provider:QQ、微信、Google。
    • 支付 Provider:支付宝(含对账)。
    • 注册与绑定:ProviderRegistry、PluginServiceProvider。
    • 自动发现:ConnectPluginRegistry。
添加日期:2026-10-05