缓存是每一个系统都应该考虑的功能,它用来加速系统的访问,提升系统的性能。
比如说一些经常需要访问的高频热点数据,例如:电商网站的商品信息。 如果商品信息存储在数据库中,每次来查询商品信息都要来查询数据库的话,这样的操作耗时太大,代价也相对太大。 此时我们可以引入一个缓存中间件,将商品信息存放在缓存中,就不需要直接来查询数据库了。先来查询缓存中是否有该商品的信息,如果有就直接拿来使用;如果没有的话,然后再去数据库中查询,然后再将数据放回到缓存。因为应用程序与缓存的交互是非常快的,这样的话就可以大大减缓数据库的压力。再比如:一些临时性的数据,为某个用户的手机号发送了验证码,三分钟有效,过期删除。如果将这些数据存储在数据库中,也是非常有压力的。我们也可以将这些数据存储在缓存中间件中。系统直接从缓存中获取数据即可。
缓存在系统中用的还是非常多的。所以为了统一缓存的开发规范,提升系统的扩展性。J2EE 发布了 JSR-107规范。主要提供了5个接口。
什么是JSR-107
JSR是Java Specification Requests的缩写,意思是Java规范提案。2012年10月26日JSR规范委员会发布了JSR 107(JCache API的首个早期草案)。JCache 规范定义了一种对Java对象临时在内存中进行缓存的方法,包括对象的创建、共享访问、假脱机(spooling)、失效、各JVM的一致性等,可被用于缓存JSP内最经常读取的数据。
Java Caching 定义了5个核心接口,分别是CachingProvider、CacheManager、Cache、Entry 和 Expiry。
接口 | 介绍 |
---|---|
CachingProvider | 缓存提供者。 定义了创建、配置、获取、管理和控制多个 CacheManager。一个应用可以在运行期访问多个 CachingProvider。 |
CacheManager | 缓存管理器。 定义了创建、配置、获取、管理和控制多个唯一命名的 Cache,这些 Cache 存在于 CacheManager 的上下文中。一个 CacheManager 仅被一个 CachingProvider 所拥有。 |
Cache | 缓存组件。 是一个类似 Map 的数据结构并临时存储以 key 为索引的值。一个 Cache 仅被一个 CacheManager 所拥有。 |
Entry | 键值对。 是一个存储在 Cache 中的 key-value 对。 |
Expiry | 有效期。 每一个存储在 Cache 中的条目有一个定义的有效期。一旦超过这个时间,条目为过期的状态。一旦过期,条目将不可访问、更新和删除。缓存有效期可以通过 ExpiryPolicy 设置。 |
应用调用缓存图示
应用来调用缓存,首先会先调用CachingProvider(缓存提供者),缓存提供者管理了多个CacheManager(缓存管理器),缓存管理器中才真正的Cache缓存。缓存管理器中可以管理不同类型的缓存,比如:Redis、EhCache 等。
在具体缓存组件中,我们还可以设置不同模块的缓存,比如:Redis 中我们可以来缓存 商品信息、热点数据 等不同模块数据,每个缓存都是Entry<K,V>键值对类型。并且我们可以对缓存设置Expiry过期时间,指定缓存存活的时间。
缓存在我们应用开发中的调用步骤,如下图所示:
JSR-107规范使用
在项目中使用 JSR-107规范,首先需要导入 Maven 依赖:
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
该包下提供了 CachingProvider 接口,我们可以通过 getCacheManager()方式来获取 CacheManager。 CacheManger 通过 createCache()、getCache() 方法来直接获取到缓存Cache,缓存的具体增删改查操作,就在 Cache 组件中。
总结
JSR-107 作为一个 Java 规范,它定义的都是一些接口,类似于 JDBC 规范。它的好处在于:我们直接面向接口编程,需要用到哪种缓存的实现,我们来直接引入该缓存实现即可,系统就能运行起来。 然而:并不是市面上所有的缓存组件都提供了 JSR-107 规范的实现。如果我们选择的缓存中间件没有实现 JSR-107 规范接口,那么就需要自己来实现咯。整个过程 API 开发也比较麻烦,所以 JSR-107 规范在我们的日常开发中用的还是比较少。