【问题标题】:Spring 4 cache key generation is not working as expectedSpring 4 缓存键生成未按预期工作
【发布时间】:2014-07-07 14:52:14
【问题描述】:

将 spring 升级到版本 4 后,我们的自定义密钥生成器停止工作。 在迁移之前,我们执行了覆盖“generate”方法的代码,但是在迁移到spring 4.0.5之后,代码根本没有执行。 相反,我看到 SimpleKeyGenerator 是始终执行的那个。 这是春天的虫子吗?为什么我不能像以前的版本那样用自己的代码覆盖 generate 方法?

来自根上下文的样本:

<cache:annotation-driven key-generator="cacheKeyGenerator" />
<bean id="cacheKeyGenerator" class="com.poalim.xp.general.cache.CacheKeyGenerator"/>

java 密钥生成示例(迁移前)

public class CacheKeyGenerator extends DefaultKeyGenerator implements ApplicationContextAware {
public Object generate(Object target, Method method, Object... params) { 
    return  method.getName() + super.generate(target, method, params); 
}

}

迁移后的示例代码

public class CacheKeyGenerator extends SimpleKeyGenerator implements ApplicationContextAware {
public Object generate(Object target, Method method, Object... params) { 
    return  method.getName() + super.generate(target, method, params); 
}

}

附加信息: 调试代码后,我看到每次调用“生成”方法时, 它仅在 SimpleKeyGenerator 中执行,而不在我的自定义 CacheKeyGenerator 类中执行。 我试图理解为什么,所以我做了一些调试。 在调试时,我看到有 org.springframework.cache.interceptor.CacheAspectSupport 类, 具有私有属性: private KeyGenerator keyGenerator = new SimpleKeyGenerator(); 这个类在 keyGenerator 属性上有一个 setter 方法,我看到当上下文启动时, 这个setter方法是用我自定义的CacheKeyGenerator调用的,所以我断定我的配置是正确的,问题不在配置中。 我还看到,当需要密钥生成时,keyGenerator 属性“丢失”了“CacheKeyGenerator”值并具有“SimpleKeyGenerator”。 这解释了为什么我的自定义代码从未执行,但我不明白为什么 keyGenerator 属性指向 SimpleKeyGenerator。 这似乎是一个弹簧 BUG。 有什么问题?

【问题讨论】:

    标签: spring spring-cache


    【解决方案1】:

    查看您通过电子邮件发送的示例代码后,我发现您有两个问题:

    @EnableCaching

    @EnableCaching 注释旨在在您使用 Java 配置时用作 XML 配置的替代品。例如:

     @Configuration
     @EnableCaching
     public class AppConfig implements CachingConfigurer {
    
         @Bean
         @Override
         public CacheManager cacheManager() {
             // configure and return an implementation of Spring's CacheManager SPI
             SimpleCacheManager cacheManager = new SimpleCacheManager();
             cacheManager.addCaches(Arrays.asList(new ConcurrentMapCache("default")));
             return cacheManager;
         }
    
         @Bean
         @Override
         public KeyGenerator keyGenerator() {
             // configure and return an implementation of Spring's KeyGenerator SPI
             return new MyKeyGenerator();
         }
    
     }
    

    由于您使用的是 XML 配置:

    <cache:annotation-driven key-generator="cacheKeyGenerator" />
    

    您的代码中不应有 @EnableCaching 注释,因为它可以覆盖您的 XML(将其从 FacadeImpl 中删除)。

    组件扫描覆盖

    您有一个root-context.xml 和一个servlet-context.xml 配置,但它们都在扫描相同 包。您的缓存配置在root-context.xml 中声明,因此此上下文中的 bean 已应用缓存,但是,bean 在您的 servlet-context.xml 中重复(因为它们被再次扫描),其中未应用缓存。

    由于您似乎并不真正需要根/Web 分离,我建议您只创建一个 ApplicationContext。为此:

    1) 从您的web.xml 中删除以下行

    <!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:root-context.xml</param-value>
    </context-param>
    
    <!-- Creates the Spring Container shared by all Servlets and Filters -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    

    2) 通过将以下内容添加到您的 servlet-context.xml 直接导入您的 root-context.xml 文件

    <beans:import resource="classpath:root-context.xml"/>
    

    提示

    最后一件看起来有点奇怪的事情是您依赖于密钥的toString() 方法。我很想直接使用 SimpleKey 类来满足您的需求:

    public Object generate(Object target, Method method, Object... params) {
        return new SimpleKey(method.getName(), params);
    }
    

    如果您可以公开提供复制问题的示例代码并将其作为堆栈溢出的链接提供,您也更有可能在此类问题上获得帮助。 GitHub 是托管示例项目的绝佳场所。另外请不要大喊这是BUG,直到你确定:)

    【讨论】:

    • 谢谢,我会采纳你的建议,但问题依然存在。请参阅我在原始帖子上的其他信息。好像是 Springs BUG。
    • @Cacheable(key="#spEL")这个key没有使用keyGenerator,如何解决?
    • 依赖于 key 的 toString() 方法——如果没有指定任何东西并且输入对象不是原语,spring 依赖什么?
    猜你喜欢
    • 2016-05-02
    • 1970-01-01
    • 2013-08-20
    • 2021-08-01
    • 1970-01-01
    • 2018-06-05
    • 2015-04-01
    • 1970-01-01
    • 2020-06-23
    相关资源
    最近更新 更多