如何建立 Laravel 延遲載入的服務提供者

lufeijun1234發表於2019-04-18

laravel 的服務提供者是建立在服務容器之上,實現高內聚、低耦合的功能模組。其中 register 函式負責將實現類繫結到服務容器中, boot 函式在所有服務容器註冊完成之後執行,處理配置等一系列操作。

在 laravel 系統框架啟動階段,會讀取配置檔案 config/app.php 中 $providers 的所有需要載入的服務提供者,在所有服務提供者的 register 函式呼叫完成之後,再依次呼叫各個服務提供者的 boot 函式,完成服務提供者的註冊和啟動。所以不要嘗試在 register 方法中註冊任何監聽器,路由,或者其他任何功能。否則,你可能會意外地使用到尚未載入的服務提供者提供的服務。

建立一個服務容器

建立一個介面類 和 一個對應的實現類


namespace App\Lufeijun1234\Provider\Contracts;

interface CurlContract
{
  public function get($url);
  public function post($url,$data,$header=[]);
}
namespace App\Lufeijun1234\Provider\Curl;

use App\Lufeijun1234\Provider\Contracts\CurlContract;

class CurlService implements CurlContract
{

  public function get($url)
  {
    echo "get";
  }

  public function post($url,$data,$header=[])
  {
    echo "post";
  }
}

執行的 artisan 命令

php artisan make:provider CurlServiceProvider

在 CurlServiceProvider 類中的 register 函式完成註冊

public function register()
{
    echo "curl provider register<br>";
    $this->app->singleton('curl', function(){
      return new CurlService;
    });
}
public function boot()
{
    echo "curl provider boot<br>";
}

在 config/app.php 中註冊服務提供者

直接在 providers 引數中新增 App\Providers\CurlServiceProvider::class,

驗證

任意註冊一個空的路由,透過頁面訪問,可以看到剛才在 register 和 boot 中寫的輸出語句列印出來,說明我們的服務提供者已經被註冊和啟動了,在 http 控制器中,透過 \App::make('curl') 便可以訪問到我們新新增的服務提供者,進行 get|post 傳送請求。

延遲服務提供者

如果系統在啟動時載入的提供者過多,必然會導致系統效能下降,好在 laravel 框架為我們提供延遲載入服務提供者的功能,只有真正使用到改服務提供者時,才進行繫結和啟動。

延遲服務提供者需要修改的地方

class CurlServiceProvider extends ServiceProvider 
{
  protected $defer = true;

  /**
   * 中間不變的地方暫時省略
   *
   */

  public function provides()
  {
    return ['curl'];
  }
}

利用框架的 artisan 命令生成快取檔案

執行 php artisan clear-compiled ,會重新生成框架快取檔案,在 bootstrap/cache/services.php 中儲存系統服務提供者的所有資訊,其中 deferred 儲存的是所有需要延遲載入的服務提供者。

延遲載入註冊啟動邏輯

/**
 * vendor/laravel/framework/src/Illuminate/Foundation/Application.php
 * Resolve the given type from the container.
 *
 * (Overriding Container::make)
 *
 * @param  string  $abstract
 * @param  array  $parameters
 * @return mixed
 */
public function make($abstract, array $parameters = [])
{
    $abstract = $this->getAlias($abstract);

    if (isset($this->deferredServices[$abstract]) && ! isset($this->instances[$abstract])) {
        $this->loadDeferredProvider($abstract);
    }

    return parent::make($abstract, $parameters);
}

上邊程式碼是系統服務容器解析實現類的邏輯,中間有一層判斷,如果待解析的類在延遲載入服務提供者列表中,並且是首次解析時,便會呼叫延遲載入函式 loadDeferredProvider , 呼叫服務提供者的 register 和 boot 函式進行註冊和繫結。之後在進行後續解析。

透過對 laravel 框架服務提供者邏輯的理解,手動建立一個傳送請求的 CurlServiceProvider 服務提供者,並且實現延遲載入,降低對框架系統效能的影響。如有不對,還請指教

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章