Laravel修炼:服务提供者

前言

  上一篇博客文章收集了关于Laravel服务容器的相关知识(传送门),我们知道了服务容器主要有绑定和解析两个重要功能,那么Laravel这个框架集齐了如此多功能,我们项目可能还需要另外引入一些功能包,这些绑定必须有一个统一的管理工具,统一绑定在一个地方,这个地方就是服务提供者。

关于服务提供者

  一开始学Laravel被服务容器和服务提供者两个名称搞混了,其实现在我是这样理解:容器就是底层一个大桶, 我们需要很多材料往里面填充,而提供者就是一些管道,我们就是通过提供者往容器里面塞我们需要的东西,需要的服务。

  Laravel有一种机制来定义和执行每个服务的初始处理,实现初始处理的类称为服务提供者

  服务提供者,在laravel里面,其实就是一个工厂类。它最大的作用就是用来进行服务绑定。当我们需要绑定一个或多个服务的时候,可以自定义一个服务提供者,然后把服务绑定的逻辑都放在该类的实现中。在larave里面,要自定一个服务提供者非常容易,只要继承Illuminate\Support\ServiceProvider这个类即可。下面通过一个简单的自定义服务提供者来说明服务提供者的一些要点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class yourServiceProvider extends ServiceProvider
{
protected $defer = true;

public function boot()
{
//
}

public function register()
{
$this->app->singleton('service1', function(){
return 'service1';
});
$this->app->singleton('service2', function(){
return 'service2';
});
$this->app->singleton('service3', function(){
return 'service3';
});
}

public function provides()
{
return ['service1','service2','service3'];
}
}

对于服务提供者类可以通过artisan命令创建:
php artisan make:provider yourServiceProvider
创建后的文件会存放在app\Providers\目录下

avatar

  现在我们的服务已经在yourServiceProvider这个类里面的register()里面进行绑定了。虽然完成了服务提供者的创建和绑定,但框架现在不知道多了一个服务提供者,所以在程序运行过程中还不会调用该类中的registe()方法,所以需要在某个位置进行注册来告诉框架新创建的服务提供者–配置文件config\app.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
'providers' => [

/*
* Laravel Framework Service Providers...
*/
Illuminate\Auth\AuthServiceProvider::class,
Illuminate\Broadcasting\BroadcastServiceProvider::class,
Illuminate\Bus\BusServiceProvider::class,
Illuminate\Cache\CacheServiceProvider::class,
Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
...
...
...
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,

],

当laravel找到这个服务提供者的类以后,就会初始化这个服务提供者类,得到一个服务提供者的对象,然后调用它的register方法,自然它里面的所有服务绑定代码就都会执行了:

1
2
3
4
5
6
7
public function registerConfiguredProviders()
{
$manifestPath = $this->getCachedServicesPath();

(new ProviderRepository($this, new Filesystem, $manifestPath))
->load($this->config['app.providers']);
}

laravel会把所有的自定义服务提供者都注册进来。这个注册的过程其实就是前面说的实例化服务提供者的类,并调用register方法的过程。

  除了register方法,服务提供者里面还有一个boot方法,这个boot方法,会在所有的服务提供者都注册完成之后才会执行,所以当你想在服务绑定完成之后,通过容器解析出其它服务,做一些初始化工作的时候,那么就可以这些逻辑写在boot方法里面。因为boot方法执行的时候,所有服务提供者都已经被注册完毕了,所以在boot方法里面能够确保其它服务都能被解析出来。

  以上主要介绍了laravel服务提供器的作用和具体使用方法,在我们平时的开发一般情况下引入第三方包就是这样的步骤(举例overtrue/laravel-wechat):

  • 安装引入:composer require “overtrue/laravel-wechat:~4.0”
  • 在 config/app.php 注册 ServiceProvider 和 Facade(Laravel 5.5 无需手动注册)

    1
    2
    3
    4
    5
    6
    7
    8
    'providers' => [
    // ...
    Overtrue\LaravelWeChat\ServiceProvider::class,
    ],
    'aliases' => [
    // ...
    'EasyWeChat' => Overtrue\LaravelWeChat\Facade::class,
    ],
  • 创建配置文件

    1
    artisan vendor:publish --provider="Overtrue\LaravelWeChat\ServiceProvider

服务提供者还有一个小问题值的注意,由于php是一门基本语言,在处理请求的时候,都会从入口文件把所有php都执行一遍。为了性能考虑,laravel会在第一次初始化的时候,把所有的服务提供者都缓存到bootstrap/cache/services.php文件里面,所以有时候当你改了一个服务提供者的代码以后,再刷新不一定能看到期望的效果,这有可能就是因为缓存所致。这时把services.php删掉就能看到你要的效果了。

 再次感 云诸葛这篇文章,看完后收货很大,本文内容较为粗略,想要详细了解可以看这里laravel框架容器管理的一些要点