演示代码
本地缓存数据存入文件
public static void testQ15() {
LinkedBlockingDeque<ConcurrentHashMap<String, ConcurrentHashMap<Integer, Integer>>> failureStatusCache = new LinkedBlockingDeque<>(4);
LinkedBlockingDeque<ConcurrentHashMap<String, ConcurrentHashMap<Integer, Integer>>> successStatusCache = new LinkedBlockingDeque<>(4);
LinkedBlockingDeque<ConcurrentHashMap<String, Integer>> pushedStateCache = new LinkedBlockingDeque<>(4);
ObjectOutputStream oos = null;
ConcurrentHashMap<String, ConcurrentHashMap<Integer, Integer>> mapF = new ConcurrentHashMap<>();
mapF.put("失败数据", new ConcurrentHashMap<Integer, Integer>() {{
put(1, 0);
}});
failureStatusCache.add(mapF);
ConcurrentHashMap<String, ConcurrentHashMap<Integer, Integer>> mapS = new ConcurrentHashMap<>();
mapS.put("成功数据", new ConcurrentHashMap<Integer, Integer>() {{
put(2, 0);
}});
successStatusCache.add(mapS);
pushedStateCache.add(new ConcurrentHashMap<String, Integer>() {{
put("哈哈哈", 3);
}});
log.info("【SoulCache - saveData】持久化数据到文件");
try {
oos = new ObjectOutputStream(Files.newOutputStream(Paths.get(PersistencePath.createFile("tzh"))));
oos.writeObject(failureStatusCache);
oos.writeObject(successStatusCache);
oos.writeObject(pushedStateCache);
log.info("【SoulCache - saveData】持久化数据到文件 | 结束");
} catch (Exception e) {
log.error("保存持久化文件异常", e);
} finally {
try {
if (oos != null) {
oos.close();
}
} catch (IOException ioe) {
log.error("IO流关闭异常", ioe);
}
}
}
从文件提取数据到本地缓存
public static void testQ16() {
ObjectInputStream ois = null;
try {
String path = PersistencePath.getPath("tzh");
log.info("【SoulCache - loadData】加载到内存开始... | path:{}", path);
ois = new ObjectInputStream(Files.newInputStream(Paths.get(path)));
LinkedBlockingDeque<ConcurrentHashMap<String, ConcurrentHashMap<Integer, Integer>>> failureStatusCache = (LinkedBlockingDeque<ConcurrentHashMap<String, ConcurrentHashMap<Integer, Integer>>>) ois.readObject();
LinkedBlockingDeque<ConcurrentHashMap<String, ConcurrentHashMap<Integer, Integer>>> successStatusCache = (LinkedBlockingDeque<ConcurrentHashMap<String, ConcurrentHashMap<Integer, Integer>>>) ois.readObject();
LinkedBlockingDeque<ConcurrentHashMap<String, Integer>> pushedStateCache = (LinkedBlockingDeque<ConcurrentHashMap<String, Integer>>) ois.readObject();
System.out.println("失败数据:"+failureStatusCache.getFirst().toString());
System.out.println("成功数据:"+successStatusCache.getFirst().toString());
System.out.println(pushedStateCache.getFirst().toString());
log.info("【SoulCache - loadData】加载到内存 结束");
} catch (Exception e) {
log.error("加载内存持久化文件异常", e);
} finally {
try {
if (ois != null) {
ois.close();
}
PersistencePath.delFile("tzh");
} catch (IOException ioe) {
log.error("IO流关闭异常", ioe);
}
}
}
工具类
public class PersistencePath {
private static final Logger logger = LoggerFactory.getLogger(PersistencePath.class);
private static AtomicInteger aofVersion = new AtomicInteger(0);
private final static String path = "/Users/zeki/test/";
public static String serverId="1";
public static String serverName="titan";
private static String getAofVersion(){
String _v = DateUtil.formatDateyyyyMMddHHmmss(System.currentTimeMillis()) + "_" + aofVersion.get();
aofVersion.incrementAndGet();
return _v;
}
private static String buildFileName(){
return String.format("%s%s.obj", Optional.ofNullable(serverName).orElse(defaultServerName()), serverId);
}
private static String buildFileName_AOF(){
return buildFileName().concat(getAofVersion());
}
private static String buildFileName(String prefixName){
return String.format("%s%s_%s.obj", Optional.ofNullable(serverName).orElse(defaultServerName()), serverId, prefixName);
}
public static String getPath() {
String fileName = buildFileName();
File file = new File(path, fileName);
if (file.exists()) {
return path + fileName;
}
logger.warn("getPath {}{} 不存在",path,fileName);
return null;
}
public static String getPath_AOF() {
String fileName = buildFileName_AOF();
File file = new File(path, fileName);
if (file.exists()) {
return path + fileName;
}
return null;
}
public static String getPath(String prefixName) {
String fileName = buildFileName(prefixName);
File file = new File(path, fileName);
if (file.exists()) {
return path + fileName;
}
return null;
}
public static String createFile() throws IOException {
String fileName = buildFileName();
File file = new File(path, fileName);
if (!file.exists()) {
file.createNewFile();
}
return path + fileName;
}
public static String createFile_AOF() throws IOException {
String fileName = buildFileName_AOF();
File file = new File(path, fileName);
if (!file.exists()) {
file.createNewFile();
}
return path + fileName;
}
public static String createFile(String prefixName) throws IOException {
String fileName = buildFileName(prefixName);
File file = new File(path, fileName);
if (!file.exists()) {
file.createNewFile();
}
return path + fileName;
}
public static boolean delFile() {
String fileName = buildFileName();
File file = new File(path, fileName);
if (file.exists()) {
return file.delete();
}
return false;
}
public static boolean delFile(String prefixName) {
String fileName = buildFileName(prefixName);
File file = new File(path, fileName);
if (file.exists()) {
FileUtil.rename(file, String.format("%s_bak_%s_%s",
fileName,
cn.hutool.core.date.DateUtil.today(),
IdUtil.fastSimpleUUID()), false, true);
return true;
}
return false;
}
private static String defaultServerName() {
return Optional.ofNullable(SpringUtil.getApplicationContext()).map(ApplicationContext::getApplicationName).orElse("NULL");
}
}
实战
初始化操作
implements CommandLineRunner
项目开始则执行以下代码,做个钩子,项目关闭时会触发该线程业务逻辑
@Override
public void run(String... args) {
Runtime.getRuntime().addShutdownHook(new Thread(shutdownHook));
}
执行 本地缓存数据存入文件 的线程任务
- 这里的
init
方法是项目一启动会执行,将文件数据放进本地缓存中初始化 - 这里的
run
方法是线程执行业务,项目结束运行,钩子触发该业务将本地缓存数据存放进文件中
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
@Component
public class ShutdownHook implements Runnable{
private final static Logger log = LoggerFactory.getLogger(ShutdownHook.class);
private static final List<Persistence> canBeHookList = new ArrayList<>();
@Value("${server-node.id}")
private String nodeId;
@Value("${spring.application.name}")
private String applicationName;
@Resource
private MonitorThread monitorThread;
@PostConstruct
public void init() {
PersistencePath.serverId = nodeId;
PersistencePath.serverName = applicationName;
SmsQueueManage.getInstance().loadLocalData();
MemoryParamCache.getInstance().loadLocalData();
}
@Override
public void run() {
Thread.currentThread().setName("ShutdownHook_Thread");
log.info("【sms-rules退出 - Thread:{}】- 钩子回调 开始...",Thread.currentThread().getName());
monitorThread.stopMonitorAndAllThread();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
log.error(Thread.currentThread().getName() + ": 线程休眠异常" ,e);
}
log.info("等待持久化队列管理类 size:{}",canBeHookList.size());
for (Persistence q : canBeHookList) {
q.saveData();
}
log.error("【sms-rules退出 - Thread:{}】- 钩子回调 完毕",Thread.currentThread().getName());
}
public static void add(Persistence p) {
canBeHookList.add(p);
}
public static void remove(Persistence p) {
canBeHookList.remove(p);
}
}
持久化工具类
public class MemoryParamCache implements Persistence {
private final static Logger log = LoggerFactory.getLogger(MemoryParamCache.class);
private static final String memoryParamCachePrefixFileName = "memoryParamCache";
private volatile static MemoryParamCache instance;
private MemoryParamCache(){
ShutdownHook.add(this);
}
public static MemoryParamCache getInstance(){
if (null == instance) {
synchronized (MemoryParamCache.class) {
if (null == instance) {
instance = new MemoryParamCache();
}
}
}
return instance;
}
@Override
public void saveData() {
ObjectOutputStream oos = null;
String path = "";
try {
path = PersistencePath.createFile(memoryParamCachePrefixFileName);
log.info("【MemoryParamCache - saveData】持久化内存参数到文件 | 开始 | path:{}",path);
oos = new ObjectOutputStream(new FileOutputStream(path));
oos.writeObject(RuleSymbol.cityMap);
log.info("【MemoryParamCache - saveData】持久化内存参数到文件 | 结束 | path:{} | cityMap:{}",path , RuleSymbol.cityMap.size());
} catch (Exception e) {
log.error("【MemoryParamCache - 持久化内存参数到文件】异常 | path:{}",path, e);
} finally {
try {
if (oos != null) {
oos.close();
}
} catch (IOException ioe) {
}
}
}
public void loadLocalData() {
ObjectInputStream ois = null;
String path = "";
try {
path = PersistencePath.getPath(memoryParamCachePrefixFileName);
log.info("【MemoryParamCache - loadLocalData】内存参数缓存文件-->-->-->-->加载到内存开始... | path:{}",path);
ois = new ObjectInputStream(new FileInputStream(path));
RuleSymbol.cityMap = (ConcurrentHashMap<String, String>) ois.readObject();
log.info("【MemoryParamCache - loadLocalData】内存参数缓存文件-->-->-->-->加载到内存 结束 | path:{} | cityMap:{}",path, RuleSymbol.cityMap.size());
}catch (Exception e) {
log.error("【sms-rules启动 - 加载持久化后的内存参数】异常 | path:{}", path,e);
}finally {
if(ois != null){
try {
ois.close();
} catch (IOException e) {
}
boolean b = PersistencePath.delFile(memoryParamCachePrefixFileName);
log.info("【MemoryParamCache - loadLocalData】STEP-TWO 删除缓存数据文件:{}",b);
}
}
}
}