赞
踩
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
项目中使用到了缓存,定义一个切面,拦截类或方法上存在@SysDataCache注解请求,对于这些方法的返回值进行缓存。项目中主要还是使用在缓存常量,一些不易改变的值
@Documented
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SysDataCache {
}
@Aspect //定义一个切面 @Configuration public class SysDataCacheAspect { private static Logger logger = LogManager.getLogger(SysDataCacheAspect.class); private static final Map<String,Boolean> cacheFileNames = new ConcurrentHashMap<String, Boolean>(); private static LoadingCache<String,Object> cache = null; static { // CacheLoader 初始化 CacheLoader<String, Object> cacheLoader = new CacheLoader<String, Object>() { @Override // load方法的作用是在通过get方法从LoadingCache获取不到值时去加载该值并放入缓存。 public Object load(String key) throws Exception { return null; } }; cache = CacheBuilder.newBuilder() // 设置容量大小 .maximumSize(80000) //默认一天后过期 .expireAfterWrite(10, TimeUnit.DAYS) .removalListener(new RemovalListener<String, Object>() { @Override public void onRemoval(RemovalNotification<String, Object> notification) { if(notification.getValue()!=null && notification.getValue() instanceof CacheFile) { CacheFile cacheFile = (CacheFile)notification.getValue(); removeCacheFile(cacheFile.fileName); } } }) // 加载器配置 .build(cacheLoader); } private String normalizedArgsStr(Object[] args){ if(args==null || args.length==0) { return ""; } Object[] normalizedArgs = new Object[args.length]; if(args!=null) { for(int i=0;i<args.length;i++) { Object arg = args[i]; if(arg instanceof AccessTokenUser) { AccessTokenUser user = (AccessTokenUser)arg; normalizedArgs[i]= user.getUserId(); }else { normalizedArgs[i]=arg; } } } return JsonConverter.toJsonStr(normalizedArgs); } @Around("execution(* (@com.xysd.bizbase.annotation.SysDataCache *).*(..)) || execution(@com.xysd.bizbase.annotation.SysDataCache * *(..))") public Object process(ProceedingJoinPoint point) throws Throwable { String className = point.getSignature().getDeclaringTypeName(); String methodName = point.getSignature().getName(); Object[] args = point.getArgs(); String key = className+"_$_"+methodName+"_$_"+(normalizedArgsStr(args)); Object cached = cache.getIfPresent(key); if(methodName.endsWith("_dontCache")){ return point.proceed(args); } if(cached!=null) { if(cached instanceof CacheFile) { CacheFile cachedFile = (CacheFile)cached; Object cachedData = readCachedData(cachedFile); if(cachedData==null) { //读取缓存失败 return point.proceed(args); }else { return cachedData; } }else { return cached; } }else { cached = point.proceed(args); if(cached instanceof ApiResultDTO){ if(((ApiResultDTO<?>) cached).getData() == null) return cached; } if(cached!=null) { try { CacheFile cachedFile = cacheToDiskIfNecessary(cached); if(cachedFile!=null) { cache.put(key, cachedFile); }else { cache.put(key, cached); } }catch(Exception e) { logger.error("缓存失败,失败信息{}",e.getMessage()); e.printStackTrace(); } } return cached; } } private Object readCachedData(CacheFile cachedFile) { String fileName = cachedFile.getFileName(); String absolutePath = getAbsoluteCacheFilePath(fileName); File f = new File(absolutePath); InputStream in = null; ObjectInputStream oin = null; try { in = new FileInputStream(f); oin = new ObjectInputStream(in); Object cachedData = oin.readObject(); return cachedData; }catch(Exception e) { logger.error("读取缓存序列化文件失败,失败信息:{}",e.getMessage()); e.printStackTrace(); return null; } finally { Utils.clean(in,oin); } } /** * 当value序列化后占用字节大于50K时写入磁盘进行缓存 * @param value * @return */ private CacheFile cacheToDiskIfNecessary(Object value) { int cachThreadshold = 50*1024; ByteArrayOutputStream bos = null ; ObjectOutputStream oos = null; try { bos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(bos); oos.writeObject(value); oos.flush(); byte[] byteArray = bos.toByteArray(); if(byteArray!=null && byteArray.length>cachThreadshold) { return buildCacheFile(byteArray); }else { return null; } }catch(Exception e) { throw new RuntimeException(e); }finally { Utils.clean(bos,oos); } } private CacheFile buildCacheFile(byte[] byteArray) { String fileName = "syscachefile_"+Utils.getUUID(""); String absolutePath = getAbsoluteCacheFilePath(fileName); File f = new File(absolutePath); OutputStream out = null; try { if(!f.getParentFile().exists()) { f.getParentFile().mkdirs(); } out = new FileOutputStream(f); out.write(byteArray); out.flush(); cacheFileNames.put(fileName, true); return new CacheFile(fileName); }catch(Exception e) { throw new RuntimeException(e); }finally { Utils.clean(out); } } private static String getAbsoluteCacheFilePath(String fileName) { String sysCacheBaseDir = Utils.getTmpDirRoot()+"/sysDataCache"; return sysCacheBaseDir+"/"+fileName; } public static void removeCacheFile(String fileName) { if(StringUtils.isNoneBlank(fileName)) { cacheFileNames.remove(fileName); String absolutePath = getAbsoluteCacheFilePath(fileName); File f = new File(absolutePath); try { if(f.exists() && f.isFile()) { f.delete(); } }catch(Exception e) { //删除失败不做任何处理 e.printStackTrace(); } } } /** * 清空缓存 */ public static final void clearCache() { for(String fileName:cacheFileNames.keySet()) { removeCacheFile(fileName); } cacheFileNames.clear(); cache.invalidateAll(); } public static class CacheFile implements Serializable { private static final long serialVersionUID = -6926387004863371705L; private String fileName; public CacheFile(String fileName) { super(); this.fileName = fileName; } public String getFileName() { return fileName; } } }
@Service @Transactional @SuppressWarnings("unchecked") public class SysDatasServiceImpl implements _ISysDatasService { private final static ConstantItem dataKey_dict_politicalStatus = new ConstantItem("politicalStatus", "政治身份"); @Override @SysDataCache @Transactional(readOnly = true) public Map<String, String> getSysDataKeysInfo(AccessTokenUser user) { result.put((String) dataKey_dict_politicalStatus.getId(), dataKey_dict_politicalStatus.getName()); } @Override @SysDataCache @Transactional(readOnly = true) public Map<String, Object> getSysDatasByDataKeys(AccessTokenUser user, Map<String, Object> dataKeyAndParams) { if (dataKey_dict_politicalStatus.getId().equals(entry.getKey())) {//政治身份 Map<String, Object> dictParams = (Map<String, Object>) entry.getValue(); data.put(entry.getKey(), getDictValue(entry.getKey(), dictParams)); continue; } } //从字典中获取数据 private List<SimpTreeNode> getDictValue(String dictCodes, Map<String, Object> params) { if("all".equals(dictCodes)){ List<SysDataSimpleDTO> rootDicts = systemGatewayService.findAllRootDicts(1); dictCodes = Optional.ofNullable(rootDicts).orElse(new ArrayList<>()).stream().map(r->r.getId().replace("-","")).collect(Collectors.joining(",")); } else if (params != null && params.get("dictCodes") != null) { dictCodes = (String) params.get("dictCodes"); params.remove("dictCodes"); } List<SimpTreeNode> codeList = systemGatewayService.findDictSimTreeNodeByDictCodes(dictCodes, params); return codeList; } }
作为性能缓存工具,这里是作为统计sql查询的耗时,当然这是基于内存的缓存,如果需要保留下来。可以插入到数据库中
public class MonitorTask { public static final String STATUS_RUUNING = "running"; public static final String STATUS_END = "end"; public static final String STATUS_FAILED = "failed"; private Date beginTime;//开始时间 private String content;//sql private String taskId;//任务id uuid private Date endTime;//结束时间 private String status = STATUS_RUUNING;//任务执行状态 public MonitorTask(String content, String taskId) { super(); this.content = content; this.taskId = taskId; //指定任务开始时间 this.beginTime = new Date(); } public Date getBeginTime() { return beginTime; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getTaskId() { return taskId; } public void setTaskId(String taskId) { this.taskId = taskId; } public Date getEndTime() { return endTime; } public void setEndTime(Date endTime) { this.endTime = endTime; } public void setBeginTime(Date beginTime) { this.beginTime = beginTime; } public void finished(boolean success) { //指定任务结束时间 this.endTime = new Date(); if (success) { status = STATUS_END; } else { status = STATUS_FAILED; } } public String getStatus() { return status; } public boolean isFailed() { return STATUS_FAILED.equals(this.status); } public boolean isSuccess() { return STATUS_END.equals(this.status); } public long getCost() { if (this.endTime == null) { return 0; } else if (this.endTime.getTime() > this.beginTime.getTime()) { return this.endTime.getTime() - this.beginTime.getTime(); } else { return 0; } } }
public class TaskStat { private String content; //执行总数 private volatile int totalCount; //总耗时 private volatile long totalCost; //最近一次耗时 private volatile long lastCost; public int getTotalCount() { return totalCount; } public long getTotalCost() { return totalCost; } public long getLastCost() { return lastCost; } public void finish(MonitorTask task) { this.totalCount++; this.totalCost += task.getCost(); this.lastCost = task.getCost(); } public TaskStat(String content) { super(); this.content = content; } //平均时耗 public double getAvgCost() { if (this.totalCount == 0) { return 0; } else { return this.totalCost / this.totalCount; } } public String getContent() { return content; } }
//执行统计逻辑 public class PerformanceStat { //缓存任务执行的开始时间,结束时间,成功与否,任务状态等等 private static LoadingCache<String, MonitorTask> runningTasks = null; static { // CacheLoader 初始化 CacheLoader<String, MonitorTask> cacheLoader1 = new CacheLoader<String, MonitorTask>() { @Override // load方法的作用是在通过get方法从LoadingCache获取不到值时去加载该值并放入缓存。 public MonitorTask load(String key) throws Exception { return null; } }; runningTasks = CacheBuilder.newBuilder() // 设置容量大小 .maximumSize(50000) //默认一天后过期 //.expireAfterWrite(60*24, TimeUnit.MINUTES) // 加载器配置 .build(cacheLoader1); } //缓存任务总耗时,平均耗时,总执行次数 private static LoadingCache<String, TaskStat> taskStats = null; static { // CacheLoader 初始化 CacheLoader<String, TaskStat> cacheLoader = new CacheLoader<String, TaskStat>() { @Override // load方法的作用是在通过get方法从LoadingCache获取不到值时去加载该值并放入缓存。 public TaskStat load(String key) throws Exception { return null; } }; taskStats = CacheBuilder.newBuilder() // 设置容量大小 .maximumSize(200000) //默认一天后过期 //.expireAfterWrite(60*24, TimeUnit.MINUTES) // 加载器配置 .build(cacheLoader); } /** * 开始监控任务 * * @param content 监控任务内容 * @return */ public static MonitorTask beginTask(String content) { MonitorTask task = new MonitorTask(content, UUID.randomUUID().toString()); runningTasks.put(task.getTaskId(), task); TaskStat stat = taskStats.getIfPresent(task.getContent()); if (stat == null) { stat = new TaskStat(content); taskStats.put(task.getContent(), stat); } return task; } /** * 任务完成 * * @param task * @param success */ public static void finishTask(MonitorTask task, boolean success) { if (task == null) { return; } TaskStat stat = taskStats.getIfPresent(task.getContent()); task.finished(success); runningTasks.invalidate(task.getTaskId()); if (stat != null) { stat.finish(task); } } //清空缓存 public static void clear() { runningTasks.invalidateAll(); taskStats.invalidateAll(); } //排序 public static List<TaskStat> sort(String sortType) { List<TaskStat> stats = new ArrayList<TaskStat>(taskStats.asMap().values()); if ("1".equals(sortType)) { //按照总耗时倒序排序 Collections.sort(stats, new Comparator<TaskStat>() { @Override public int compare(TaskStat o1, TaskStat o2) { return Long.valueOf(o2.getTotalCost()).compareTo(Long.valueOf(o1.getTotalCost())); } }); } if ("2".equals(sortType)) { //按照平均耗时倒序排序 Collections.sort(stats, new Comparator<TaskStat>() { @Override public int compare(TaskStat o1, TaskStat o2) { return Double.valueOf(o2.getAvgCost()).compareTo(Double.valueOf(o1.getAvgCost())); } }); } return stats; } }
public class QueryProxy implements InvocationHandler { private Object target; private MonitorTask task; //指定拦截下面这些方法 private static final List<String> jdbcMethods = Arrays.asList("getSingleResult", "getResultList", "executeUpdate", "getResultList", "uniqueResult", "getSingleResult", "list"); public QueryProxy(String content, Object target) { super(); this.target = target; task = PerformanceStat.beginTask(content.toLowerCase()); } private boolean isJdbcMethod(Method method) { String n = method.getName(); if (jdbcMethods.contains(n)) { return true; } else { return false; } } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { Object result = method.invoke(target, args); if (this.isJdbcMethod(method)) { PerformanceStat.finishTask(task, true); } return result; } catch (RuntimeException e) { if (this.isJdbcMethod(method)) { PerformanceStat.finishTask(task, true); } throw e; } } @SuppressWarnings("unchecked") public static final <T> T newProxyQuery(Class<T> queryClass, String content, Object target) { QueryProxy proxyHandler = new QueryProxy(content, target); return (T) Proxy.newProxyInstance(QueryProxy.class.getClassLoader(), new Class[]{queryClass}, proxyHandler); } }
@RequestMapping(value="/holiday", method=RequestMethod.GET)
public String queryHoliday(HttpServletRequest request){
return myService.getHolidayByYear();
}
public String getHolidayByYear(){
Date year = CalendarUtils.getCurrentYearBeginDate();
year = CalendarUtils.offsetYears(year,-1);
List<DateRec> holidays = commonRepositoryHibernate.getHolidayByYear(year);
if (CollectionUtils.isEmpty(holidays)) return null;
return JsonConverter.toJsonStr(holidays);
}
public List<DateRec> getHolidayByYear(Date year){
String hql = "select d from " + DateRec.class.getName() + " d where d.valid = 1 and dateTime >= :dateTime ";
List<DateRec> holidays = this.createHQLQueryByMapParams(DateRec.class, hql, Utils.buildMap("dateTime", year)).list();
if (holidays == null) holidays = new ArrayList<>();
return holidays;
}
private boolean isMonitorPerformance() { //这里可以通过配置文件配置 return true; } /** * 创建query * 通过params设置query查询参数 * @param <T> * @param hql * @param params */ protected <T> Query<T> createHQLQueryByMapParams(Class<T> resultType,String hql,Map<String,Object> params){ Query<T> query = JpaQueryBuilder.createHQLQueryByMapParams(getSession(), resultType, hql, params); if(isMonitorPerformance()) { return QueryProxy.newProxyQuery(Query.class, hql,query); } return query; }
@ApiImplicitParam(name="sort", value="排序类型")
@RequestMapping(value="/stat", method=RequestMethod.GET)
public List<TaskStat> stat(@RequestParam String sort,
HttpServletRequest request){
return PerformanceStat.sort(sort);
}
//排序 public static List<TaskStat> sort(String sortType) { List<TaskStat> stats = new ArrayList<TaskStat>(taskStats.asMap().values()); if ("1".equals(sortType)) { //按照总耗时倒序排序 Collections.sort(stats, new Comparator<TaskStat>() { @Override public int compare(TaskStat o1, TaskStat o2) { return Long.valueOf(o2.getTotalCost()).compareTo(Long.valueOf(o1.getTotalCost())); } }); } if ("2".equals(sortType)) { //按照平均耗时倒序排序 Collections.sort(stats, new Comparator<TaskStat>() { @Override public int compare(TaskStat o1, TaskStat o2) { return Double.valueOf(o2.getAvgCost()).compareTo(Double.valueOf(o1.getAvgCost())); } }); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。