Caffeine 缓存 和 java集合缓存 以及 redis 缓存 关系

​ 先比较前两着,比较显著的区别:1,Caffeine 缓存可以设定删除时间等删除条件、ConcurrentMap 代表的只JAVA集合类等只能动态添加保存,除非显示的删除(有可能内存溢出)。

2, Caffeine 的读写能力显著高于ConcurrentHashMap 。

3,ConcurrentMapCacheManager 这一类基本都是基于本地内存的缓存,不支持分布式,当然caffeine也是不支持分布式的,著名的支持分布式缓存是redis,,其他的都是应用中的 基于本地应用 的缓存,即本地缓存

​ 常用的spring Cache :

public enum CacheType {
	GENERIC, // 使用的SimpleCacheManager(自己手动指定Cache,可任意类型Cache实现哦)
	JCACHE, // 使用org.springframework.cache.jcache.JCacheCacheManager
	EHCACHE, // 使用org.springframework.cache.ehcache.EhCacheCacheManager
	HAZELCAST, // 使用com.hazelcast.spring.cache.HazelcastCacheManager
	INFINISPAN, // 使用org.infinispan.spring.provider.SpringEmbeddedCacheManager
	COUCHBASE, // 使用com.couchbase.client.spring.cache.CouchbaseCacheManager
	REDIS, // 使用org.springframework.data.redis.cache.RedisCacheManager,依赖于RedisTemplate进行操作
	CAFFEINE, // 使用org.springframework.cache.caffeine.CaffeineCacheManager
	@Deprecated
	GUAVA, // 使用org.springframework.cache.guava.GuavaCacheManager,已经过期不推荐使用了
	SIMPLE, // 使用ConcurrentMapCacheManager
	NONE; // 使用NoOpCacheManager,表示禁用缓存
       
}

补充:Memcached,也是高性能、分布式的

​ 简单介绍这几种缓存的特点:

  1. EhCache:一个纯Java的进程内缓存框架,具有快速、精干等特点。因为它是纯Java进程的,所以也是基于本地缓存的。(注意:EhCache2.x和EhCache3.x差异巨大且不兼容)

  2. Hazelcast:基于内存的数据网格。虽然它基于内存,但是分布式应用程序可以使用Hazelcast进行分布式缓存、同步、集群、处理、发布/订阅消息等。(如果你正在寻找基于内存的、高速的、可弹性扩展的、支持分布式的、对开发者友好的NoSQL,Hazelcast是一个很棒的选择,它的理念是用应用服务的内存换取效率,成本较高).

    从com.hazelcast.spring.cache.HazelcastCacheManager这个包名中也能看出,是它自己实现的Spring Cache标准,而不是spring-data帮它实现的(类似MyBatis集成Spring),但它凭借自己的足够优秀,让Spring接受了它

  3. Infinispan:基于Apache 2.0协议的分布式键值存储系统,可以以普通java lib或者独立服务的方式提供服务,支持各种协议(Hot Rod, REST, WebSockets)。支持的高级特性包括:事务、事件通知、高级查询、分布式处理、off-heap及故障迁移。 它按照署模式分为嵌入式(Embedded)模式(基于本地内存)、Client-Server(C\S)模式。

  4. Couchbase:是一个非关系型数据库,它实际上是由couchdb+membase组成,所以它既能像couchdb那样存储json文档(类似MongoDB),也能像membase那样高速存储键值对。(新一代的NoSql数据库,国外挺火的)

  5. Redis:熟悉得不能再熟悉的分布式缓存,只有Client-Server(C\S)模式,单线程让它天生具有线程安全的特性。Java一般使用Jedis/Luttuce来操纵~

  6. Caffeine(咖啡因):Caffeine是使用Java8对Guava缓存的重写版本,一个接近最佳的的缓存库(号称性能最好)。Spring5已经放弃guava,拥抱caffeine,它的API保持了近乎和guava一致,但是性能上碾压它。

  7. guava是谷歌Google Guava工具包的,使用非常广泛。Caffeine长江后浪推前浪,性能上碾压了Guava,是它的替代品。

  8. SIMPLE:略

原文链接:https://blog.csdn.net/f641385712/article/details/94982916

​ 下面简单介绍下几种缓存的特点:

1,Caffeine 缓存

1.1 特点
  • 自动加载条目到缓存中,可选异步方式
  • 可以基于大小剔除
  • 可以设置过期时间,时间可以从上次访问或上次写入开始计算
  • 异步刷新
  • keys自动包装在弱引用中
  • values自动包装在弱引用或软引用中
  • 条目剔除通知
  • 缓存访问统计
1.2 spring-boot 集成caffeine的demo
1.2.1 pom引入
        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
            <version>3.0.4</version>
        </dependency>
 
		<-- 一般带着这个  !>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
1.2.2 准备cache config配置文件:

下面这段代码相当于在xml配置文件当中声明caffinee cache配置, 即caffiine manager。

