Java Spring中引入了对Cache的支持,并通过@Cacheable来完成对某个方法的执行进行缓存。
其核心思想是:在调用缓存方法时,把方法的输入参数作为缓存的key,把方法的输出结构作为缓存的value。

使用时,一般按下面步骤执行:

  1. 声明程序支持@Caching
  2. 对具体的方法声明使用缓存

Spring对应的实现非常灵活,很容易支持使用外部的缓存,这里分别以google guavaehcache为例来说明怎么使用

集成google guava

使用时很简单,代码如下:

添加maven依赖

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>

声明支持@Caching, 并创建CacheConfig

通过@EnableCache来声明对@Caching的支持,创建CacheConfig并定义不同的缓存策略,代码如下:

import com.google.common.cache.CacheBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.guava.GuavaCache;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.interceptor.SimpleKeyGenerator;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;

@Configuration
@EnableCaching
public class CacheConfig implements CachingConfigurer {

public final static String CACHE_ONE = "cacheOne";
public final static String CACHE_TWO = "cacheTwo";

private final Logger log = LoggerFactory
.getLogger(CacheConfig.class);

@Bean
@Override
public CacheManager cacheManager() {
log.info("Initializing simple Guava Cache manager.");
SimpleCacheManager cacheManager = new SimpleCacheManager();

GuavaCache cache1 = new GuavaCache(CACHE_ONE, CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.build());

GuavaCache cache2 = new GuavaCache(CACHE_TWO, CacheBuilder.newBuilder()
.expireAfterWrite(60, TimeUnit.SECONDS)
.build());

cacheManager.setCaches(Arrays.asList(cache1,cache2));

return cacheManager;
}

@Override
public CacheResolver cacheResolver() {
return null;
}

@Bean
@Override
public KeyGenerator keyGenerator() {
return new SimpleKeyGenerator();
}

@Override
public CacheErrorHandler errorHandler() {
return null;
}
}

对具体的方法声明使用缓存

如果某一个方法要使用缓存,可以在方法上添加@Cacheable注解,并指定对应的缓存策略名称,如下:

@Service
public class CachedService extends WebServiceGatewaySupport implements CachedService {

@Inject
private RestTemplate restTemplate;

@Cacheable(CacheConfig.CACHE_ONE)
public String getCached() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> reqEntity = new HttpEntity<>("url", headers);
return restTemplate.exchange("url", HttpMethod.GET, reqEntity, String.class).getBody();
}
}

集成ehcache

添加maven依赖

<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>

声明程序支持@Caching

通过@EnableCache来声明对@Caching的支持,创建CacheConfig并定义不同的缓存策略,代码如下:

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

@Configuration
@EnableCaching
@ComponentScan({ "com.demo.*" })
public class AppConfig {
@Bean
public CacheManager cacheManager() {
return new EhCacheCacheManager(ehCacheCacheManager().getObject());
}

@Bean
public EhCacheManagerFactoryBean ehCacheCacheManager() {
EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
cmfb.setConfigLocation(new ClassPathResource("main/resource/ehcache.xml"));
cmfb.setShared(true);
return cmfb;
}
}

这里对cache的定义放在了main/resource/ehcache.xml配置文件中了,示例文件内容:

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true"
monitoring="autodetect"
dynamicConfig="true">


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

<cache name="cache1"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="1000"
eternal="false"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="300" timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU"
transactionalMode="off">

<persistence strategy="localTempSwap" />
</cache>
</ehcache>

对具体的方法声明使用缓存

@Cacheable("cache1")
public User getUser(String name) {
// TODO
return null;
}

关闭ehcache instance

web.xml中配置对应的listener,应用程序销毁时,同时关闭ehcache实例。

<!-- ehcache 磁盘缓存 监控,持久化恢复 -->
<listener>
<listener-class>net.sf.ehcache.constructs.web.ShutdownListener</listener-class>
</listener>

参考文章

google guava

ehcache