聊聊Spring Cache的缓存抽象与JSR107缓存抽象JCache,并使用API方式使用Spring Cache【享学Spring】(中)

简介: 聊聊Spring Cache的缓存抽象与JSR107缓存抽象JCache,并使用API方式使用Spring Cache【享学Spring】(中)

SimpleCacheManager


// @since 3.1
public class SimpleCacheManager extends AbstractCacheManager {
  private Collection<? extends Cache> caches = Collections.emptySet();
  public void setCaches(Collection<? extends Cache> caches) {
    this.caches = caches;
  }
  @Override
  protected Collection<? extends Cache> loadCaches() {
    return this.caches;
  }
}


最简单的一个CacheManager,它的caches都必须由调用者手动指定。若交给容器管理会自动执行afterPropertiesSet()方法,否则需要手动自己调用cacheManager.afterPropertiesSet();,自己放进去的setCaches才会生效~


NoOpCacheManager


一种基本的、无操作的CacheManager实现,适用于禁用缓存,通常用于在没有实际存储的情况下作为缓存声明。

ConcurrentMapCacheManager(重要)

// @since 3.1
public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderAware {
  private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);
  // true表示:若为null,就新创建一个缓存添加进去
  private boolean dynamic = true;
  // 是否允许value为null
  private boolean allowNullValues = true;
  // 指定此缓存管理器是存储每个条目的副本,还是存储其所有缓存的引用
  // 影响到ConcurrentMapCache对value值的存储~~~
  // false表示:存储它自己(引用)
  // true表示:存储一个副本(对序列化有要求~~~) 很少这么使用~~~
  private boolean storeByValue = false;
  public ConcurrentMapCacheManager() {
  }
  public ConcurrentMapCacheManager(String... cacheNames) {
    setCacheNames(Arrays.asList(cacheNames));
  }
  public void setCacheNames(@Nullable Collection<String> cacheNames) {
    if (cacheNames != null) {
      for (String name : cacheNames) {
        this.cacheMap.put(name, createConcurrentMapCache(name));
      }
      this.dynamic = false; // 手动设置了,就不允许在动态创建了
    } else {
      this.dynamic = true;
    }
  }
  protected Cache createConcurrentMapCache(String name) {
    // isStoreByValue=true需要存储值的副本的时候,才对序列化有要求~~~否则直接存引用即可
    SerializationDelegate actualSerialization = (isStoreByValue() ? this.serialization : null);
    return new ConcurrentMapCache(name, new ConcurrentHashMap<>(256), isAllowNullValues(), actualSerialization);
  }
  @Override
  public void setBeanClassLoader(ClassLoader classLoader) {
    this.serialization = new SerializationDelegate(classLoader);
    if (isStoreByValue()) {
      // 重新创建Cache 因为要副本嘛
      recreateCaches();
    }
  }
  private void recreateCaches() {
    for (Map.Entry<String, Cache> entry : this.cacheMap.entrySet()) {
      entry.setValue(createConcurrentMapCache(entry.getKey()));
    }
  }
  @Override
  @Nullable
  public Cache getCache(String name) {
    Cache cache = this.cacheMap.get(name);
    // dynamic=true  为null的时候会动态创建一个
    if (cache == null && this.dynamic) {
      synchronized (this.cacheMap) {
        cache = this.cacheMap.get(name);
        if (cache == null) {
          cache = createConcurrentMapCache(name);
          this.cacheMap.put(name, cache);
        }
      }
    }
    return cache;
  }
  @Override
  public Collection<String> getCacheNames() {
    return Collections.unmodifiableSet(this.cacheMap.keySet());
  }
  ...
}


它的缓存存储是基于内存的,所以它的生命周期是与应用关联的,对于生产级别的大型企业级应用程序,这可能并不是理想的选择,但它用于本地自己测试是个很好的选择。


CompositeCacheManager


// @since 3.1  
public class CompositeCacheManager implements CacheManager, InitializingBean {
  // 内部聚合管理着一批CacheManager
  private final List<CacheManager> cacheManagers = new ArrayList<>();
  // 若这个为true,则可以结合NoOpCacheManager实现效果~~~
  private boolean fallbackToNoOpCache = false;
  public CompositeCacheManager() {
  }
  public CompositeCacheManager(CacheManager... cacheManagers) {
    setCacheManagers(Arrays.asList(cacheManagers));
  }
  // 也可以调用此方法,来自己往里面添加(注意是添加)CacheManager们
  public void setCacheManagers(Collection<CacheManager> cacheManagers) {
    this.cacheManagers.addAll(cacheManagers);
  }
  public void setFallbackToNoOpCache(boolean fallbackToNoOpCache) {
    this.fallbackToNoOpCache = fallbackToNoOpCache;
  }
  // 如果fallbackToNoOpCache=true,那么在这个Bean初始化完成后,也就是在末尾添加一个NoOpCacheManager
  // 当然fallbackToNoOpCache默认值是false
  @Override
  public void afterPropertiesSet() {
    if (this.fallbackToNoOpCache) {
      this.cacheManagers.add(new NoOpCacheManager());
    }
  }
  // 找到一个cache不为null的就return了~
  @Override
  @Nullable
  public Cache getCache(String name) {
    for (CacheManager cacheManager : this.cacheManagers) {
      Cache cache = cacheManager.getCache(name);
      if (cache != null) {
        return cache;
      }
    }
    return null;
  }
  // 可以看到返回的是所有names,并且用的set
  @Override
  public Collection<String> getCacheNames() {
    Set<String> names = new LinkedHashSet<>();
    for (CacheManager manager : this.cacheManagers) {
      names.addAll(manager.getCacheNames());
    }
    return Collections.unmodifiableSet(names);
  }
}


