ehcache3-spring
ehcache3和spring都支持jcache,二者必然可以很方便的整合在一起。
<!--开启spring cache注解--> <cache:annotation-driven mode="proxy" cache-manager="cacheManager"/> <!--CacheManager--> <bean id="cacheManager" class="org.springframework.cache.jcache.JCacheCacheManager"> <property name="cacheManager" ref="jCacheManagerFactory"/> </bean> <!--这里的JCacheManagerFactory就相当于CachingProvider,通过CachingProvider就可以得到CacheManager,--> <!--JCacheManagerFactoryBean是一个FactoryBean,通过getObject可以得到CacheManager实例--> <bean id="jCacheManagerFactory" class="org.springframework.cache.jcache.JCacheManagerFactoryBean"> <!--这里只能配置一个ehcache文件--> <property name="cacheManagerUri" value="classpath:ehcache.xml" /> </bean>
下面的afterPropertiesSet是JCacheManagerFactoryBean的逻辑,JCacheManagerFactoryBean通过getObject方法将cacheManager注入JCacheCacheManager中。
但是这样整合是存在问题的,下面是org.springframework.cache.jcache.JCacheCacheManager的一段逻辑,当ehcache配置的cache声明了非Object的keyType、valueType这里就会出现问题。那是不是说将keyType、valueType均设置为Object,或不进行设置(默认为Object)就可以了呢?
的确可行,我们可以进行类似如下的配置,但如果我们需要一种灵活的serializer配置,比如我希望有若干个default serializer,这若干个default serializer是针对若干个特定class进行序列化的,这种配置虽然可以继续使用,但显然不太合适,我是反感这种“含糊”的配置的,我更喜欢“精确”的配置(即指定key-type、value-type)。
1 <cache alias="off-heap-cache"> 2 <!--可以为key、value指定serializer,也可以在cacheManager级别指定Object的默认serializer--> 3 <key-type serializer="com.zyong.spring.ehcache.BaseSerializer"/> 4 <value-type serializer="com.zyong.spring.ehcache.BaseSerializer"/> 5 <expiry> 6 <tti unit="minutes">5</tti> 7 </expiry> 8 <resources> 9 <heap>1</heap> 10 <offheap unit="MB">1</offheap> 11 </resources> 12 </cache>
那么,如何让配置变得“精确”,又能适配spring呢?这里,我对JCacheCacheManager做了一些扩展,在spring与ehcache整合的配置文件中,将原JCacheCacheManager替换为该JCacheEhCacheManager 即可,这样就可以在ehcache配置文件中指定key-type、value-type了。
1 public class JCacheEhCacheManager extends org.springframework.cache.jcache.JCacheCacheManager { 2 @Override 3 protected Collection<Cache> loadCaches() { 4 Collection<Cache> caches = new LinkedHashSet<Cache>(); 5 EhcacheManager ehcacheManager; 6 try { 7 ehcacheManager = getCacheManager().unwrap(EhcacheManager.class); 8 } catch (Exception e) { 9 //如果不是Ehcache,则使用原loadCaches 10 return super.loadCaches(); 11 } 12 Set<Map.Entry<String, CacheConfiguration<?, ?>>> entries = ehcacheManager.getRuntimeConfiguration().getCacheConfigurations().entrySet(); 13 for (Map.Entry<String, CacheConfiguration<?, ?>> entry : entries) { 14 //获取cache配置 15 CacheConfiguration<?, ?> cacheConfiguration = entry.getValue(); 16 //通过cacheName、keyType、valueType获取cache 17 javax.cache.Cache jcache = getCacheManager().getCache(entry.getKey() 18 , cacheConfiguration.getKeyType() 19 , cacheConfiguration.getValueType()); 20 caches.add(new JCacheCache(jcache, isAllowNullValues())); 21 } 22 return caches; 23 } 24 }