我尝试在4.3版本的项目中使用ehcache3
。
我配置了缓存管理器:
<cache:annotation-driven />
<bean id="cacheManager" class="org.springframework.cache.jcache.JCacheCacheManager">
<property name="cacheManager">
<bean class="org.springframework.cache.jcache.JCacheManagerFactoryBean">
<property name="cacheManagerUri" value="classpath:ehcache.xml"/>
</bean>
</property>
</bean>
ehcache.xml :
<config
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3'
xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
xsi:schemaLocation="
http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd" >
<service>
<jsr107:defaults enable-statistics="true" enable-management="true"/>
</service>
<cache alias="customerSettings">
<key-type>java.lang.Long</key-type>
<expiry>
<none/>
</expiry>
<resources>
<heap>500</heap>
</resources>
</cache>
</config>
但是当我部署项目时,我有一个例外:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cacheManager' defined in ServletContext resource [/WEB-INF/spring/root-context.xml]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Cache [customerSettings] specifies key/value types. Use getCache(String, Class, Class)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
... 100 more
Caused by: java.lang.IllegalArgumentException: Cache [customerSettings] specifies key/value types. Use getCache(String, Class, Class)
at org.ehcache.jsr107.Eh107CacheManager.getCache(Eh107CacheManager.java:297)
at org.springframework.cache.jcache.JCacheCacheManager.loadCaches(JCacheCacheManager.java:105)
at org.springframework.cache.support.AbstractCacheManager.initializeCaches(AbstractCacheManager.java:61)
at org.springframework.cache.support.AbstractCacheManager.afterPropertiesSet(AbstractCacheManager.java:50)
at org.springframework.cache.jcache.JCacheCacheManager.afterPropertiesSet(JCacheCacheManager.java:97)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624)
... 107 more
如果我删除:
<key-type>java.lang.Long</key-type>
它的工作正常,但缓存的keyType是Object, 需要做什么,我可以使用自己的密钥类型和值类型?
答案 0 :(得分:4)
Spring cache is not typed,所以它没有使用Jcache (javax.cache / JSR-107 caching API)
的类型化API既然你在ehcache.xml中指定了类型,那么Ehcache拒绝让Spring使用getCache()的非类型签名
当你考虑它时,如果你让Spring使用Ehcache(via @CacheResult and other JCache annotations for example),你必须让它为你选择什么是关键和值类型 - 它不再是你应该指定的人类型。
答案 1 :(得分:1)
正如您在org.springframework.cache.jcache.JCacheCacheManager的源代码中所看到的,Spring并不了解它应该使用方法getCache(String,Class,Class)而不是简单的getCache(String)。更确切地说,这个类对getCache(String,Class,Class)一无所知。
所以你有三种方式:
在get和put操作期间不执行任何操作缓存使用equals(),并且可能是来自密钥的真实类的hashCode()方法。如果您使用直接访问缓存而不是通过注释进行声明式访问,那么只有在显式类型转换中才会感到不适。
扩展此类并研究它以了解这些缓存配置功能。</ p>
查看可能知道这些设置的另一个CacheManager。
答案 2 :(得分:0)
好的,你必须要破解一下:
编写自定义CacheManager
并在配置xml:
<bean id="cacheManager" class="your.path.MyCustomLongObjectJCacheManager">
<property name="cacheManager">
<bean class="org.springframework.cache.jcache.JCacheManagerFactoryBean">
<property name="cacheManagerUri" value="classpath:ehcache.xml"/>
</bean>
</property>
</bean>
这是一些(伪)代码:
public class MyCustomLongObjectJCacheManager extends JCacheCacheManager{
@Override
protected Collection<Cache> loadCaches() {
javax.cache.CacheManager cacheManager = getCacheManager();
Collection<Cache> caches = new LinkedHashSet<Cache>();
for (String cacheName : getCacheManager().getCacheNames()) {
if("customerSettings".equals(cacheName)){ // or manager instance of Eh107CacheManager...
javax.cache.Cache<Long, Object> jcache = cacheManager.getCache(cacheName, Long.class, Object.class);
caches.add(new MyCustomAdaptingCache(jcache, isAllowNullValues()));
} else {
javax.cache.Cache<Object, Object> jcache = cacheManager.getCache(cacheName);
caches.add(new JCacheCache(jcache, isAllowNullValues()));
}
}
return caches;
}
@Override
protected Cache getMissingCache(String cacheName) {
// Check the JCache cache again (in case the cache was added at runtime)
javax.cache.CacheManager cacheManager = getCacheManager();
if("customerSettings".equals(cacheName)){
javax.cache.Cache<Long, Object> jcache = cacheManager.getCache(cacheName, Long.class, Object.class);
return new MyCustomAdaptingCache(jcache, isAllowNullValues());
}
javax.cache.Cache<Object, Object> jcache = getCacheManager().getCache(cacheName);
if (jcache != null) {
return new JCacheCache(jcache, isAllowNullValues());
}
return null;
}
}
public static class MyCustomAdaptingCache extends AbstractValueAdaptingCache {
private final javax.cache.Cache<Long, Object> cache;
public MyCustomAdaptingCache(javax.cache.Cache<Long, Object> jcache) {
this(jcache, true);
}
public MyCustomAdaptingCache(javax.cache.Cache<Long, Object> jcache, boolean allowNullValues) {
super(allowNullValues);
Assert.notNull(jcache, "Cache must not be null");
this.cache = jcache;
}
@Override
public final String getName() {
return this.cache.getName();
}
@Override
public final javax.cache.Cache<Long, Object> getNativeCache() {
return this.cache;
}
@Override
protected Object lookup(Object key) {
return this.cache.get((Long)key);
}
@Override
public <T> T get(Object key, Callable<T> valueLoader) {
try {
return this.cache.invoke((Long)key, new ValueLoaderEntryProcessor<T>(), valueLoader);
}
catch (EntryProcessorException ex) {
throw new ValueRetrievalException(key, valueLoader, ex.getCause());
}
}
@Override
public void put(Object key, Object value) {
this.cache.put((Long)key, toStoreValue(value));
}
@Override
public ValueWrapper putIfAbsent(Object key, Object value) {
boolean set = this.cache.putIfAbsent((Long)key, toStoreValue(value));
return (set ? null : get(key));
}
@Override
public void evict(Object key) {
this.cache.remove((Long)key);
}
@Override
public void clear() {
this.cache.removeAll();
}
private class ValueLoaderEntryProcessor<T> implements EntryProcessor<Long, Object, T> {
@SuppressWarnings("unchecked")
@Override
public T process(MutableEntry<Long, Object> entry, Object... arguments)
throws EntryProcessorException {
Callable<T> valueLoader = (Callable<T>) arguments[0];
if (entry.exists()) {
return (T) fromStoreValue(entry.getValue());
}
else {
T value;
try {
value = valueLoader.call();
}
catch (Exception ex) {
throw new EntryProcessorException("Value loader '" + valueLoader + "' failed " +
"to compute value for key '" + entry.getKey() + "'", ex);
}
entry.setValue(toStoreValue(value));
return value;
}
}
}
}
祝你好运。