You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony 5中如何重写TraceableAdapter 替换框架默认实现

自定义Symfony TraceableAdapter 实现方案

你提到的CacheCollectorPass是Symfony在容器编译阶段自动给所有缓存适配器套上Traceable包装类的内置编译器Pass,默认直接硬编码了TraceableAdapter和TraceableTagAwareAdapter两个类作为包装实现,你可以通过调整容器编译逻辑完成替换,具体方案如下:

方案1:重写编译器Pass(完全替换默认实现)

  • 第一步:创建自定义Traceable实现类,继承原有官方类保证兼容性,只重写你需要修改的逻辑即可,需要同时兼容普通缓存和标签缓存两种场景:
// src/Cache/Adapter/CustomTraceableAdapter.php
namespace App\Cache\Adapter;

use Symfony\Component\Cache\Adapter\TraceableAdapter;

class CustomTraceableAdapter extends TraceableAdapter
{
    // 示例:重写get方法添加自定义逻辑
    public function get(string $key, callable $callback, float $beta = null, array &$metadata = null): mixed
    {
        // 自定义前置逻辑
        $result = parent::get($key, $callback, $beta, $metadata);
        // 自定义后置逻辑
        return $result;
    }
}
// src/Cache/Adapter/CustomTraceableTagAwareAdapter.php
namespace App\Cache\Adapter;

use Symfony\Component\Cache\Adapter\TraceableTagAwareAdapter;

class CustomTraceableTagAwareAdapter extends TraceableTagAwareAdapter
{
    // 对应标签缓存的自定义逻辑
}
  • 第二步:创建自定义编译器Pass,替换原有类选择逻辑
// src/DependencyInjection/Compiler/CustomCacheCollectorPass.php
namespace App\DependencyInjection\Compiler;

use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface;
use Symfony\Component\Cache\DependencyInjection\CacheCollectorPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use App\Cache\Adapter\CustomTraceableAdapter;
use App\Cache\Adapter\CustomTraceableTagAwareAdapter;

class CustomCacheCollectorPass extends CacheCollectorPass
{
    public function process(ContainerBuilder $container)
    {
        if (!$container->hasDefinition('data_collector.cache')) {
            return;
        }

        foreach ($container->findTaggedServiceIds('cache.pool') as $id => $attributes) {
            $definition = $container->getDefinition($id);
            if ($definition->isAbstract()) {
                continue;
            }
            // 替换原有硬编码的类名,使用自定义实现
            $recorderClass = is_subclass_of($definition->getClass(), TagAwareAdapterInterface::class)
                ? CustomTraceableTagAwareAdapter::class
                : CustomTraceableAdapter::class;
            $recorder = $container->register($id.'.recorder', $recorderClass)
                ->setDecoratedService($id)
                ->setPublic(false)
                ->addArgument($id.'.recorder.inner');

            $container->getDefinition('data_collector.cache')->addMethodCall('addInstance', [$id, $recorder]);
        }
    }
}
  • 第三步:在Kernel中注册自定义Pass,先移除原有官方Pass避免重复执行
// src/Kernel.php
use App\DependencyInjection\Compiler\CustomCacheCollectorPass;
use Symfony\Component\Cache\DependencyInjection\CacheCollectorPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;

class Kernel extends BaseKernel
{
    protected function build(ContainerBuilder $container): void
    {
        $container->removePass(CacheCollectorPass::class);
        $container->addCompilerPass(new CustomCacheCollectorPass());
    }
}

方案2:装饰现有Traceable服务(轻量需求适用)

如果不需要完全替换默认实现,只是需要追加额外逻辑,可以直接用装饰器模式处理所有Traceable服务,不需要修改编译器Pass:

  • 在config/services.yaml中添加全局装饰配置:
services:
    App\Cache\Decorator\TraceableAdapterDecorator:
        decorates: '*.recorder'
        arguments: ['@.inner']

装饰器实现对应的缓存接口,将大部分逻辑代理给内部的原生TraceableAdapter即可。

注意:以上两种方案默认仅在dev环境生效,因为缓存数据收集器本身默认仅在dev环境加载,如需生产环境生效需要额外调整数据收集器的加载配置。

内容的提问来源于stack exchange,提问作者Taras Sachavskyi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 13:30:01