【问题标题】:Caching in Spring on methods with array parameters在 Spring 中缓存具有数组参数的方法
【发布时间】:2013-08-02 19:11:06
【问题描述】:

我有一个包含多种方法的服务,并尝试使用 Spring @Cacheable 注释来缓存它们。一切正常,除了我发现以数组作为方法参数的方法没有被缓存。考虑到数组可以保存不同的值,这在某种程度上是有道理的,但我仍然认为这是可能的。

以下方法被缓存:

@Cacheable("myCache")
public Collection<Building> findBuildingByCode(String buildingCode) {...}

@Cacheable("myCache")
public Collection<Building> getBuildings() {...}

但是,如果我将findBuildingByCode 方法更改为以下任一方法,它不会被缓存:

@Cacheable("myCache") 
public Collection<Building> findBuildingByCode(String[] buildingCode) {...}

@Cacheable("myCache")
public Collection<Building> findBuildingByCode(String... buildingCode) {...}

这里是相关的Spring xml配置:

<!-- Cache beans -->
<cache:annotation-driven/>

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"
    p:cache-manager-ref="ehcache" />

<!-- EhCache library setup -->
<bean id="ehcache"
    class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />

Ehcache配置:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">

<diskStore path="java.io.tmpdir/ehcache" />

<!-- Default settings -->
<defaultCache eternal="false" maxElementsInMemory="1"
    overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0"
    timeToLiveSeconds="100" memoryStoreEvictionPolicy="LRU" />

<!-- Other caches -->

<cache name="myCache" eternal="false" maxElementsInMemory="500"
    overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0"
    timeToLiveSeconds="43200" memoryStoreEvictionPolicy="LRU" />

 </ehcache>

这是已知功能还是错误?

【问题讨论】:

    标签: java spring ehcache spring-annotations


    【解决方案1】:

    尝试这样定义缓存键:

    @Cacheable(value="myCache", key="#buildingCode.toString()")
    

    #buildingCode.hashCode()。因此缓存管理器将能够缓存该方法。

    【讨论】:

    【解决方案2】:

    对数组使用散列或字符串表示并不能在缓存方面定义唯一性。例如,数组包含 2 个或更多相同的条目或具有不同的顺序:hash/toString 将不同......但缓存键可能应该相同。 我要做的是在你的数组周围创建一个包装器......并创建一个 getCacheKey() 来做你需要做的任何事情......

    public class BuildCodesCacheWrapper {
    private String[] buildingCodes;
    
    private BuildCodesCacheWrapper(String[] buildingCodes) {
        super();
        this.buildingCodes = buildingCodes;
    }
    
    public String getCacheKey(){
        String key = "";
        if(null != buildingCodes){
            for(String code : buildingCodes){
                if(!key.contains("")){
                    key += code;
                }
            }
        }
        return key;
    }
    }
    

    (上面的代码未经测试,可以对所有类型的数组等更通用...)

    并在 SPEL 表达式中使用 getCacheKey() 方法...

    @Cacheable("myCache", key="#buildingCode.getCacheKey()") 
    public Collection<Building> findBuildingByCode(BuildCodesCacheWrapper buildingCode) {...}
    

    【讨论】:

    • 您可以在数组中使用 SortedSet,这样您就可以摆脱重复和顺序问题。
    【解决方案3】:

    只是扩展@Benoit 的回答:

    @Cacheable(value = "myCache", key = "T(java.util.Arrays).asList(#terms).hashCode()")

    在我的例子中,我使用扩展运算符将参数传递给可缓存函数,如下所示:

    @Cacheable(...) public Object func(String... terms)

    在 terms 数组上调用 toString 或 hashCode 每次都会产生不同的结果,但是将其转换为列表和 hashCoding 似乎可以解决问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-10
      • 2021-01-25
      • 2011-04-10
      • 1970-01-01
      • 2010-12-08
      • 2014-03-26
      • 1970-01-01
      相关资源
      最近更新 更多