先比较前两着,比较显著的区别: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,也是高性能、分布式的
简单介绍这几种缓存的特点:
EhCache:一个纯Java的进程内缓存框架,具有快速、精干等特点。因为它是纯Java进程的,所以也是基于本地缓存的。(注意:EhCache2.x和EhCache3.x差异巨大且不兼容)
Hazelcast:基于内存的数据网格。虽然它基于内存,但是分布式应用程序可以使用Hazelcast进行分布式缓存、同步、集群、处理、发布/订阅消息等。(如果你正在寻找基于内存的、高速的、可弹性扩展的、支持分布式的、对开发者友好的NoSQL,Hazelcast是一个很棒的选择,它的理念是用应用服务的内存换取效率,成本较高).
从com.hazelcast.spring.cache.HazelcastCacheManager这个包名中也能看出,是它自己实现的Spring Cache标准,而不是spring-data帮它实现的(类似MyBatis集成Spring),但它凭借自己的足够优秀,让Spring接受了它
Infinispan:基于Apache 2.0协议的分布式键值存储系统,可以以普通java lib或者独立服务的方式提供服务,支持各种协议(Hot Rod, REST, WebSockets)。支持的高级特性包括:事务、事件通知、高级查询、分布式处理、off-heap及故障迁移。 它按照署模式分为嵌入式(Embedded)模式(基于本地内存)、Client-Server(C\S)模式。
Couchbase:是一个非关系型数据库,它实际上是由couchdb+membase组成,所以它既能像couchdb那样存储json文档(类似MongoDB),也能像membase那样高速存储键值对。(新一代的NoSql数据库,国外挺火的)
Redis:熟悉得不能再熟悉的分布式缓存,只有Client-Server(C\S)模式,单线程让它天生具有线程安全的特性。Java一般使用Jedis/Luttuce来操纵~
Caffeine(咖啡因):Caffeine是使用Java8对Guava缓存的重写版本,一个接近最佳的的缓存库(号称性能最好)。Spring5已经放弃guava,拥抱caffeine,它的API保持了近乎和guava一致,但是性能上碾压它。
guava是谷歌Google Guava工具包的,使用非常广泛。Caffeine长江后浪推前浪,性能上碾压了Guava,是它的替代品。
SIMPLE:略
原文链接:https://blog.csdn.net/f641385712/article/details/94982916
下面简单介绍下几种缓存的特点:
<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>
下面这段代码相当于在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)
此策略,手动将值放入缓存之后再检索。
//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。
相当于在初始化的时候就缓存赋值,暂不清楚场景!
//step1 : 初始化缓存 LoadingCache<String, DataObject> cache = Caffeine.newBuilder() .maximumSize(100) .expireAfterWrite(1, TimeUnit.MINUTES) .build(k -> DataObject.get("Data for " + k));
和前面差不多,暂不清楚场景。
AsyncLoadingCache<String, DataObject> cache = Caffeine.newBuilder() .maximumSize(100) .expireAfterWrite(1, TimeUnit.MINUTES) .buildAsync(k -> DataObject.get("Data for " + k));
这种回收方式假定当超过配置的缓存大小限制时会发生回收。
这种回收策略是基于条目的到期时间,有三种类型:
访问后到期 — 从上次读或写发生后,条目即过期。 .expireAfterAccess(``5``, TimeUnit.MINUTES)
写入后到期 — 从上次写入发生之后,条目即过期 .expireAfterWrite(``10``, TimeUnit.SECONDS)
自定义策略 — 到期时间由 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));
还未使用过这种: 可以将缓存配置为启用缓存键值的垃圾回收。为此,我们将 key 和 value 配置为 弱引用,并且我们可以仅配置软引用以进行垃圾回收。
可以定义统计方式等, 记录缓存的使用情况。
先说下 redis和caffeine的主要区别和联系:
相同点:
两个都是缓存的方式
不同点:
redis是将数据存储到内存里
caffeine是将数据存储在本地应用里
caffeine和redis相比,没有了网络IO上的消耗
联系:
一般将两者结合起来,形成一二级缓存。使用流程大致如下:
去一级缓存中查找数据(caffeine-本地应用内)
如果没有的话,去二级缓存中查找数据(redis-内存)
再没有,再去数据库中查找数据(数据库-磁盘)
原文链接:https://blog.csdn.net/qsbbl/article/details/107764058