UserCacheManager.java 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. package me.zhengjie.modules.security.service;
  2. import lombok.extern.slf4j.Slf4j;
  3. import me.zhengjie.modules.security.service.dto.JwtUserDto;
  4. import org.springframework.beans.factory.annotation.Value;
  5. import org.springframework.stereotype.Component;
  6. import java.util.Iterator;
  7. import java.util.Map;
  8. import java.util.concurrent.ConcurrentHashMap;
  9. import java.util.concurrent.Future;
  10. import java.util.concurrent.atomic.AtomicBoolean;
  11. /**
  12. * 用户缓存
  13. *
  14. * @author TikiWong
  15. * @date 2022/1/27 8:23
  16. **/
  17. @Slf4j
  18. @Component
  19. public class UserCacheManager {
  20. @Value("${user-cache.min-evictable-size}")
  21. private int minEvictableSize;
  22. @Value("${user-cache.min-evictable-interval}")
  23. private long minEvictableInterval;
  24. @Value("${user-cache.min-idle-time}")
  25. private long minIdleTime;
  26. private final Map<String, Node> cache = new ConcurrentHashMap<>();
  27. private final AtomicBoolean expelLock = new AtomicBoolean(true);
  28. private long nextMinEvictableTime = 0;
  29. public Future<JwtUserDto> putIfAbsent(String username, Future<JwtUserDto> ft) {
  30. Node tryNode = new Node(ft);
  31. Node node = cache.putIfAbsent(username, tryNode);
  32. expel();
  33. return nodeToDate(node);
  34. }
  35. /**
  36. * 缓存回收
  37. * 为避免超过边界后回收热点数据设置了最小生存时间
  38. * 回收时会保留在最小生存时间内的数据
  39. **/
  40. public void expel() {
  41. long now = System.currentTimeMillis();
  42. if (cache.size() < minEvictableSize ||
  43. now < nextMinEvictableTime ||
  44. !expelLock.compareAndSet(true, false)) {
  45. return;
  46. }
  47. long oldestTime = now;
  48. int evictedCount = 0;
  49. try {
  50. Iterator<Map.Entry<String, Node>> iterator = cache.entrySet().iterator();
  51. while (iterator.hasNext()) {
  52. Map.Entry<String, Node> entry = iterator.next();
  53. long nodeTime = entry.getValue().getTime();
  54. if (nodeTime + minIdleTime < now) {
  55. iterator.remove();
  56. evictedCount++;
  57. }
  58. oldestTime = Math.min(oldestTime, nodeTime);
  59. }
  60. } finally {
  61. this.nextMinEvictableTime = Math.max(now + minEvictableInterval, oldestTime);
  62. expelLock.set(true);
  63. log.info("回收掉【{}】条用户缓存, 剩余缓存数为【{}】,下次可回收时间为【{}】秒后",
  64. evictedCount,
  65. cache.size(),
  66. (this.nextMinEvictableTime - now) / 1000);
  67. }
  68. }
  69. public Future<JwtUserDto> get(String username) {
  70. return nodeToDate(cache.get(username));
  71. }
  72. public void clear() {
  73. cache.clear();
  74. }
  75. public void remove(String username) {
  76. cache.remove(username);
  77. }
  78. private Future<JwtUserDto> nodeToDate(Node node) {
  79. return node == null ? null : node.getData();
  80. }
  81. private static class Node {
  82. private final Future<JwtUserDto> data;
  83. private final long time;
  84. public Node(Future<JwtUserDto> data) {
  85. this.data = data;
  86. this.time = System.currentTimeMillis();
  87. }
  88. public Future<JwtUserDto> getData() {
  89. return data;
  90. }
  91. public long getTime() {
  92. return time;
  93. }
  94. }
  95. }