Lumen配置文件按需加載出現的坑

問題描述

公司一個高併發API須要從Laravel移植到Lumen,因爲數據庫配置信息是經過遠程或者緩存讀取後動態配置,因此在中間件時使用到了 Config::set 然而實際運行時發現數據庫配置並無更新。php

因爲是從Laravel移植,所以保留了Facades的寫法,Lumen中能夠經過如下方法使用Facades:laravel

  • 取消 bootstarp/app.php$app->withFacades(); 的註釋數據庫

  • use Illuminate\Support\Facades\XXX數組

另外一方面,系統使用 Redis 做爲緩存,經過 env 配置 Redis ,配置信息存儲在 config/database.php 在沒有使用數據庫先使用緩存的狀況下,報沒有傳配置項的錯誤。緩存

問題分析

經過閱讀源碼 laravel/lumen-framework/src/Application.php 發現,Lumen中的服務都是按需綁定並加載。先來看看 make() 的代碼:併發

public function make($abstract, array $parameters = [])
{
    $abstract = $this->getAlias($this->normalize($abstract));

    if (array_key_exists($abstract, $this->availableBindings) &&
        ! array_key_exists($this->availableBindings[$abstract], $this->ranServiceBinders)) {
        $this->{$method = $this->availableBindings[$abstract]}();

        $this->ranServiceBinders[$method] = true;
    }

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

Lumen經過數組 $availableBindings 實現了基本服務的按需綁定並加載。在服務按需綁定並加載的時候,使用了相似組件的形式經過 loadComponent() 載入配置項並綁定服務。再來看看 loadComponent() 的代碼:app

public function loadComponent($config, $providers, $return = null)
{
    $this->configure($config);

    foreach ((array) $providers as $provider) {
        $this->register($provider);
    }

    return $this->make($return ?: $config);
}

如此就釋然爲何在中間件以及使用 DB 以前想要動態配置數據庫的信息時沒法正確的寫入配置項了。由於在這個時候 DB 的相關配置文件尚未被載入。你先寫入了配置項當使用 DB 的時候會再次載入配置文件中的配置項覆蓋動態寫入的內容。ide

同理,使用 Redis 時,因爲 Redis 相關配置是寫在 database.php 裏的,僅僅經過 $app->register(Illuminate\Redis\RedisServiceProvider::class); 註冊是沒法獲取到配置項,若是在使用 Redis 時以前沒有使用 DB 就會報沒有傳配置項的錯誤。高併發

解決方案

既然找到了問題所在,要解決起來也是很方便的。只要在修改、使用配置項以前先載入配置文件就能夠解決這些問題。好比:this

  • 使用 app()->configure('database'); 載入所須要的配置文件

  • 在註冊綁定服務到服務容器的時候使用 loadComponent 進行註冊綁定


歡迎關注個人博客 http://targetliu.com

相關文章
相關標籤/搜索