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

相关文章
相关标签/搜索