如何将一个庞大的单体应用拆分成多个可通过 Composer 管理的独立包?

18次阅读

拆单体应用为composer包的核心是识别边界、解耦依赖、标准化发布:先静态分析划定高内聚模块,抽离接口、消除隐式依赖,再构建符合PSR-4的独立包结构,通过私有Packagist管理版本,实现平滑迁移与契约保障。

如何将一个庞大的单体应用拆分成多个可通过 Composer 管理的独立包?

把一个庞大的单体应用拆成多个可通过 Composer 管理的独立包,核心是“识别边界、解耦依赖、标准化发布”。不是简单切文件,而是围绕业务能力或技术职责划分出高内聚、低耦合的组件,并让它们能像第三方包一样被 require、更新和维护。

先梳理和划定包的边界

别一上来就建 git 仓库。先在现有代码里做静态分析和领域建模:

  • 找出反复出现、逻辑自洽、不依赖太多上下文的模块,比如「用户认证」、「订单状态机」、「通知渠道抽象层」、「excel 导出工具集」
  • 检查这些模块是否已有隐式依赖(比如直接 new 了 appModelsXXX 或调用了 config(‘app.debug’));有就得先抽离接口、注入依赖、移除 laravel Facade 直接调用
  • Interface-first 思路:先定义 Contracts(如 NotificationSenderInterface),再把实现留在主应用或新包里,便于后续替换

创建可被 Composer 加载的包结构

每个包本质是一个符合 PSR-4 自动加载规范的 php 项目,目录结构要干净:

  • 根目录放 composer.json(必须含 name、type、autoload、require)
  • src/ 下放核心代码,建议按功能分命名空间,如 MyCompanyNotificationchannelWechat
  • tests/ 和 README.md 是标配,方便后续 CI 和协作
  • type 推荐设为 library(不是 laravel-package),避免被 Laravel 自动发现机制干扰,由你显式注册服务提供者

处理依赖与版本管理

包之间、包与主应用之间不能靠相对路径或硬编码引用:

  • 所有包统一发布到私有 Packagist(如 Satis、private Packagist)或 github/gitlab(用 dist-type + version tags)
  • 主应用的 composer.json 中用 “mycompany/auth”: “^2.0” 替代 require_once ‘../packages/auth/src/AuthManager.php
  • 包内部尽量只依赖 PHP 标准库或稳定抽象(如 psr/log、psr/http-client),避免锁死 Laravel 版本;若必须依赖,用 ^10.0 这类宽松约束,并在测试中覆盖多版本

平滑迁移与持续集成

拆包不是一次性动作,要支持边运行边重构

  • 第一步:把代码复制进新包,同时在原位置保留兼容层(如 class_alias 或代理类),保证旧调用不崩
  • 第二步:逐步将主应用中的 use 语句和 new 实例切换到新包的命名空间
  • 第三步:CI 流程中加入包的单元测试、PHPStan 分析、以及主应用对包的集成测试,确保每次提交都验证契约不变

基本上就这些。关键不是快,而是稳——每个包上线前,它应该能单独跑通测试、能被另一个全新 Laravel 项目 require 并用起来。拆得清楚,以后加功能、换实现、甚至开源某一部分,都会变得轻量得多。

text=ZqhQzanResources