新增缓存管理功能, 支持手动/自动刷新缓存, 查看、清理缓存。

This commit is contained in:
zhaojun1998
2020-05-24 15:41:33 +08:00
parent 84e9cce60f
commit 949c437653
9 changed files with 304 additions and 45 deletions

View File

@@ -0,0 +1,19 @@
package im.zhaojun.zfile.cache;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author zhaojun
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DriveCacheKey {
private Integer driveId;
private String key;
}

View File

@@ -0,0 +1,43 @@
package im.zhaojun.zfile.cache;
import cn.hutool.cache.impl.CacheObj;
import cn.hutool.cache.impl.TimedCache;
import im.zhaojun.zfile.context.DriveContext;
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
import im.zhaojun.zfile.util.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
/**
* @author zhaojun
*/
@Slf4j
public class MyTimedCache<K, V> extends TimedCache<K, V> {
private DriveContext driveContext;
public MyTimedCache(long timeout) {
super(timeout);
}
public MyTimedCache(long timeout, Map<K, CacheObj<K, V>> map) {
super(timeout, map);
}
@Override
protected void onRemove(K key, V cachedObject) {
log.debug("尝试刷新缓存: " + key);
if (driveContext == null) {
driveContext = SpringContextHolder.getBean(DriveContext.class);
}
DriveCacheKey cacheKey = (DriveCacheKey) key;
AbstractBaseFileService baseFileService = driveContext.getDriveService(cacheKey.getDriveId());
try {
baseFileService.fileList(cacheKey.getKey());
} catch (Exception e) {
log.error("尝试刷新驱动器 {} 的 {} 失败, ", cacheKey.getDriveId(), cacheKey.getKey());
e.printStackTrace();
}
}
}

View File

