关于 bitrix-service-locator
面向 Bitrix Framework 开发者的 ServiceLocator 依赖注入技能,说明服务解析、注册、覆盖方式,以及构造函数注入的适用位置。
主要功能
- 01服务解析与自动装配规则
- 02在设置中注册服务
- 03全局及运行时覆盖
- 04按组件说明注入方式
- 05生命周期与领域层规范
适用场景
- 01注册接口实现
- 02在服务中解析依赖
- 03覆盖模块绑定
- 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 为参数调用 |
| 已注册的具体类或字符串 ID | className → 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