laravel 6 服务容器通过反射解析、显式绑定和构造函数类型提示实现业务层依赖自动注入;需满足自动加载前提与可解析类型提示,接口须在 register() 中显式绑定,注入仅发生在容器获取实例时,单例与绑定影响生命周期管理。

Laravel 6 的服务容器实现业务层依赖自动注入,核心在于反射解析 + 显式绑定 + 构造函数类型提示三者协同。它不是“魔法”,而是有明确触发条件和配置要求的机制。
业务层类如何被自动注入
业务层类(如 app/Services/OrderService.php、app/Repositories/UserRepository.php)要被自动注入,需满足两个前提:
- 类本身可被自动加载(命名空间正确、文件路径规范、已执行
composer dump-autoload) - 构造函数参数全部是可解析的类型提示:要么是具体类(如
Logger),要么是已绑定的接口(如PaymentServiceInterface)
例如:
class OrderService
{
public function __construct(
UserRepository $userRepository,
PaymentServiceInterface $paymentService
) {
// $userRepository 会被自动 new 实例
// $paymentService 必须已在 AppServiceProvider@register() 中 bind
}
}
若 $paymentService 未绑定,运行时会抛出 Unresolvable dependency 错误。
接口必须显式绑定才能注入
Laravel 不会“猜测”接口该用哪个实现。你必须在服务提供者的 register() 方法中完成绑定:
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->bind(
PaymentServiceInterface::class,
StripePaymentService::class
);
}
注意:
- 绑定必须写在
register(),不能放boot()(否则队列、命令行等场景会失效) - 类名必须带完整命名空间(
use语句不能漏) - 字符串别名(如
'payment')无法匹配构造函数中的接口类型提示
自动注入实际发生的时机
业务层类的自动注入,发生在你通过容器获取实例时,比如:
- 控制器构造函数被路由调度器调用(
app()->make(OrderController::class)) - 在命令中调用
app(OrderService::class) - 在事件监听器、Job、中间件中使用类型提示
但如果你手动 new OrderService(),注入完全不会触发——容器根本没参与。
单例与每次新建的选择影响业务行为
业务层对象常涉及状态或资源消耗,生命周期管理很关键:
- 用
bind():每次请求都新建实例 → 适合无状态、轻量类(如 DTO、格式化器) - 用
singleton():全局复用单个实例 → 适合含连接、缓存、上下文的类(如数据库查询构建器封装、HTTP 客户端)
错误示例:
$this->app->bind(DatabaseClient::class, function () {
return new DatabaseClient(); // 每次都新建连接 → 连接池迅速打满
});
应改为:
$this->app->singleton(DatabaseClient::class, function ($app) {
return new DatabaseClient($app['config']->get('database'));
});
不复杂但容易忽略











