Symfony 7中如何自动注入兼容双接口的自定义缓存池?
Symfony 7 自定义缓存池同时调用两类缓存方法的注入方案
问题背景
已在Symfony 7中定义自定义Redis标签缓存池:
framework: cache: default_redis_provider: '%env(resolve:REDIS_URL)%' pools: cache.score: adapter: cache.adapter.redis_tag_aware
根据文档使用CacheInterface $cacheScore自动注入时,仅能调用CacheInterface的方法,无法使用Psr\Cache\CacheItemPoolInterface提供的getItem()等方法。而缓存适配器同时实现了这两个接口,需要同时使用两类方法,且要求仅修改cache.yaml即可切换适配器,无需改动业务代码。
尝试直接注入AbstractAdapter或RedisTagAwareAdapter均抛出依赖注入异常。
附symfony console debug:autowiring cache输出:
Autowirable Types ================= The following classes & interfaces can be used as type-hints when autowiring: (only showing classes/interfaces matching cache) CacheItemPoolInterface generates CacheItemInterface objects. Psr\Cache\CacheItemPoolInterface - alias:cache.app Psr\Cache\CacheItemPoolInterface $cacheScore - target:cache.score Covers most simple to advanced caching needs. Symfony\Contracts\Cache\CacheInterface - alias:cache.app Symfony\Contracts\Cache\CacheInterface $cacheScore - target:cache.score Allows invalidating cached items using tags. Symfony\Contracts\Cache\TagAwareCacheInterface - alias:cache.app.taggable Symfony\Contracts\Cache\TagAwareCacheInterface $cacheScore - target:cache.score
解决方案
利用Symfony自动注入的参数名匹配特性,通过以下两种方式即可同时调用两类方法,且满足适配器灵活切换的需求:
方案1:双参数注入
在服务构造函数中同时注入CacheInterface和Psr\Cache\CacheItemPoolInterface,通过参数名$cacheScore匹配目标缓存池:
use Psr\Cache\CacheItemPoolInterface; use Symfony\Contracts\Cache\CacheInterface; class YourBusinessService { private CacheInterface $cache; private CacheItemPoolInterface $cachePool; public function __construct( CacheInterface $cacheScore, CacheItemPoolInterface $cacheScore ) { $this->cache = $cacheScore; $this->cachePool = $cacheScore; } public function handleBusinessLogic() { // 使用Symfony缓存契约的get方法 $cachedValue = $this->cache->get('user_score', function () { return $this->calculateScore(); }); // 使用PSR-6规范的getItem方法 $cacheItem = $this->cachePool->getItem('user_score'); if (!$cacheItem->isHit()) { $cacheItem->set($this->calculateScore()); $this->cachePool->save($cacheItem); } } private function calculateScore() { // 业务逻辑计算 return 95; } }
方案2:单参数+类型断言
仅注入一个接口实例,通过类型断言确保它同时实现另一接口:
use Psr\Cache\CacheItemPoolInterface; use Symfony\Contracts\Cache\CacheInterface; class YourBusinessService { private CacheInterface $cache; private CacheItemPoolInterface $cachePool; public function __construct(CacheInterface $cacheScore) { $this->cache = $cacheScore; // 断言实例同时实现CacheItemPoolInterface assert($cacheScore instanceof CacheItemPoolInterface); $this->cachePool = $cacheScore; } // 业务方法同上 }
优势说明
两种方案均无需修改services.yaml,仅通过自动注入的参数名匹配即可绑定目标缓存池。后续若需切换适配器(如从Redis改为文件缓存),只需修改cache.yaml中的adapter配置,业务代码无需任何改动,完全符合需求。
内容的提问来源于stack exchange,提问作者michnovka
相关产品推荐
相关产品推荐

