资讯专栏INFORMATION COLUMN

Laravel 的缓存源码解析

SwordFly / 1539人阅读

摘要:年月日前言支持多种缓存系统并提供了统一的接口默认支持的存储驱动包括如下默认使用数组测试用关系型数据库默认的缓存配置文件在参考链接使用直接使用为我们提供的支持的大部分方法其他使用方法请参照官方翻译中文文档源码中常用

Last-Modified: 2019年5月10日14:17:34

前言

Laravel 支持多种缓存系统, 并提供了统一的api接口.

(Laravel 5.5)默认支持的存储驱动包括如下:

file (默认使用)

apc

array (数组, 测试用)

database (关系型数据库)

memcached

redis

默认的缓存配置文件在 config/cache.php

参考链接:

https://learnku.com/docs/lara...

https://www.jianshu.com/p/46a...

使用

直接使用Laravel为我们提供的Facade

use IlluminateSupportFacadesCache;
$cache = Cache::get("key");

支持的大部分方法:

Cache::put("key", "value", $minutes);
Cache::add("key", "value", $minutes);
Cache::forever("key", "value");
Cache::remember("key", $minutes, function(){ return "value" });
Cache::rememberForever("key", function(){ return "value" });
Cache::forget("key");
Cache::has("key");
Cache::get("key");
Cache::get("key", "default");
Cache::get("key", function(){ return "default"; });
Cache::tags("my-tag")->put("key","value", $minutes);
Cache::tags("my-tag")->has("key");
Cache::tags("my-tag")->get("key");
Cache::tags("my-tag")->forget("key");
Cache::tags("my-tag")->flush();
Cache::increment("key");
Cache::increment("key", $amount);
Cache::decrement("key");
Cache::decrement("key", $amount);
Cache::tags("group")->put("key", $value);
Cache::tags("group")->get("key");
Cache::tags("group")->flush();

其他使用方法请参照官方翻译(中文)文档: https://learnku.com/docs/lara...

源码

Laravel 中常用 Cache Facade 来操作缓存, 对应的实际类是 IlluminateCacheCacheManager 缓存管理类(工厂).

Cache::xxx()

我们通过 CacheManager 类获取持有不同存储驱动的 IlluminateCacheRepository

CacheManager::store($name = null)

Repository 仓库类代理了实现存储驱动接口 IlluminateContractsCacheStore 的类实例.

Cache Facade

首先从 Cache Facade 开始分析, 先看一下其源码:


在配置文件 configapp.php 中定义了 Cache 服务提供者

//...
"providers" => [
        // ......
        IlluminateCacheCacheServiceProvider::class,
        // ......
    ],
//...

IlluminateCacheCacheServiceProvider 源文件:

app->singleton("cache", function ($app) {
            return new CacheManager($app);
        });

        $this->app->singleton("cache.store", function ($app) {
            return $app["cache"]->driver();
        });

        $this->app->singleton("memcached.connector", function () {
            return new MemcachedConnector;
        });
    }
    
    // ......
}

通过上面源码可知, Cache Facade 关联的项是 IlluminateCacheCacheManager, 也就是我们通过 Cache Facade 实际调用的是 CacheManager实例的方法.

CacheManager

CacheManager 实现了 IlluminateContractsCacheFactory 接口(↑), 即实现了一个简单工厂, 传入存储驱动名, 返回对应的驱动实例.

CacheManager实现的简单工厂接口方法:

getDefaultDriver();

        return $this->stores[$name] = $this->get($name);
    }
    
    /**
     * Get the default cache driver name.
     *
     * @return string
     */
    public function getDefaultDriver()
    {
        return $this->app["config"]["cache.default"];
    }

    /**
     * Attempt to get the store from the local cache.
     *
     * @param  string  $name
     * @return IlluminateContractsCacheRepository
     */
    protected function get($name)
    {
        return $this->stores[$name] ?? $this->resolve($name);
    }

    /**
     * Resolve the given store.
     *
     * @param  string  $name
     * @return IlluminateContractsCacheRepository
     *
     * @throws InvalidArgumentException
     */
    protected function resolve($name)
    {
        $config = $this->getConfig($name);

        if (is_null($config)) {
            throw new InvalidArgumentException("Cache store [{$name}] is not defined.");
        }

        if (isset($this->customCreators[$config["driver"]])) {
            return $this->callCustomCreator($config);
        } else {
            $driverMethod = "create".ucfirst($config["driver"])."Driver";

            if (method_exists($this, $driverMethod)) {
                return $this->{$driverMethod}($config);
            } else {
                throw new InvalidArgumentException("Driver [{$config["driver"]}] is not supported.");
            }
        }
    }
    
    /**
     * Dynamically call the default driver instance.
     *
     * @param  string  $method
     * @param  array   $parameters
     * @return mixed
     */
    public function __call($method, $parameters)
    {
        return $this->store()->$method(...$parameters);
    }
}

可以看到 CacheManager 提供了会话级别的实例缓存, 当解析驱动名时, 它会按如下顺序解析:

自定义驱动: 查看是否有通过 CacheManager::extend(...)自定义的驱动

Laravel提供的驱动: 查看是否存在 CacheManager::createXxxDriver(...)方法

这些方法返回的实例必须是实现了 IlluminateContractsCacheRepository 接口

