Laravel源码解析之服务提供者

概述

官方文档中关于服务提供者的这篇文档,主要是说明如何编写自定义的服务提供者。本篇注解,就来说说啥是服务提供者,然后再总结一下如何编写服务提供者。

服务提供者想要理解,首先需要理解什么是服务容器,可以移步服务容器 进行了解。在有了服务容器的概念后,就可以很容易的理解什么是服务提供者了。

服务容器是盛放服务的容器,有绑定和解析两个主要操作。绑定就是将服务注册到容器中。而服务提供者,就是完成绑定服务到容器任务的单元。看名字就知道,是用来提供服务的单位。简言之,服务容器中绑定的服务,就是由服务提供者绑定进去的。就是这么个功能。 详细看看。

Laravel 中服务提供者的结构

服务提供者类,都要继承自 Illuminate\Support\ServiceProvider 服务提供者基类。

服务提供者一定要有一个 register 方法,这个方法功能就是完成服务绑定到容器的。参考日志服务提供者 Illuminate\Log\LogServiceProvider register 的实现:

class LogServiceProvider extends ServiceProvider
{
    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        // 绑定一个单例对象,用于提供日志服务
        $this->app->singleton('log', function () {
            return $this->createLogger();
        });
    }
}

可以看到 register () 方法,确实是完成服务容器的绑定。这就是服务提供者的主要任务。

除了这个 register () 方法外,还有 boot () 也是比较常用的方法,后边会提到。

绑定的时机

再看就是这个 register () 方法是在何时被调用的,就是何时完成注册的。

一部分,就是在应用服务容器初始化时,完成基础的服务绑定,参考代码:

文件 Illuminate\Foundation\Application :
构造方法:

public function __construct($basePath = null)
    {
        if ($basePath) {
            $this->setBasePath($basePath);
        }

        $this->registerBaseBindings();
        // 注册基础服务提供者,其他代码忽略
        $this->registerBaseServiceProviders();

        $this->registerCoreContainerAliases();
    }

调用的 Illuminate\Foundation\Application::registerBaseServiceProviders():

protected function registerBaseServiceProviders()
{
    $this->register(new EventServiceProvider($this));

    $this->register(new LogServiceProvider($this));

    $this->register(new RoutingServiceProvider($this));
}

这个 $this->register() 就可以触发对应的服务提供者的 register () 方法。

另一部分是在内核 Kernel 处理请求前,会绑定一些基础功能服务提供者。

可以参考代码 Illuminate\Foundation\Application::registerConfiguredProviders() :

public function registerConfiguredProviders()
{
    (new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath()))
                ->load($this->config['app.providers']);
}

注意观察 $this->config[‘app.providers’] 这行代码就是从配置文件中读取配置好的服务提供者列表,进行注册绑定,app.providers’ 这个配置可以在 config/app.php` 中看到, 列举一部分:

'providers' => [
    /*
     * Laravel Framework Service Providers...
     */
    Illuminate\Auth\AuthServiceProvider::class,
    ... 好多,好多

    /*
     * Package Service Providers...
     */
    Laravel\Tinker\TinkerServiceProvider::class,

    /*
     * Application Service Providers...
     */
    ... 好多,好多
    App\Providers\RouteServiceProvider::class,
],

而这个 registerConfiguredProviders () 方法,是在 $kernel->handle () 的内部进行调用的。详细的调用过程,大家可以利用 ide 进行追踪下。需要注意的就是,这个方法是在内核处理请求阶段执行的。

以上就是两处服务提供者,绑定服务的时机。1,应用服务容器初始化过程;2,内核处理请求过程中。

服务容器的 boot () 方法

一个基本的服务器容器,除了 register () 方法外,还会存在一个 boot 方法。对比 register () 方法,他们的主要差异是执行时机不同,进而导致了所完成的任务特征也有所不同。

register (), 是服务提供者的主要任务,就完成某些服务的注册。使用服务提供者,核心目的就是为了注册服务。

boot (),是为了初始化某些服务特殊工作。任何服务提供者的 boot () 方法都会在全部服务提供者注册之后运行。那也就可以保证在 boot () 方法中,可以使用全部的注册服务。而对应的 register () 是在每个服务提供者注册时执行,其中不能使用其他服务提供者绑定的服务,因为我们不能完全确定其先后顺序。除非你非常熟悉。

执行时机的差异,可以参考代码:Illuminate\Foundation\Http\Kernel::$bootstrappers 属性,即时在内核处理请求时,需要启动的功能数组定义:

protected $bootstrappers = [
    \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
    \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
    \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
    \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
    // 先启动注册服务提供者,触发服务提供者的register()方法
    \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
    // 注册完毕后,在启动boot服务提供者,触发全部服务提供者的boot()方法
    \Illuminate\Foundation\Bootstrap\BootProviders::class,
];

注意此数组的最后两个元素,显示注册服务提供者,再时启动服务提供者。这就确定了服务提供者方法的执行时机。

延迟绑定的优化

在 app.providers 配置项中,这么多的服务提供者,是不是都需要在初始化公共阶段完成绑定呢?如果某些服务器在整个周期可能会用不到呢,那岂不是白白绑定了?Laravel 通过 将某些服务提供者设置为延迟状态,来解决这个性能问题。

就是说,如果某个服务提供者被设置为延迟处理,那么不会在初始化时就绑定,而是在真正使用时才绑定,使用属性 $defer = true 就可做到。那么启动阶段在处理到该服务提供者时,如果发现是延迟的,那么不立即绑定,等到需要时在绑定。

class RiakServiceProvider extends ServiceProvider
{
    /**
     * 是否延时加载提供器。
     *
     * @var bool
     */
    protected $defer = true;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shang443

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值