
CMS后端前端【免费下载链接】webiny-jsOpen-source, self-hosted CMS platform on AWS serverless (Lambda, DynamoDB, S3). TypeScript framework with multi-tenancy, lifecycle hooks, GraphQL API, and AI-assisted development via MCP server. Built for developers at large organizations.项目地址https://gitcode.com/gh_mirrors/we/webiny-js点击查看免费下载本篇技术指南以 Webiny 仓库中的内部实施计划 docs/.bruno/plans/2026-07-27-ddb-storage-ops-direct-di.md 为骨架完整还原webiny/api-headless-cms-ddb存储操作层从工厂模式迁移到直接 DI 注册的架构改造表与实体抽象化、Group/Model 操作类化、Entry 操作 per-request 注册器化并最终消灭StorageOperationsFactory与beforeInit。读完本文你将掌握 Webiny 的webiny/di容器与webiny/feature/api三者createAbstraction/createImplementation/createFeature的配合范式、请求作用域与单例作用域的取舍逻辑以及一个 1421 行工厂如何被拆解为 22 个按方法划分的 DI 类的完整路径。一、背景为什么工厂模式要被替换在重构之前api-headless-cms-ddb的存储操作通过一个巨型工厂装配其运行时流程如下HeadlessCmsDdbFeature.register(container) → 注册 DynamoDbStorageOperationsFactory一个 DI 类 HeadlessCmsFeature.register(container, config) → 请求时 → storageOperations container.resolve(StorageOperationsFactory).create(context) → storageOperations.beforeInit(context) // 手动清空 data loaders → registerCmsStorageOperations(container, { groups: storageOperations.groups, ... })这套流程存在三个结构性问题工厂承担了过多的装配职责它同时创建 groups、models、entries 三类存储操作消费者无法按需只取其一beforeInit是手工生命周期管理需要显式清空 DataLoader 缓存属于容器模型与请求模型不匹配的补丁Group/Model/Entry 被捆死在同一工厂返回的同一个对象树中无法获得精确的依赖粒度。计划的核心判断是基础设施表、实体和 Group/Model 操作都没有请求级依赖理应成为应用级app-scoped单例只有 Entry 操作依赖请求级状态CmsStorageModelProvider、StorageTransformRegistry必须走 per-request 注册路径。二、目标架构Container-per-request 消除 beforeInit目标流程如下HeadlessCmsDdbFeature.register(rootContainer) → 创建 table entities 作为 DI 实例app-scoped → 注册 DdbGroupStorageOperations → GroupStorageOperations单例app-scoped → 注册 DdbModelStorageOperations → ModelStorageOperations单例app-scoped → 注册 DdbCmsEntryStorageOpsRegistrar → CmsEntryStorageOpsRegistrar HeadlessCmsFeature.register(requestContainer, config) → groups/models 已在容器中继承自 root → const registrar container.resolve(CmsEntryStorageOpsRegistrar) → registrar.register(requestContainer) // 用请求级依赖创建 entry ops → 没有 StorageOperationsFactory没有 beforeInit关键设计决策是容器按请求重建container-per-request时单例天然等于每请求一个实例因此 DataLoader 缓存随请求自然获得新鲜度beforeInit这个手工清空动作就没有存在必要了。为什么 entries 不能做成 app-scoped计划文档给出了精确定位createEntriesStorageOperations捕获了容器引用并从中懒解析CmsStorageModelProvider和StorageTransformRegistry而这两者注册在请求容器上。DI 的解析方向是子→父child→parentroot 作用域的 entry ops 看不到子容器请求容器上新增的注册。因此 Entry 操作必须通过一个轻量的CmsEntryStorageOpsRegistrar抽象由适配器在 feature 注册时挂上实现再由HeadlessCmsFeature在每个请求里调用registrar.register(requestContainer)把 22 个 entry 抽象逐个接好。三、全局约束Global Constraints重构过程必须遵守以下约定这也是 Webiny DI 化代码风格的一部分一个文件一个抽象 / 一个文件一个实现one abstraction per file, one implementation per file实现文件用类名命名导出名与抽象名一致同名namespace导出Interface类型只导出外部消费者需要的内容dependencies 数组的顺序必须与构造函数参数顺序一致。这些约束在落地后的源码中都能一一对上例如 CmsDdbGroupEntity.ts 与 CreateEntryStorageOperation.ts 都采用了export const Xxx createAbstractionInterface(...)export namespace Xxx { export type Interface ... }的成对模式。四、Task 1创建 DDB 基础设施抽象infrastructure abstractions产出文件位于packages/api-headless-cms-ddb/src/abstractions/文件抽象底层类型CmsDdbTable.tsCmsDdbTableITable来自webiny/db-dynamodbCmsDdbGroupEntity.tsCmsDdbGroupEntityIGroupEntityCmsDdbModelEntity.tsCmsDdbModelEntityIModelEntityCmsDdbEntryEntity.tsCmsDdbEntryEntityIEntryEntity表抽象的典型写法落地源码与计划完全一致// packages/api-headless-cms-ddb/src/abstractions/CmsDdbTable.ts import { createAbstraction } from webiny/feature/api; import type { ITable } from webiny/db-dynamodb; export const CmsDdbTable createAbstractionITable(Cms/Ddb/Table); export namespace CmsDdbTable { export type Interface ITable; }实体抽象与之同构// packages/api-headless-cms-ddb/src/abstractions/CmsDdbGroupEntity.ts import { createAbstraction } from webiny/feature/api; import type { IGroupEntity } from ~/definitions/types.js; export const CmsDdbGroupEntity createAbstractionIGroupEntity(Cms/Ddb/GroupEntity); export namespace CmsDdbGroupEntity { export type Interface IGroupEntity; }CmsDdbModelEntityIModelEntity与CmsDdbEntryEntityIEntryEntity完全套用同一模式。这些抽象是后续所有 DDB 操作的挂钩点操作类通过构造函数注入实体抽象从而与具体的 DynamoDB 表结构解耦。提交git add packages/api-headless-cms-ddb/src/abstractions/ git commit -m feat(api-headless-cms-ddb): add DDB infrastructure DI abstractions五、Task 2DdbGroupStorageOperations DI 实现将createGroupsStorageOperations函数转换为正式的 DI 类。消费CmsDdbGroupEntity与FilterUtil来自webiny/db-dynamodb产出GroupStorageOperations抽象的实现。计划中的实现骨架// packages/api-headless-cms-ddb/src/operations/group/DdbGroupStorageOperations.ts import { createImplementation } from webiny/feature/api; import { GroupStorageOperations } from webiny/api-headless-cms/features/shared/storageOperations/GroupStorageOperations.js; import { CmsDdbGroupEntity } from ~/abstractions/CmsDdbGroupEntity.js; import { FilterUtil } from webiny/db-dynamodb/feature/FilterUtil/index.js; import type { CmsGroup, CmsGroupStorageOperations, /* ... */ } from webiny/api-headless-cms/types/index.js; // Key helpers沿用现有实现createPartitionKey、createSortKeys、createKeys、createType ... class DdbGroupStorageOperationsImpl implements CmsGroupStorageOperations { private readonly entity: IGroupEntity; private readonly filterUtil: FilterUtil.Interface; constructor(entity: CmsDdbGroupEntity.Interface, filterUtil: FilterUtil.Interface) { this.entity entity; this.filterUtil filterUtil; } async get(params: CmsGroupStorageOperationsGetParams): PromiseCmsGroup | null { // 与原 createGroupsStorageOperations.get 相同逻辑 } // list / create / update / delete 同理 } export const DdbGroupStorageOperations createImplementation({ abstraction: GroupStorageOperations, implementation: DdbGroupStorageOperationsImpl, dependencies: [CmsDdbGroupEntity, FilterUtil] });值得注意的实现细节所有 key 生成辅助函数createPartitionKey、createKeys等以私有方法或模块级函数的形式留在同一文件内不做无谓的跨文件拆分。从落地后的源码看这一任务最终演进为按方法拆分的形态operations/group/目录下出现了 DdbGetGroup.ts、DdbListGroups、DdbCreateGroup、DdbUpdateGroup、DdbDeleteGroup五个类由 operations/group/feature.ts 统一注册。以DdbGetGroup为例它实现GetGroupStorageOperation.Interface仅注入CmsDdbGroupEntityclass DdbGetGroupImpl implements GetGroupStorageOperation.Interface { constructor(private entity: CmsDdbGroupEntity.Interface) {} async execute(params: CmsGroupStorageOperationsGetParams) { const keys createKeys(params); try { const result await this.entity.get(keys); return result?.data || null; } catch (ex) { throw new WebinyError(ex.message || Could not get group., ex.code || GET_GROUP_ERROR, { error: ex, ...params, keys }); } } } export const DdbGetGroup GetGroupStorageOperation.createImplementation({ implementation: DdbGetGroupImpl, dependencies: [CmsDdbGroupEntity] });从源码结构看createAbstraction返回的抽象对象自带createImplementation({ implementation, dependencies })静态方法这是计划中全局函数形式createImplementation({ abstraction, implementation, dependencies })在落地时的同构演进抽象即实现目标的载体。提交git add packages/api-headless-cms-ddb/src/operations/group/DdbGroupStorageOperations.ts git commit -m feat(api-headless-cms-ddb): add DdbGroupStorageOperations DI implementation六、Task 3DdbModelStorageOperations DI 实现与 Task 2 完全同构唯一差异是模型操作不需要FilterUtilDDB 模型操作不做客户端过滤依赖数组里只有实体export const DdbModelStorageOperations createImplementation({ abstraction: ModelStorageOperations, implementation: DdbModelStorageOperationsImpl, dependencies: [CmsDdbModelEntity] });对应文件为packages/api-headless-cms-ddb/src/operations/model/DdbModelStorageOperations.ts。落地后同样拆分为DdbCreateModel、DdbDeleteModel、DdbGetModel、DdbListModels、DdbUpdateModel五个类由 operations/model/feature.ts 注册。依赖面的对比小结Group 操作 实体 FilterUtil服务端过滤Model 操作 仅实体Entry 操作 实体 请求级状态 若干 filter/sort registry见下文 Task 4 与演进。这直接对应了各自的数据访问方式差异。七、Task 4CmsEntryStorageOpsRegistrar 抽象 DDB 实现Entry 操作需要请求级依赖CmsStorageModelProvider、StorageTransformRegistry不能在 feature 注册时root 容器创建。因此方案是核心包定义抽象适配器注册一个轻量 registrarHeadlessCmsFeature每请求调用一次。第一步在 api-headless-cms 中创建抽象文件packages/api-headless-cms/src/features/shared/storageOperations/CmsEntryStorageOpsRegistrar.tsimport { createAbstraction } from webiny/feature/api; import type { Container } from webiny/di; export interface ICmsEntryStorageOpsRegistrar { register(container: Container): void; } export const CmsEntryStorageOpsRegistrar createAbstractionICmsEntryStorageOpsRegistrar(Cms/EntryStorageOpsRegistrar); export namespace CmsEntryStorageOpsRegistrar { export type Interface ICmsEntryStorageOpsRegistrar; }第二步registerCmsEntryStorageOperations 辅助函数文件packages/api-headless-cms/src/features/shared/storageOperations/registerCmsEntryStorageOperations.ts该函数接收一个Container与一个CmsEntryStorageOperations对象既有接口把每个方法包装为{ execute: ... }形式并注册全部22 个 entry 抽象——即从原registerCmsStorageOperations的 entries 部分抽取而来export const registerCmsEntryStorageOperations ( container: Container, entries: CmsEntryStorageOperations ): void { container.registerInstance(CreateEntryStorageOperation, { execute: entries.create }); container.registerInstance(CreateEntryRevisionFromStorageOperation, { execute: entries.createRevisionFrom }); // ... 全部 22 个注册 ... };同时在packages/api-headless-cms/src/features/shared/storageOperations/index.tsbarrel 与packages/api-headless-cms/src/exports/api/cms/storage.ts中 re-export。第三步DDB 实现文件packages/api-headless-cms-ddb/src/DdbCmsEntryStorageOpsRegistrar.tsimport { createImplementation } from webiny/feature/api; import { CmsEntryStorageOpsRegistrar } from webiny/api-headless-cms/features/shared/storageOperations/CmsEntryStorageOpsRegistrar.js; import { CmsDdbEntryEntity } from ~/abstractions/CmsDdbEntryEntity.js; import { registerCmsEntryStorageOperations } from webiny/api-headless-cms/features/shared/storageOperations/registerCmsEntryStorageOperations.js; import { createEntriesStorageOperations } from ./operations/entry/index.js; import type { Container } from webiny/di; import type { IEntryEntity } from ~/definitions/types.js; class DdbCmsEntryStorageOpsRegistrarImpl implements CmsEntryStorageOpsRegistrar.Interface { constructor(private entryEntity: CmsDdbEntryEntity.Interface) {} register(container: Container): void { const entries createEntriesStorageOperations({ entity: this.entryEntity, container }); registerCmsEntryStorageOperations(container, entries); } } export const DdbCmsEntryStorageOpsRegistrar createImplementation({ abstraction: CmsEntryStorageOpsRegistrar, implementation: DdbCmsEntryStorageOpsRegistrarImpl, dependencies: [CmsDdbEntryEntity] });注意 registrar 的职责边界它只负责在请求时把createEntriesStorageOperations仍是一个工厂函数的结果逐个注册为 22 个 entry 抽象把 entry 操作改造成 per-method DI 类不在本计划范围内见Whats NOT in scope。提交git add packages/api-headless-cms/src/features/shared/storageOperations/CmsEntryStorageOpsRegistrar.ts git add packages/api-headless-cms/src/features/shared/storageOperations/registerCmsEntryStorageOperations.ts git add packages/api-headless-cms/src/features/shared/storageOperations/index.ts git add packages/api-headless-cms/src/exports/api/cms/storage.ts git add packages/api-headless-cms-ddb/src/DdbCmsEntryStorageOpsRegistrar.ts git commit -m feat(api-headless-cms, api-headless-cms-ddb): add entry storage ops registrar八、Task 5重写 HeadlessCmsDdbFeature 直接注册修改文件packages/api-headless-cms-ddb/src/index.ts。重写后的 feature 不再注册任何工厂而是在注册期直接完成全部基础设施与操作装配import { FilterUtilFeature } from webiny/db-dynamodb/feature/FilterUtil/feature.js; export const HeadlessCmsDdbFeature createFeature({ name: cms.storageOperations.ddb, register: container { FilterRegistriesFeature.register(container); FilterUtilFeature.register(container); const db container.resolve(DynamoDBClient); const documentClient db.client; const tableInstance createTable({ documentClient }); // 注册基础设施实例app-scoped container.registerInstance(CmsDdbTable, tableInstance); container.registerInstance(CmsDdbGroupEntity, createGroupEntity({ entityName: ENTITIES.GROUPS, table: tableInstance })); container.registerInstance(CmsDdbModelEntity, createModelEntity({ entityName: ENTITIES.MODELS, table: tableInstance })); container.registerInstance(CmsDdbEntryEntity, createEntryEntity({ entityName: ENTITIES.ENTRIES, table: tableInstance })); // Group modelDI 类app-scoped 单例 container.register(DdbGroupStorageOperations).inSingletonScope(); container.register(DdbModelStorageOperations).inSingletonScope(); // Entry registrarapp-scoped由 HeadlessCmsFeature 每请求调用 container.register(DdbCmsEntryStorageOpsRegistrar).inSingletonScope(); } });同时删除DynamoDbStorageOperationsFactoryImpl、DynamoDbStorageOperationsFactory、createDynamoDbStorageOperations保留registerDynamoDbStorageOperationsdeprecated 包装器并更新为调用新 feature该包装器在后续2026-07-28的清理中被彻底删除见下文演进。落地后的 api-headless-cms-ddb/src/index.ts 与计划高度一致HeadlessCmsDdbFeature先注册FilterRegistriesFeature与FilterUtilFeature从容器解析DynamoDBClient取client用createTable({ documentClient })建表实例随后registerInstance四个基础设施抽象最后依次注册三个 ops featuregroup/model/entry。差异点在于 entry 部分最终改由DdbEntryStorageOpsFeature直接注册 22 个类且另有一个HeadlessCmsDdbRequestFeature见 requestFeature.ts负责 per-request 的 DataLoader 装配——这正是container-per-request → 单例即请求级设计的落地形态// packages/api-headless-cms-ddb/src/operations/entry/requestFeature.ts export const HeadlessCmsDdbRequestFeature createFeature({ name: cms.storageOperations.ddb.request, register: container { container.register(DataLoadersHandler).inSingletonScope(); } });该文件注释精确说明了理由DataLoader 缓存只能存活一个请求root 单例跨请求存活会一直返回它首次读到的条目entry 操作留在 root从解析它们的容器里解析这个依赖于是每个请求拿到自己的 loader。对应实现见 dataLoaders.ts 中的DataLoadersHandlerImpl内部持有DataLoaderCache通过CmsDdbDataLoaders.createImplementation绑定到CmsDdbEntryEntity。提交git add packages/api-headless-cms-ddb/src/ git commit -m refactor(api-headless-cms-ddb): register storage operations directly via DI九、Task 6在 HeadlessCmsFeature 中以 registrar 替换 StorageOperationsFactory修改文件packages/api-headless-cms/src/HeadlessCmsFeature.tspackages/api-headless-cms/src/features/shared/abstractions.ts— 移除StorageOperationsFactorypackages/api-headless-cms/src/exports/api/cms/storage.ts— 移除StorageOperationsFactoryre-exportpackages/api-headless-cms/src/types/types.ts— 从HeadlessCms接口中移除storageOperations字段替换工厂调用将HeadlessCmsFeature.register中大约 219–258 行的工厂流程// REMOVE: const storageOperations container.resolve(StorageOperationsFactory).create(cmsContext); storageOperations.beforeInit(cmsContext); registerCmsStorageOperations(container, { ... });替换为// REPLACE WITH: const entryRegistrar container.resolve(CmsEntryStorageOpsRegistrar); entryRegistrar.register(container);groups/models 已在容器中继承自 root、由适配器 feature 注册只有 entry 抽象需要 per-request 注册。移除 facade 上的 storageOperationsHeadlessCmsFeature约 300 行处构建 facade 的storageOperations字段一并删除types.ts中HeadlessCms接口同步移除该字段。计划明确说明只有测试使用context.cms.storageOperations应改为从容器解析各 per-method 抽象该测试迁移在计划的 scope 内进行context.cms.storageOperations的测试清理被标记为独立后续工作。清理共享抽象在features/shared/abstractions.ts删除StorageOperationsFactory抽象及其 namespace、IHeadlessCmsStorageOperationsFactory接口在exports/api/cms/storage.ts删除 re-export同时从HeadlessCmsFeature配置接口约 91 行移除storageOperations?: IHeadlessCmsStorageOperationsFactoryany配置项。构建与测试yarn build -p webiny/api-headless-cms 21 | tail -30 yarn build -p webiny/api-headless-cms-ddb 21 | tail -30 yarn test packages/api-headless-cms 21 | tail -50提交git add packages/api-headless-cms/ git commit -m refactor(api-headless-cms): remove StorageOperationsFactory, storage ops pre-registered by adapter十、Task 7清理死代码packages/api-headless-cms-ddb/src/types.ts— 移除StorageOperationsFactory、HeadlessCmsStorageOperations含getTable/getEntities与StorageOperationsFactoryParams删除或掏空packages/api-headless-cms-ddb/src/operations/group/index.ts中旧的createGroupsStorageOperations删除或掏空packages/api-headless-cms-ddb/src/operations/model/index.ts中旧的createModelsStorageOperations。git commit -m chore(api-headless-cms-ddb): remove dead factory code and types十一、任务依赖关系Task 1: 独立基础设施抽象 Task 2: 依赖 Task 1需要 CmsDdbGroupEntity Task 3: 依赖 Task 1需要 CmsDdbModelEntity Task 4: 依赖 Task 1需要 CmsDdbEntryEntity—— 创建 registrar 抽象 DDB 实现 Task 5: 依赖 Task 1-4重写 HeadlessCmsDdbFeature Task 6: 依赖 Task 5在 HeadlessCmsFeature 中用 registrar 替换工厂 Task 7: 依赖 Task 6死代码清理Task 1 是唯一独立任务其余任务按链式顺序推进Task 5 是粘合层把前 4 个任务的成果接入 feature 注册期Task 6 是用户侧切换Task 7 是收尾。十二、范围外事项Whats NOT in scope计划明确划出边界避免一次改动过大Entry 操作不转换为 per-method DI 类未来事项——entries 保持createEntriesStorageOperations函数形态由 registrar 包装其他适配器ddb-es、sql、pg-os不在此计划内——各自在 DDB 验证模式后单独出计划不删除types.ts中的HeadlessCmsStorageOperations接口——需要所有适配器迁移完成后才能移除不从测试中移除context.cms.storageOperations——属于独立清理测试应改为从容器解析各 per-method 抽象。十三、实施结果与源码级佐证该计划在bruno/refactor/api-headless-cms-storage-ops分支上执行随后又经历了两个后续阶段。结合 docs/.bruno/handoff/ 目录下的交接文档可以完整还原整个演进链条1. 计划落地handoff2026-07-27-storage-ops-di-split.md2026-07-27-storage-ops-di-split.md 记录了两个计划共 21 个 commit、86 个文件变更的落地情况先完成 per-method 存储操作抽象拆分GroupStorageOperations、ModelStorageOperations 22 个 per-method entry 抽象再完成 DDB 直接 DI 注册。关键决策包括groups/models 各一个抽象面小entry 按方法一个抽象共 22 个换取最大粒度beforeInit被消除——container-per-request 使单例等于请求级DataLoader 每请求自动新鲜storageOperations字段改为可选 deprecated测试迁移到从容器解析各抽象遗留回退HeadlessCmsFeature先尝试CmsEntryStorageOpsRegistrar对未迁移的适配器ddb-es、sql、pg-os回退到StorageOperationsFactory用窄 try/catch 避免掩盖错误StorageOperationsFactory保留并标注deprecated——因为 ddb-es、sql、pg-os 仍在使用。2. 演进一per-method 全量 DIhandoff2026-07-27-storage-ops-per-method-di.md2026-07-27-storage-ops-per-method-di.md 记录了把迁移推广到全部 4 个适配器DDB、DDB-ES、SQL、PG-OS的完整过程43 个 commit、193 个文件并把 DDB 的 1421 行单块工厂拆解为 22 个独立 DI 类DataLoadersHandler转为正式 DI 实现DdbEntryStorageOpsFeature在 app 作用域注册全部 22 个操作。这正是我们在 operations/entry/feature.ts 中看到的 22 个container.register(DdbXxx)调用。同时CmsEntryStorageOpsRegistrar、registerCmsEntryStorageOperations、registerCmsStorageOperations、StorageOperationsFactory均被删除——中间态registrar完成了它的历史使命。以依赖最复杂的 DdbListEntries.ts 为例可见 per-method 类如何精准声明依赖class DdbListEntriesImpl implements ListEntriesStorageOperation.Interface { constructor( private entity: CmsDdbEntryEntity.Interface, private storageModelProvider: CmsStorageModelProvider.Interface, private storageTransformRegistry: StorageTransformRegistry.Interface, private pathRegistry: FieldFilterPathRegistry.Interface, private transformRegistry: FieldFilterValueTransformRegistry.Interface, private filterCreateRegistry: FieldFilterCreateRegistry.Interface, private sortingRegistry: FieldSortingRegistry.Interface, private valueFilterRegistry: ValueFilterRegistry.Interface ) {} // ... } export const DdbListEntries ListEntriesStorageOperation.createImplementation({ implementation: DdbListEntriesImpl, dependencies: [ CmsDdbEntryEntity, CmsStorageModelProvider, StorageTransformRegistry, FieldFilterPathRegistry, FieldFilterValueTransformRegistry, FieldFilterCreateRegistry, FieldSortingRegistry, ValueFilterRegistry ] });dependencies 数组与构造函数参数顺序严格一一对应——这正是全局约束第 4 条的直接体现。而 DdbGetEntry.ts 则展示了 per-method 类之间如何相互组合DdbGetEntry注入ListEntriesStorageOperation通过limit: 1 的 list实现 get 语义。3. 演进二移除 deprecated 包装器handoff2026-07-28-deprecated-wrappers-removal.md2026-07-28-deprecated-wrappers-removal.md 记录了清理阶段删除 3 个 deprecated 的register*StorageOperations包装函数registerDynamoDbStorageOperations、registerCmsOpenSearchStorageOperations、registerSqlStorageOperations4 个调用方全部改为直接使用HeadlessCmsDdbFeature、HeadlessCmsDdbEsFeature、HeadlessCmsSqlFeature。至此生产代码中不再残留任何 legacy 存储操作模式。4. 最终形态的关键源码位置关注点源码位置DDB feature 装配入口api-headless-cms-ddb/src/index.ts基础设施抽象api-headless-cms-ddb/src/abstractions/Group 操作注册operations/group/feature.tsModel 操作注册operations/model/feature.tsEntry 操作注册22 个类operations/entry/feature.tsper-request DataLoader 装配operations/entry/requestFeature.ts每方法抽象定义22 个 entry 5 group 5 modelfeatures/shared/storageOperations/核心 feature仅注册 StorageFeature无工厂HeadlessCmsFeature.ts从 HeadlessCmsFeature.ts 的当前源码看register中已没有任何StorageOperationsFactory解析或beforeInit调用存储装配完全由各适配器 feature 自行负责——这正是本计划适配器拥有装配权目标的终态。十四、模式总结这套 DI 范式可以怎么迁移到其他适配器以 DDB 为样板计划明确后续每个适配器ddb-es、sql、pg-os各自出计划、套用同一模式基础设施抽象化为表 / 实体创建createAbstractionGroup/Model 操作类化每个方法一个实现类createImplementation绑定抽象依赖仅实体 需要时的 FilterUtil 等 app-scoped 服务Entry 操作 per-request 化要么走 registrar 中间态要么演进后直接把 per-method 类注册为 app-scoped 单例把 DataLoader 等请求级状态放进 per-request 注册的inSingletonScope()实现中依赖顺序纪律dependencies 数组与构造参数严格同序保证容器装配正确性。这套模式的核心收益可以归结为三点消除手工生命周期方法beforeInit、依赖粒度精确到方法级、装配责任完全归属适配器——而这一切都是通过 Webiny 自身webiny/diwebiny/feature/api原生的容器与 feature 机制完成的没有引入任何额外框架。赞分享CMS后端前端【免费下载链接】webiny-jsOpen-source, self-hosted CMS platform on AWS serverless (Lambda, DynamoDB, S3). TypeScript framework with multi-tenancy, lifecycle hooks, GraphQL API, and AI-assisted development via MCP server. Built for developers at large organizations.项目地址https://gitcode.com/gh_mirrors/we/webiny-js点击查看免费下载相关推荐Webiny CMS 存储操作全量 DI 迁移实录api-headless-cms 四大适配器的按方法注入重构Webiny CMS 存储操作全量 DI 迁移实录api headless cms 四大适配器的按方法注入重构 导读 本文基于 Webiny 开源仓库中 doCMS后端前端Webiny Headless CMS 过滤器注册表 DI 重构以依赖注入替代 PluginsContainer 透传Webiny Headless CMS 过滤器注册表 DI 重构以依赖注入替代 PluginsContainer 透传 Webinywebiny js在其CMS后端前端Webiny Headless CMS 的 OpenSearch 工具层 DI 抽取实践深入解析 webiny/api-headless-cms-utils-os 模块重构Webiny Headless CMS 的 OpenSearch 工具层 DI 抽取实践深入解析 webiny/api headless cms utilsCMS后端前端上一篇Whisky 上手全指南Apple Silicon Mac 免费运行 Windows 软件5 分钟跑通第一个 exe下一篇3 步搞定 QQ 聊天记录数据库解密全平台密钥提取、修复与迁移完整教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考