mcpField
B
bitrix-service-locator

bitrix-service-locator

github.com/bxmaximum开发47266 次安装2 周前更新
代码仓库

关于 bitrix-service-locator

面向 Bitrix Framework 开发者的 ServiceLocator 依赖注入技能,说明服务解析、注册、覆盖方式,以及构造函数注入的适用位置。

主要功能

  1. 01服务解析与自动装配规则
  2. 02在设置中注册服务
  3. 03全局及运行时覆盖
  4. 04按组件说明注入方式
  5. 05生命周期与领域层规范

适用场景

  1. 01注册接口实现
  2. 02在服务中解析依赖
  3. 03覆盖模块绑定
  4. 04在命令中访问容器

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/bxmaximum/bitrix-framework-skills --skill bitrix-service-locator

安装后在 Claude Code 中输入/bitrix-service-locator确认已加载。

详细介绍

ServiceLocator(DI)

基线:main 23.0+ · 已验证:main 26.800.0

允许使用构造函数 DI 的位置(服务可以;控制器通过操作参数注入;命令和处理器不可以):bitrix-framework。领域类绝不接触容器。

get($id) 的解析方式(自 main 26.250* 起)

键结果
已构建或通过 addInstance() 添加同一个实例
未注册,但类存在自动装配:每个构造函数参数都调用 get(<其类型>);有默认值的参数使用默认值
已注册的接口 / 抽象类className → 自动装配实现(忽略 constructorParams);constructor 闭包 → 以 constructorParams 为参数调用
已注册的具体类或字符串 IDclassName → new $class(...array_values(constructorParams)),不进行自动装配;constructor 闭包 → 不带参数调用
  • 实例会在进程内缓存,除非条目设置了 'singleton' => false。
  • 循环依赖会抛出 CircularDependencyException。没有默认值的无类型、联合类型或标量参数会抛出 ServiceNotFoundException。
  • 在 26.250 之前:每个已注册的键都通过 new $class(...constructorParams) 或 constructor() 构建。只有当未注册类的所有构造函数参数都是具体类时,才会自动装配(不考虑默认值)。没有 singleton 选项。在此类内核上,请通过 constructor 闭包绑定带有依赖项的实现。

注册

在 /local/modules/vendor.module/.settings.php 中的 services(在 Loader::includeModule() 时注册)或全局设置中:

<?php
return [
    'services' => [
        'value' => [
            // interface → implementation (autowired since 26.250*)
            \Vendor\Blog\Domain\PostRepositoryInterface::class => [
                'className' => \Vendor\Blog\Infrastructure\OrmPostRepository::class,
            ],
            // scalar arguments → factory
            \Vendor\Blog\Infrastructure\TelegramClient::class => [
                'constructor' => static fn () => new \Vendor\Blog\Infrastructure\TelegramClient(
                    (string)getenv('TELEGRAM_BOT_TOKEN'),
                ),
            ],
            // positional args; closure evaluated on first get()
            'vendor.blog.mailer' => [
                'className' => \Vendor\Blog\Infrastructure\Mailer::class,
                'constructorParams' => static fn () => ['[email protected]'],
            ],
        ],
        'readonly' => true,
    ],
];
  • 不要注册只依赖其他类的具体类。get(PostService::class) 会自动装配该类,而单独使用 [ 'className' => PostService::class ] 会执行 new PostService() → ArgumentCountError。
  • 优先使用 FQCN 键。字符串 ID(main.validation.service)是内核风格。
  • 内核会注册 Application、Routing\Router、DB\Connection、Data\Cache、Data\ManagedCache、Data\TaggedCache、EventManager、Data\ConnectionPool、\CUserTypeManager(自 main 26.250* 起)以及 Data\Storage\PersistentStorageInterface(自 main 25.1100 起,bitrix-storage)。请通过构造函数注入这些对象,而不要调用 Application::getInstance()->…。

覆盖

  • 先注册者优先:registerByModuleSettings() 会跳过已存在的键。后加载的模块无法覆盖先加载的模块。
  • 在 /local/.settings_extra.php 的全局 services 中覆盖模块绑定(应用启动时、模块之前注册),或在运行时(init.php、测试)调用:ServiceLocator::getInstance()->addInstance($id, $object) / addInstanceLazy($id, ['className' => …])。

获取服务

  • 服务:使用构造函数参数。
  • 控制器操作:为具体类指定类型提示。操作参数中的接口不会被解析(bitrix-controllers)。
  • Messenger 接收器通过 get(FQCN) 构建,因此会自动装配。控制台命令和事件处理器不会自动装配:请在 execute() / 处理器中调用 ServiceLocator::getInstance()->get(Foo::class)。
  • has($id) 仅当 ID 已注册或已构建时才返回 true;可自动装配的类不满足此条件。

规则

  • 服务是进程级单例:不要在属性中保存请求级状态。长时间运行的消费者会在消息之间保留实例。
  • 如果容器可以构建服务,就不要在控制器 / 命令中使用 new Service()。领域代码中不要调用容器。
  • 配置应通过工厂以类型化对象或标量的形式传入,而不是作为原始数组服务。
  • 功能开关:使用内核的 Bitrix\Main\Config\Feature(自 main 26.700 起,bitrix-storage),不要自建标记服务。

评论

支持 Markdown