Guava Cache
Google Guava Cache是一種非常優秀本地緩存解決方案,提供了基于容量,時間和引用的緩存回收方式。
怎麼用?
引入依賴
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
相關加載緩存代碼
public class GiteaUserServiceImpl implements GiteaUserService {
// 緩存的list
private LoadingCache<String, Optional<CommonUserDto>> emailUserList;
// 在項目啟動的時候構造緩存
@PostConstruct
public void init() {
// 設定兩小時的過期時間
emailUserList = CacheBuilder.newBuilder().expireAfterWrite(2, TimeUnit.HOURS).build(new CacheLoader<String, Optional<CommonUserDto>>() {
// 緩存失效之後的重新加載邏輯
@Override
public Optional<CommonUserDto> load(String email) {
CommonUserDto commonUserDto = null;
try {
commonUserDto = giteaExService.qryUserDtoByEmail(email);
}
catch (Exception e) {
logger.error("LoadingCache Portal User error...", e);
}
return Optional.ofNullable(commonUserDto);
}
});
// 加載緩存
this.loadUserDtoList();
}
/**
* 查詢并且構造使用者集合
*/
private void loadUserDtoList() {
// 查詢全量使用者
List<CommonUserDto> userDtoList = giteaExService.qryUserDtoList();
// 加載緩存
userDtoList.stream()
.filter(commonUserDto -> !ObjectUtils.isEmpty(commonUserDto) && StringUtils.isNotEmpty(commonUserDto.getEmail()))
.forEach(commonUserDto -> {
// 構造email緩存
emailUserList.put(commonUserDto.getEmail(), Optional.of(commonUserDto));
});
}
}
load方法是緩存失效之後的重新加載邏輯,因為guava cache不允許出現null,是以使用Optional作為容器,設定null;
ehcache
Ehcache主要基于記憶體緩存,磁盤緩存為輔的,使用起來友善。支援緩存内容存儲在磁盤中。
使用方式
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.4</version>
</dependency>
在項目資源目錄下建立一個ehcache.xml檔案,檔案内容參考如下:
<ehcache>
<diskStore path = "./cache"/>
<!-- 預設的管理政策 -->
<defaultCache
eternal = "false"
maxElementsInMemory = "10000"
overflowToDisk = "true"
diskPersistent = "false"
timeToIdleSeconds = "604800"
timeToLiveSeconds = "7200"
diskExpiryThreadIntervalSeconds = "120"
memoryStoreEvictionPolicy = "LRU"/>
<!-- 此緩存最多可以存活timeToLiveSeconds秒,如果期間超過timeToIdleSeconds秒未通路,緩存失效 -->
<cache
name = "defaultCache"
eternal = "false"
maxElementsInMemory = "80000"
overflowToDisk = "true"
diskPersistent = "false"
timeToIdleSeconds = "604800"
timeToLiveSeconds = "604800"
memoryStoreEvictionPolicy = "LRU"/>
<!-- maxElementsInMemory 記憶體中最大緩存對象數,看着自己的heap大小來搞 -->
<!-- eternal:true表示對象永不過期,此時會忽略timeToIdleSeconds和timeToLiveSeconds屬性,預設為false -->
<!-- maxElementsOnDisk:硬碟中最大緩存對象數,若是0表示無窮大 -->
<!-- overflowToDisk:true表示當記憶體緩存的對象數目達到了maxElementsInMemory界限後,
會把溢出的對象寫到硬碟緩存中。注意:如果緩存的對象要寫入到硬碟中的話,則該對象必須實作了Serializable接口才行。-->
<!-- diskSpoolBufferSizeMB:磁盤緩存區大小,預設為30MB。每個Cache都應該有自己的一個緩存區。-->
<!-- diskPersistent:是否緩存虛拟機重新開機期資料 -->
<!-- diskExpiryThreadIntervalSeconds:磁盤失效線程運作時間間隔,預設為120秒 -->
<!-- timeToIdleSeconds: 設定允許對象處于空閑狀态的最長時間,以秒為機關。當對象自從最近一次被通路後,
如果處于空閑狀态的時間超過了timeToIdleSeconds屬性值,這個對象就會過期,
EHCache将把它從緩存中清空。隻有當eternal屬性為false,該屬性才有效。如果該屬性值為0,
則表示對象可以無限期地處于空閑狀态 -->
<!-- timeToLiveSeconds:設定對象允許存在于緩存中的最長時間,以秒為機關。當對象自從被存放到緩存中後,
如果處于緩存中的時間超過了 timeToLiveSeconds屬性值,這個對象就會過期,
EHCache将把它從緩存中清除。隻有當eternal屬性為false,該屬性才有效。如果該屬性值為0,
則表示對象可以無限期地存在于緩存中。timeToLiveSeconds必須大于timeToIdleSeconds屬性,才有意義 -->
<!-- memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,
Ehcache将會根據指定的政策去清理記憶體。可選政策有:LRU(最近最少使用,預設政策)、
FIFO(先進先出)、LFU(最少通路次數)。-->
</ehcache>
注入bean的方式構造cacheManager
@Configuration
public class EhCacheConfig {
/**
* 據shared與否的設定,Spring分别通過CacheManager.create()或new CacheManager()方式來建立一個ehcache基地.
*/
@Bean
public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() {
EhCacheManagerFactoryBean cacheManagerFactoryBean = new EhCacheManagerFactoryBean();
cacheManagerFactoryBean.setConfigLocation(new ClassPathResource("ehcache.xml"));
cacheManagerFactoryBean.setShared(true);
return cacheManagerFactoryBean;
}
}
寫一個緩存工具類
@Component
@EnableCaching
public class CacheUtils {
private static Cache cache;
private static final String CACHE_NAME = "defaultCache";
@Autowired
private EhCacheCacheManager ehCacheCacheManager;
public static void put(String key, Object value) {
put(CACHE_NAME, key, value);
}
public static Object get(String key) {
Element element = cache.get(key);
if (null != element) {
return element.getObjectValue();
}
return element;
}
@PostConstruct
private void init() {
EhCacheCacheManager ehCacheCacheManager = ApplicationContextHelper.getBean(EhCacheCacheManager.class);
CacheManager cacheManager = ehCacheCacheManager.getCacheManager();
try {
cache = cacheManager.getCache(CACHE_NAME);
if (cache == null) {
throw new RuntimeException("目前系統中沒有定義“" + CACHE_NAME + "”這個緩存。");
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* 寫入緩存 通用方法
*
* @param cacheName
* @param key
* @param value
*/
private static void put(String cacheName, String key, Object value) {
Element element = new Element(key, value);
cache.put(element);
}
}
以上是兩種本地緩存的架構的簡單使用,個人使用來看Google的緩存更加簡單實用。