@@ -1,8 +1,6 @@
package im.zhaojun.zfile.cache;
import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.CacheObj;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.util.StrUtil;
import im.zhaojun.zfile.model.constant.ZFileConstant;
import im.zhaojun.zfile.model.dto.FileItemDTO;
@@ -33,6 +31,9 @@ public class ZFileCache {
@Value("${zfile.cache.timeout}")
private long timeout;
@Value("${zfile.cache.auto-refresh.interval}")
private long autoRefreshInterval;
/**
* 缓存 map 对象.
@@ -44,7 +45,7 @@ public class ZFileCache {
* key: 文件夹路径
* value: 文件夹中内容
*/
private ConcurrentMap<Integer, TimedCache<String, List<FileItemDTO>>> drivesCache = new ConcurrentHashMap<>();
private ConcurrentMap<Integer, MyTimedCache<DriveCacheKey, List<FileItemDTO>>> drivesCache = new ConcurrentHashMap<>();
/**
* 系统设置缓存
@@ -68,7 +69,7 @@ public class ZFileCache {
* 文件夹中列表
*/
public synchronized void put(Integer driveId, String key, List<FileItemDTO> value) {
getCacheByDriveId(driveId).put(key, value);
getCacheByDriveId(driveId).put(new DriveCacheKey(driveId, key), value);
}
@@ -84,7 +85,7 @@ public class ZFileCache {
* @return 驱动器中文件夹的内容
*/
public List<FileItemDTO> get(Integer driveId, String key) {
return getCacheByDriveId(driveId).get(key, false);
return getCacheByDriveId(driveId).get(new DriveCacheKey(driveId, key), false);
}
@@ -161,10 +162,10 @@ public class ZFileCache {
* @return 所有缓存 key
*/
public Set<String> keySet(Integer driveId) {
Iterator<CacheObj<String, List<FileItemDTO>>> cacheObjIterator = getCacheByDriveId(driveId).cacheObjIterator();
Iterator<CacheObj<DriveCacheKey, List<FileItemDTO>>> cacheObjIterator = getCacheByDriveId(driveId).cacheObjIterator();
Set<String> keys = new HashSet<>();
while (cacheObjIterator.hasNext()) {
keys.add(cacheObjIterator.next().getKey());
keys.add(cacheObjIterator.next().getKey().getKey());
}
return keys;
}
@@ -180,7 +181,7 @@ public class ZFileCache {
* 文件夹路径
*/
public void remove(Integer driveId, String key) {
getCacheByDriveId(driveId).remove(key);
getCacheByDriveId(driveId).remove(new DriveCacheKey(driveId, key));
}
@@ -241,14 +242,74 @@ public class ZFileCache {
*
* @return 驱动器对应的缓存
*/
private synchronized TimedCache<String, List<FileItemDTO>> getCacheByDriveId(Integer driveId) {
TimedCache<String, List<FileItemDTO>> driveCache = drivesCache.get(driveId);
private synchronized MyTimedCache<DriveCacheKey, List<FileItemDTO>> getCacheByDriveId(Integer driveId) {
MyTimedCache<DriveCacheKey, List<FileItemDTO>> driveCache = drivesCache.get(driveId);
if (driveCache == null) {
driveCache = CacheUtil.newTimedCache(timeout * 1000);
driveCache = new MyTimedCache<>(timeout * 1000);
drivesCache.put(driveId, driveCache);
startAutoCacheRefresh(driveId);
}
return driveCache;
}
/**
* 获取指定驱动器的缓存命中数
*
* @param driveId
* 驱动器 ID
*
* @return 缓存命中数
*/
public int getHitCount(Integer driveId) {
return getCacheByDriveId(driveId).getHitCount();
}
/**
* 获取指定驱动器的缓存未命中数
*
* @param driveId
* 驱动器 ID
*
* @return 缓存未命中数
*/
public int getMissCount(Integer driveId) {
return getCacheByDriveId(driveId).getMissCount();
}
/**
* 开启缓存自动刷新, 仅当数据库设置为开启时, 才会真正开启缓存自动刷新.
*
* @param driveId
* 驱动器 ID
*/
public void startAutoCacheRefresh(Integer driveId) {
DriveConfig driveConfig = driverConfigRepository.findById(driveId).get();
Boolean autoRefreshCache = driveConfig.getAutoRefreshCache();
if (autoRefreshCache != null && autoRefreshCache) {
MyTimedCache<DriveCacheKey, List<FileItemDTO>> driveCache = drivesCache.get(driveId);
if (driveCache == null) {
driveCache = new MyTimedCache<>(timeout * 1000);
drivesCache.put(driveId, driveCache);
}
driveCache.schedulePrune(autoRefreshInterval * 1000);
}
}
/**
* 停止缓存自动刷新
*
* @param driveId
* 驱动器 ID
*/
public void stopAutoCacheRefresh(Integer driveId) {
MyTimedCache<DriveCacheKey, List<FileItemDTO>> driveCache = drivesCache.get(driveId);
if (driveCache != null) {
driveCache.cancelPruneSchedule();
}
}
}

View File

@@ -1,7 +1,9 @@
package im.zhaojun.zfile.controller.admin;
import im.zhaojun.zfile.model.dto.CacheInfoDTO;
import im.zhaojun.zfile.model.dto.ResultBean;
import im.zhaojun.zfile.service.DriveConfigService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -21,17 +23,50 @@ public class CacheController {
@Resource
private DriveConfigService driveConfigService;
@PostMapping("/{driveId}/enable")
public ResultBean enableCache(@PathVariable("driveId") Integer driveId) {
driveConfigService.updateCacheStatus(driveId, true);
return ResultBean.success();
}
@PostMapping("/{driveId}/disable")
public ResultBean disableCache(@PathVariable("driveId") Integer driveId) {
driveConfigService.updateCacheStatus(driveId, false);
return ResultBean.success();
}
@GetMapping("/{driveId}/info")
public ResultBean cacheInfo(@PathVariable("driveId") Integer driveId) {
CacheInfoDTO cacheInfo = driveConfigService.findCacheInfo(driveId);
return ResultBean.success(cacheInfo);
}
@PostMapping("/{driveId}/refresh")
public ResultBean refreshCache(@PathVariable("driveId") Integer driveId, String key) throws Exception {
driveConfigService.refreshCache(driveId, key);
return ResultBean.success();
}
@PostMapping("/{driveId}/auto-refresh/start")
public ResultBean enableAutoRefresh(@PathVariable("driveId") Integer driveId) {
driveConfigService.startAutoCacheRefresh(driveId);
return ResultBean.success();
}
@PostMapping("/{driveId}/auto-refresh/stop")
public ResultBean disableAutoRefresh(@PathVariable("driveId") Integer driveId) {
driveConfigService.stopAutoCacheRefresh(driveId);
return ResultBean.success();
}
@PostMapping("/{driveId}/clear")
public ResultBean clearCache(@PathVariable("driveId") Integer driveId) {
driveConfigService.clearCache(driveId);
return ResultBean.success();
}
}

View File

@@ -0,0 +1,23 @@
package im.zhaojun.zfile.model.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Set;
/**
* @author zhaojun
*/
@Data
@AllArgsConstructor
public class CacheInfoDTO {
private Integer cacheCount;
private Integer hitCount;
private Integer missCount;
private Set<String> cacheKeys;
}

View File

@@ -1,8 +1,11 @@
package im.zhaojun.zfile.service;
import im.zhaojun.zfile.cache.ZFileCache;
import im.zhaojun.zfile.context.DriveContext;
import im.zhaojun.zfile.context.StorageTypeContext;
import im.zhaojun.zfile.exception.InitializeException;
import im.zhaojun.zfile.model.constant.StorageConfigConstant;
import im.zhaojun.zfile.model.dto.CacheInfoDTO;
import im.zhaojun.zfile.model.dto.DriveConfigDTO;
import im.zhaojun.zfile.model.dto.StorageStrategyConfig;
import im.zhaojun.zfile.model.entity.DriveConfig;
@@ -11,7 +14,6 @@ import im.zhaojun.zfile.model.enums.StorageTypeEnum;
import im.zhaojun.zfile.repository.DriverConfigRepository;
import im.zhaojun.zfile.repository.StorageConfigRepository;
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
import im.zhaojun.zfile.context.DriveContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
@@ -21,6 +23,7 @@ import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
* 驱动器 Service 类
@@ -39,6 +42,9 @@ public class DriveConfigService {
@Resource
private DriveContext driveContext;
@Resource
private ZFileCache zFileCache;
public static final Class<StorageStrategyConfig> STORAGE_STRATEGY_CONFIG_CLASS = StorageStrategyConfig.class;
/**
@@ -60,7 +66,7 @@ public class DriveConfigService {
* @return 驱动器设置
*/
public DriveConfig findById(Integer id) {
return driverConfigRepository.getOne(id);
return driverConfigRepository.findById(id).get();
}
@@ -137,6 +143,12 @@ public class DriveConfigService {
BeanUtils.copyProperties(driveConfigDTO, driveConfig);
driverConfigRepository.save(driveConfig);
if (driveConfig.getAutoRefreshCache()) {
startAutoCacheRefresh(driveConfig.getId());
} else {
stopAutoCacheRefresh(driveConfig.getId());
}
// 保存存储策略设置.
StorageStrategyConfig storageStrategyConfig = driveConfigDTO.getStorageStrategyConfig();
@@ -221,4 +233,97 @@ public class DriveConfigService {
driverConfigRepository.save(driveConfig);
}
}
/**
* 更新指定驱动器的缓存启用状态
*
* @param driveId
* 驱动器 ID
*
* @param autoRefreshCache
* 是否启用缓存自动刷新
*/
public void updateAutoRefreshCacheStatus(Integer driveId, Boolean autoRefreshCache) {
DriveConfig driveConfig = findById(driveId);
if (driveConfig != null) {
driveConfig.setAutoRefreshCache(autoRefreshCache);
driverConfigRepository.save(driveConfig);
}
}
/**
* 获取指定驱动器的缓存信息
* @param driveId
* 驱动器 ID
* @return 缓存信息
*/
public CacheInfoDTO findCacheInfo(Integer driveId) {
int hitCount = zFileCache.getHitCount(driveId);
int missCount = zFileCache.getMissCount(driveId);
Set<String> keys = zFileCache.keySet(driveId);
int cacheCount = keys.size();
return new CacheInfoDTO(cacheCount, hitCount, missCount, keys);
}
/**
* 刷新指定 key 的缓存:
* 1. 清空此 key 的缓存.
* 2. 重新调用方法写入缓存.
*
* @param driveId
* 驱动器 ID
*
* @param key
* 缓存 key (文件夹名称)
*/
public void refreshCache(Integer driveId, String key) throws Exception {
zFileCache.remove(driveId, key);
AbstractBaseFileService baseFileService = driveContext.getDriveService(driveId);
baseFileService.fileList(key);
}
/**
* 开启缓存自动刷新, 仅当数据库设置为开启时, 才会真正开启缓存自动刷新.
*
* @param driveId
* 驱动器 ID
*/
public void startAutoCacheRefresh(Integer driveId) {
DriveConfig driveConfig = findById(driveId);
driveConfig.setAutoRefreshCache(true);
driverConfigRepository.save(driveConfig);
zFileCache.startAutoCacheRefresh(driveId);
}
/**
* 停止缓存自动刷新
*
* @param driveId
* 驱动器 ID
*/
public void stopAutoCacheRefresh(Integer driveId) {
DriveConfig driveConfig = findById(driveId);
driveConfig.setAutoRefreshCache(false);
driverConfigRepository.save(driveConfig);
zFileCache.stopAutoCacheRefresh(driveId);
}
/**
* 清理缓存
*
* @param driveId
* 驱动器 ID
*/
public void clearCache(Integer driveId) {
zFileCache.clear(driveId);
}
}

View File

@@ -140,21 +140,6 @@ public abstract class AbstractBaseFileService implements BaseFileService {
}
/**
* 刷新指定 key 的缓存:
* 1. 清空此 key 的缓存.
* 2. 重新调用方法写入缓存.
*
* @param key
* 缓存 key (文件夹名称)
*/
public void refreshCache(String key) throws Exception {
zFileCache.remove(driveId, key);
BaseFileService currentFileService = (BaseFileService) AopContext.currentProxy();
currentFileService.fileList(key);
}
/**
* 获取单个文件信息
*