问题描述
公司一个高并发API需要从Laravel移植到Lumen,由于数据库配置信息是通过远程或者缓存读取后动态配置,所以在中间件时使用到了 Config::set
然而实际运行时发现数据库配置并没有更新。
由于是从Laravel移植,因此保留了Facades的写法,Lumen中可以通过以下方法使用Facades:
取消
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()
的代码:
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
的时候会再次载入配置文件中的配置项覆盖动态写入的内容。
同理,使用 Redis
时,由于 Redis
相关配置是写在 database.php
里的,仅仅通过 $app->register(Illuminate\Redis\RedisServiceProvider::class);
注册是无法获取到配置项,如果在使用 Redis
时之前没有使用 DB
就会报没有传配置项的错误。
解决方案
既然找到了问题所在,要解决起来也是很方便的。只要在修改、使用配置项之前先载入配置文件就可以解决这些问题。比如:
使用
app()->configure('database');
载入所需要的配置文件在注册绑定服务到服务容器的时候使用
loadComponent
进行注册绑定
欢迎关注我的博客 http://targetliu.com
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。