本质上, CacheManager 就是一个提供了会话级别缓存Repository 实例工厂, 同时它提供了一个 __call 魔术方法, 以便快速调用默认缓存驱动.

$value = Cache::store("file")->get("foo");

// 通过 _call, 调用默认缓存驱动的 get 方法
$value = Cache::get("key");
Repository

IlluminateContractsCacheRepository 接口


Repository 是一个符合 PSR-16: Common Interface for Caching Libraries 规范的缓存仓库类, 其在Laravel相应的实现类: IlluminateCacheRepository

IlluminateCacheRepository 部分代码如下:

store = $store;
    }

    public function has($key)
    {
        return ! is_null($this->get($key));
    }

    public function get($key, $default = null)
    {
        if (is_array($key)) {
            return $this->many($key);
        }

        $value = $this->store->get($this->itemKey($key));

        // If we could not find the cache value, we will fire the missed event and get
        // the default value for this cache value. This default could be a callback
        // so we will execute the value function which will resolve it if needed.
        if (is_null($value)) {
            $this->event(new CacheMissed($key));

            $value = value($default);
        } else {
            $this->event(new CacheHit($key, $value));
        }

        return $value;
    }

    public function pull($key, $default = null)
    {
        return tap($this->get($key, $default), function ($value) use ($key) {
            $this->forget($key);
        });
    }
    
    protected function event($event)
    {
        if (isset($this->events)) {
            $this->events->dispatch($event);
        }
    }

    /**
     * Set the event dispatcher instance.
     *
     * @param  IlluminateContractsEventsDispatcher  $events
     * @return void
     */
    public function setEventDispatcher(Dispatcher $events)
    {
        $this->events = $events;
    }

    public function __call($method, $parameters)
    {
        if (static::hasMacro($method)) {
            return $this->macroCall($method, $parameters);
        }

        return $this->store->$method(...$parameters);
    }
    
    public function __clone()
    {
        $this->store = clone $this->store;
    }
}

从源码可以看出, IlluminateCacheRepository 实现了代理模式, 具体的实现是交由 IlluminateContractsCacheStore 来处理, Repository 主要作用是

提供一些便捷操作(可以理解为语法糖)

Event 事件触发, 包括缓存命中/未命中、写入/删除键值

Store

IlluminateContractsCache 缓存驱动是实际处理缓存如何写入/读取/删除的类, 接口内容如下:


具体的实现类有:

ApcStore

ArrayStore

NullStore

DatabaseStore

FileStore

MemcachedStore

RedisStore

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/31443.html

相关文章

  • Laravel 缓存源码解析

    摘要:年月日前言支持多种缓存系统并提供了统一的接口默认支持的存储驱动包括如下默认使用数组测试用关系型数据库默认的缓存配置文件在参考链接使用直接使用为我们提供的支持的大部分方法其他使用方法请参照官方翻译中文文档源码中常用 Last-Modified: 2019年5月10日14:17:34 前言 Laravel 支持多种缓存系统, 并提供了统一的api接口. (Laravel 5.5)默认支持的...

    neroneroffy 评论0 收藏0
  • Laravel学习笔记之bootstrap源码解析

    摘要:总结本文主要学习了启动时做的七步准备工作环境检测配置加载日志配置异常处理注册注册启动。 说明:Laravel在把Request通过管道Pipeline送入中间件Middleware和路由Router之前,还做了程序的启动Bootstrap工作,本文主要学习相关源码,看看Laravel启动程序做了哪些具体工作,并将个人的研究心得分享出来,希望对别人有所帮助。Laravel在入口index...

    xiaoxiaozi 评论0 收藏0
  • Laravel学习笔记之Filesystem源码解析(下)

    摘要:源码解析这个类的源码主要就是文件的操作和文件属性的操作,而具体的操作是通过每一个实现的,看其构造函数看以上代码知道对于操作,实际上是通过的实例来实现的。可以看下的使用上文已经说了,使得对各种的操作变得更方便了,不管是还是得。 说明:本文主要学习下LeagueFlysystem这个Filesystem Abstract Layer,学习下这个package的设计思想和编码技巧,把自己的一...

    Luosunce 评论0 收藏0
  • Laravel框架门面Facade源码分析

    摘要:容器主要的作用就是生产各种零件,就是提供各个服务。的原理我们以为例,来讲解一下门面的原理与实现。当运行时,发现门面没有静态函数,就会调用这个魔术函数。我们看到这个魔术函数做了两件事获得对象实例,利用对象调用函数。 前言 在开始之前,欢迎关注我自己的博客:www.leoyang90.cn这篇文章我们开始讲 laravel 框架中的门面 Facade,什么是门面呢?官方文档: Facade...

    wanghui 评论0 收藏0
  • Laravel核心解读--服务提供器(ServiceProvider)

    摘要:调用了的可以看出,所有服务提供器都在配置文件文件的数组中。启动的启动由类负责引导应用的属性中记录的所有服务提供器,就是依次调用这些服务提供器的方法,引导完成后就代表应用正式启动了,可以开始处理请求了。 服务提供器是所有 Laravel 应用程序引导中心。你的应用程序自定义的服务、第三方资源包提供的服务以及 Laravel 的所有核心服务都是通过服务提供器进行注册(register)和引...

    Richard_Gao 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<