@EnableCaching  //这个可以加在启动类,即main哪儿
@Configuration
public class CacheConfig  {

    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        // 方案一(常用):定制化缓存Cache
        cacheManager.setCaffeine(Caffeine.newBuilder()
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .initialCapacity(100)
                .maximumSize(10_000))
        // 如果缓存种没有对应的value,通过createExpensiveGraph方法同步加载  buildAsync是异步加载
        //.build(key -> createExpensiveGraph(key))
        ;


        // 方案二:传入一个CaffeineSpec定制缓存,它的好处是可以把配置方便写在配置文件里
        //cacheManager.setCaffeineSpec(CaffeineSpec.parse("initialCapacity=50,maximumSize=500,expireAfterWrite=5s"));
        return cacheManager;
    }

}

使用:在代码中直接使用注入即可

    @Resource
    Cache<Integer, String> deployJobStatusCache;

	// deployJobStatusCache.getIfPresent()

特别注释

1, @Configuration : 指示一个类,或者声明一个或多个@Bean方法,并且可以由Spring容器处理,以便在运行时为这些bean生成BeanDefinition和服务请求。@Configuration 注释的类 类似于于一个 xml 配置文件的存在 ,可以将其理解为一个Xml内容的Java版本, 那么,一些Xml中使用的其他写法可以在其中能直接用。 (https://www.jianshu.com/p/721c76c1529c)

1.3 填充策略
1.3.1 手动填充

此策略,手动将值放入缓存之后再检索。

//step1:初始化
Cache<String, DataObject> cache = Caffeine.newBuilder()
 .expireAfterWrite(1, TimeUnit.MINUTES)
 .maximumSize(100)
 .build();

//get或者put
String key = "A";
DataObject dataObject = cache.getIfPresent(key);
assertNull(dataObject);

cache.put(key, dataObject);
dataObject = cache.getIfPresent(key);  
assertNotNull(dataObject);

我们也可以使用 get 方法获取值,该方法将一个参数为 key 的 Function 作为参数传入。如果缓存中不存在该键,则该函数将用于提供回退值,该值在计算后插入缓存中:

dataObject = cache.get(key, k -> DataObject.get(``"Data for A"``));
 
assertNotNull(dataObject);
assertEquals(``"Data for A"``, dataObject.getData());

get 方法可以原子方式执行计算。这意味着您只进行一次计算 — 即使多个线程同时请求该值。这就是为什么使用 get 优于 getIfPresent。

1.3.2 同步加载

相当于在初始化的时候就缓存赋值,暂不清楚场景!

//step1 : 初始化缓存
LoadingCache<String, DataObject> cache = Caffeine.newBuilder()
 .maximumSize(100)
 .expireAfterWrite(1, TimeUnit.MINUTES)
 .build(k -> DataObject.get("Data for " + k));


1.3.3 异步加载

和前面差不多,暂不清楚场景。

AsyncLoadingCache<String, DataObject> cache = Caffeine.newBuilder()
 .maximumSize(100)
 .expireAfterWrite(1, TimeUnit.MINUTES)
 .buildAsync(k -> DataObject.get("Data for " + k));
1.4 回收策略
1.4.1 基于大小回收

这种回收方式假定当超过配置的缓存大小限制时会发生回收。

1.4.2 基于时间回收

这种回收策略是基于条目的到期时间,有三种类型:

  1. 访问后到期 — 从上次读或写发生后,条目即过期。 .expireAfterAccess(``5``, TimeUnit.MINUTES)

  2. 写入后到期 — 从上次写入发生之后,条目即过期 .expireAfterWrite(``10``, TimeUnit.SECONDS)

  3. 自定义策略 — 到期时间由 Expiry 实现独自计算 ——要初始化自定义策略,我们需要实现 Expiry 接口

    cache = Caffeine.newBuilder().expireAfter(new Expiry<String, DataObject>() {
      @Override
      public long expireAfterCreate(
       String key, DataObject value, long currentTime) {
        return value.getData().length() * 1000;
      }
      @Override
      public long expireAfterUpdate(
       String key, DataObject value, long currentTime, long currentDuration) {
        return currentDuration;
      }
      @Override
      public long expireAfterRead(
       String key, DataObject value, long currentTime, long currentDuration) {
        return currentDuration;
      }
    }).build(k -> DataObject.get("Data for " + k));
    
    1.4.3 基于引用回收

    还未使用过这种: 可以将缓存配置为启用缓存键值的垃圾回收。为此,我们将 key 和 value 配置为 弱引用,并且我们可以仅配置软引用以进行垃圾回收。

1.5 统计

可以定义统计方式等, 记录缓存的使用情况。

2,redis缓存 (简单介绍)

先说下 redis和caffeine的主要区别和联系:

相同点:
两个都是缓存的方式

不同点:
redis是将数据存储到内存里
caffeine是将数据存储在本地应用里

caffeine和redis相比,没有了网络IO上的消耗

联系:
一般将两者结合起来,形成一二级缓存。使用流程大致如下:
去一级缓存中查找数据(caffeine-本地应用内)
如果没有的话,去二级缓存中查找数据(redis-内存)
再没有,再去数据库中查找数据(数据库-磁盘)

img

原文链接:https://blog.csdn.net/qsbbl/article/details/107764058

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