CompositeCacheManager要通过一个或更多的缓存管理器来进行配置,它会迭代这些缓存管理器,以查找之前所缓存的值。

看完CacheManager,再看看Cache这个接口:


public interface Cache {
  String getName();
  // 返回本地存储的那个。比如ConcurrentMapCache本地就是用的一个ConcurrentMap
  Object getNativeCache();
  // 就是用下面的ValueWrapper把值包装了一下而已~
  @Nullable
  ValueWrapper get(Object key);
  @Nullable
  <T> T get(Object key, @Nullable Class<T> type);
  @Nullable
  <T> T get(Object key, Callable<T> valueLoader);
  void put(Object key, @Nullable Object value);
  // @since 4.1
  // 不存在旧值直接put就先去了返回null,否则返回旧值(并且不会把新值put进去)
  @Nullable
  ValueWrapper putIfAbsent(Object key, @Nullable Object value);
  // 删除
  void evict(Object key);
  // 清空
  void clear();
  @FunctionalInterface
  interface ValueWrapper {
    @Nullable
    Object get();
  }
}


它的继承树非常简单,如下:

image.png


相关文章
|
13天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
44 2
|
2月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
48 4
|
4月前
|
存储 缓存 NoSQL
【Azure Redis 缓存】关于Azure Cache for Redis 服务在传输和存储键值对(Key/Value)的加密问题
【Azure Redis 缓存】关于Azure Cache for Redis 服务在传输和存储键值对(Key/Value)的加密问题
|
4月前
|
缓存 弹性计算 NoSQL
【Azure Redis 缓存 Azure Cache For Redis】Redis连接池
【Azure Redis 缓存 Azure Cache For Redis】Redis连接池
|
3月前
|
缓存 Java 应用服务中间件
随着微服务架构的兴起,Spring Boot凭借其快速开发和易部署的特点,成为构建RESTful API的首选框架
【9月更文挑战第6天】随着微服务架构的兴起,Spring Boot凭借其快速开发和易部署的特点,成为构建RESTful API的首选框架。Nginx作为高性能的HTTP反向代理服务器,常用于前端负载均衡,提升应用的可用性和响应速度。本文详细介绍如何通过合理配置实现Spring Boot与Nginx的高效协同工作,包括负载均衡策略、静态资源缓存、数据压缩传输及Spring Boot内部优化(如线程池配置、缓存策略等)。通过这些方法,开发者可以显著提升系统的整体性能,打造高性能、高可用的Web应用。
77 2
|
4月前
|
API 开发者 Java
API 版本控制不再难!Spring 框架带你玩转多样化的版本管理策略,轻松应对升级挑战!
【8月更文挑战第31天】在开发RESTful服务时,为解决向后兼容性问题,常需进行API版本控制。本文以Spring框架为例,探讨四种版本控制策略:URL版本控制、请求头版本控制、查询参数版本控制及媒体类型版本控制,并提供示例代码。此外,还介绍了通过自定义注解与过滤器实现更灵活的版本控制方案,帮助开发者根据项目需求选择最适合的方法,确保API演化的管理和客户端使用的稳定与兼容。
181 0
|
4月前
|
缓存 NoSQL Redis
【Azure Redis 缓存】Azure Cache for Redis 服务的导出RDB文件无法在自建的Redis服务中导入
【Azure Redis 缓存】Azure Cache for Redis 服务的导出RDB文件无法在自建的Redis服务中导入
|
4月前
|
缓存 开发框架 NoSQL
【Azure Redis 缓存】VM 里的 Redis 能直接迁移到 Azure Cache for Redis ? 需要改动代码吗?
【Azure Redis 缓存】VM 里的 Redis 能直接迁移到 Azure Cache for Redis ? 需要改动代码吗?
|
4月前
|
缓存 NoSQL Unix
【Azure Redis 缓存】Azure Cache for Redis 中如何快速查看慢指令情况(Slowlogs)
【Azure Redis 缓存】Azure Cache for Redis 中如何快速查看慢指令情况(Slowlogs)
|
4月前
|
缓存 NoSQL Redis
【Azure Redis 缓存】Azure Cache for Redis 是否记录具体读/写(Get/Set)或删除(Del)了哪些key呢?
【Azure Redis 缓存】Azure Cache for Redis 是否记录具体读/写(Get/Set)或删除(Del)了哪些key呢?