聊聊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


相关文章
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
92 2
|
2月前
|
缓存 NoSQL Java
什么是缓存?如何在 Spring Boot 中使用缓存框架
什么是缓存?如何在 Spring Boot 中使用缓存框架
67 0
|
3月前
|
Java API 数据库
如何使用Spring Boot构建RESTful API,以在线图书管理系统为例
【10月更文挑战第9天】本文介绍了如何使用Spring Boot构建RESTful API,以在线图书管理系统为例,从项目搭建、实体类定义、数据访问层创建、业务逻辑处理到RESTful API的实现,详细展示了每个步骤。通过Spring Boot的简洁配置和强大功能,开发者可以高效地开发出功能完备、易于维护的Web应用。
89 3
|
3月前
|
IDE Java API
基于Spring Boot REST API设计指南
【10月更文挑战第4天】 在现代的软件开发中,RESTful API已经成为了构建网络应用的标准之一。它通过HTTP协议提供了与资源交互的方式,使得不同的应用程序能够进行数据交互。Spring Boot作为一个功能强大的框架,它简化了配置和开发流程,成为了构建RESTful API的理想选择。本文将详细介绍如何在Spring Boot中设计和实现高质量的RESTful API,并提供一些最佳实践。
63 1
|
19天前
|
存储 安全 Java
Spring Boot 编写 API 的 10条最佳实践
本文总结了 10 个编写 Spring Boot API 的最佳实践,包括 RESTful API 设计原则、注解使用、依赖注入、异常处理、数据传输对象(DTO)建模、安全措施、版本控制、文档生成、测试策略以及监控和日志记录。每个实践都配有详细的编码示例和解释,帮助开发者像专业人士一样构建高质量的 API。
|
3月前
|
缓存 Java API
基于Spring Boot REST API设计指南
【10月更文挑战第11天】 在构建现代Web应用程序时,RESTful API已成为一种标准,使得不同的应用程序能够通过HTTP协议进行通信,实现资源的创建、读取、更新和删除等操作。Spring Boot作为一个功能强大的框架,能够轻松创建RESTful API。本文将详细介绍如何在Spring Boot中设计和实现高质量的RESTful API。
149 61
|
5月前
|
缓存 NoSQL Java
【Azure Redis 缓存】示例使用 redisson-spring-boot-starter 连接/使用 Azure Redis 服务
【Azure Redis 缓存】示例使用 redisson-spring-boot-starter 连接/使用 Azure Redis 服务
|
1月前
|
缓存 NoSQL Java
Spring Boot中的分布式缓存方案
Spring Boot提供了简便的方式来集成和使用分布式缓存。通过Redis和Memcached等缓存方案,可以显著提升应用的性能和扩展性。合理配置和优化缓存策略,可以有效避免常见的缓存问题,保证系统的稳定性和高效运行。
50 3
|
1月前
|
缓存 Java 数据库连接
深入探讨:Spring与MyBatis中的连接池与缓存机制
Spring 与 MyBatis 提供了强大的连接池和缓存机制,通过合理配置和使用这些机制,可以显著提升应用的性能和可扩展性。连接池通过复用数据库连接减少了连接创建和销毁的开销,而 MyBatis 的一级缓存和二级缓存则通过缓存查询结果减少了数据库访问次数。在实际应用中,结合具体的业务需求和系统架构,优化连接池和缓存的配置,是提升系统性能的重要手段。
66 4
|
2月前
|
Java 测试技术 API
详解Swagger:Spring Boot中的API文档生成与测试工具
详解Swagger:Spring Boot中的API文档生成与测试工具
56 4