Spring从3.1开始定义了 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接口来统一不同的缓存技术; 并支持使用 JCache(JSR-107) 注解简化我们开发。
常用的缓存实现有 RedisCache 、EhCache、ConcurrentMapCache 、Guava Cache(谷歌)等。
Spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单的加一个注解,就能实现缓存功能
Spring Cache提供了一层抽象,底层可以切换不同的Cache实现,具体是通过CacheManager接口来统一不同的缓存技术
针对于不同的缓存技术需要实现不同的CacheManager:
CacheManager | 描述 |
EhCacheCacheManager | 使用EhCache作为缓存技术 |
GuavaCacheManager | 使用Google的GuavaCache作为缓存技术 |
RedisCacheManager | 使用Redis作为缓存技术 |
我们来介绍Spring Cache用于缓存的常用的四个注解:
注解 | 说明 |
@EnableCaching | 开启缓存注解功能 |
@Cacheable | 在方法执行前先查看缓存中是否存有数据,如果有数据直接返回数据;如果没有,调用方法并将返回值存入缓存 |
@CachePut | 将方法的返回值放到缓存 |
@CacheEvict | 将一条或多条从缓存中删除 |
在Spring项目中,使用缓存技术只需要导入相关缓存技术的依赖包,并在启动类上加上@EnableCaching开启缓存支持即可
EhCache 是一个纯Java的进程内缓存管理框架,属于开源的Java分布式缓存框架,主要用于通用缓存,Java EE和轻量级容器,是从 Hibernate 的缓存开始的。
目前版本已到了Ehcache 3.10,Ehcache 3引入了以下内容:
改进的 API,利用 Java 泛型并简化缓存交互,
与javax.cache API (JSR-107)完全兼容,
堆下存储功能,包括仅堆下缓存,
开箱即用的Spring Caching和Hibernate集成,这要归功于javax.cache支持
1、快速轻量: Ehcache 是最快的 Java 缓存之一,很小的 jar 包
2、伸缩性:缓存在内存和磁盘存储可以伸缩到数 G
3、灵活性:Ehcache 1.2 具备对象 API 接口和可序列化 API 接口。
4、标准支持 Ehcache 提供了对 JSR107 JCACHE API 最完整的实现
5、可扩展性 监听器可以插件化
6、应用持久化 在 VM 重启后,持久化到磁盘的存储可以复原数据
官网:Ehcache
ehcache-core:API,标准缓存引擎,RMI 复制和 Hibernate 支持
ehcache:分布式 Ehcache,包括 Ehcache 的核心和 Terracotta 的库
ehcache-monitor:企业级监控和管理
ehcache-web:为 Java Servlet Container 提供缓存、gzip 压缩支持的 filters
ehcache-jcache:JSR107 JCACHE 的实现
ehcache-jgroupsreplication:使用 JGroup 的复制
ehcache-jmsreplication:使用 JMS 的复制
ehcache-openjpa:OpenJPA 插件
ehcache-server:war 内部署或者单独部署的 RESTful cache server
ehcache-unlockedreadsview:允许 Terracotta cache 的无锁读
ehcache-debugger:记录 RMI 分布式调用事件
Ehcache for Ruby:Jruby and Rails 支持
cache manager:缓存管理器,以前是只允许单例的,不过现在也可以多实例了
cache:缓存管理器内可以放置若干 cache,存放数据的实质,所有 cache 都实现了 Ehcache 接口
element:单条缓存数据的组成单位
system of record(SOR):可以取到真实数据的组件,可以是真正的业务逻辑、外部接口调用、存放真实数据的数据库等等,缓存就是从 SOR 中读取或者写入到 SOR 中去的
Ehcache 支持的数据存储包括:
堆上存储 - 利用 Java 的堆上 RAM 内存来存储缓存条目。此层使用与 您的 Java 应用程序,所有这些应用程序都必须由 JVM 垃圾回收器扫描。您的 JVM 堆空间越多 利用,应用程序性能受垃圾回收暂停的影响就越大。这家商店是 速度极快,但通常是您最有限的存储资源。
堆外存储 - 大小仅受可用 RAM 的限制。 不受 Java 垃圾回收 (GC) 的约束。 非常快,但比堆上存储慢,因为在存储和重新访问数据时,必须将数据移入和移出 JVM 堆。
磁盘存储 - 利用磁盘(文件系统)存储缓存条目。 这种类型的存储资源通常非常丰富,但比基于 RAM 的存储慢得多。至于所有使用磁盘的应用程序 存储时,建议使用快速专用的磁盘来优化吞吐量。
群集存储 - 此数据存储是远程服务器上的缓存。 远程服务器可以选择具有故障转移服务器,以提供改进的高可用性。 由于群集存储会因网络延迟以及建立客户端/服务器一致性等因素而带来性能损失, 从本质上讲,此层比本地堆外存储慢。
引入依赖:
org.ehcache ehcache3.10.0
配置文件:
配置类代码:
@ConditionalOnProperty(name = "spring.cache.type", havingValue = "ehcache") @Configuration @EnableCaching//标注启动缓存. public class CacheConfig { /** * @param ehCacheManagerFactoryBean * @return */ @Bean public EhCacheCacheManager ehCacheCacheManager(EhCacheManagerFactoryBean ehCacheManagerFactoryBean){ System.out.println("CacheConfiguration.ehCacheCacheManager()"); return new EhCacheCacheManager(ehCacheManagerFactoryBean.getObject()); } /* * 据shared与否的设置, * Spring分别通过CacheManager.create() * 或new CacheManager()方式来创建一个ehcache基地. */ @Bean public EhCacheManagerFactoryBean ehCacheManagerFactoryBean(){ System.out.println("CacheConfiguration.ehCacheManagerFactoryBean()"); EhCacheManagerFactoryBean cacheManagerFactoryBean = new EhCacheManagerFactoryBean (); cacheManagerFactoryBean.setShared(true); return cacheManagerFactoryBean; } }
工具类:
public class CacheUtils { private static CacheManager cacheManager = SpringContextHolder.getBean(CacheManager.class); private static final String SYS_CACHE = "sysCache"; /** * 获取SYS_CACHE缓存 * * @param key * @return */ public static Object get(String key) { return get(SYS_CACHE, key); } /** * 获取SYS_CACHE缓存 * * @param key * @param defaultValue * @return */ public static Object get(String key, Object defaultValue) { Object value = get(key); return value != null ? value : defaultValue; } /** * 写入SYS_CACHE缓存 * * @param key * @return */ public static void put(String key, Object value) { put(SYS_CACHE, key, value); } /** * 从SYS_CACHE缓存中移除 * * @param key * @return */ public static void remove(String key) { remove(SYS_CACHE, key); } /** * 获取缓存 * * @param cacheName * @param key * @return */ public static Object get(String cacheName, String key) { if( getCache(cacheName).get(key) == null){ return null; }else { return getCache(cacheName).get(key).get(); } } /** * 获取缓存 * * @param cacheName * @param key * @param defaultValue * @return */ public static Object get(String cacheName, String key, Object defaultValue) { Object value = get(cacheName, key); return value != null ? value : defaultValue; } /** * 写入缓存 * * @param cacheName * @param key * @param value */ public static void put(String cacheName, String key, Object value) { getCache(cacheName).put(key, value); } /** * 从缓存中移除 * * @param cacheName * @param key */ public static void remove(String cacheName, String key) { getCache(cacheName).evict(key); } /** * 获得一个Cache,没有则显示日志。 * * @param cacheName * @return */ private static Cache getCache(String cacheName) { Cache cache = cacheManager.getCache(cacheName); if (cache == null) { throw new RuntimeException("当前系统中没有定义“" + cacheName + "”这个缓存。"); } return cache; } }
测试代码:
@Cacheable(key="'user_'+#id",value="userCache") public User getUserById(String id) { return userDao.findById(id); }
这是一个cache框架,可以根据需要引入不同的cache实现方案
上一篇:13 Go的错误处理