公司一個高併發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