JCache 介绍
JCache 是 Java 官方的缓存规范即 JSR107,主要明白了Java 中基于内存进行对象缓存的一些要求,涵盖对象的创建、查询、更新、删除、一致性保证等方面内容;本文主要介绍其基本概念及简单使用。1、JCache 简介
1.1、核心概念
JCache 中定义了五个核心接口:CachingProvider、CacheManager、Cache、Entry 和 ExpiryPolicy。
A、CachingProvider 用于创建、配置、获取、管理和控制零个或多个 CacheManager;应用程序在运行时可以访问或使用零个或多个 CachingProvider。
B、CacheManager 用于创建、配置、获取、管理和控制零个或多个唯一命名的 Cache,这些 Cache 存在于 CacheManager 的上下文中;一个 CacheManager 只能归属一个 CachingProvider。
C、Cache 是类似 Map 的数据布局,用于临时存储基于 key 的 value;一个 Cache 只能归属一个 CacheManager。
D、Entry 是存储在 Cache 中的键值对。
E、ExpiryPolicy 定义了每个 Entry 在 Cache 中有用时间(TTL),有用期内 Entry 可以或许被访问、修改和删除,有用期后该 Entry 不能在被访问、修改和删除。
对应关系如下:
https://img2024.cnblogs.com/blog/1846282/202402/1846282-20240219103808626-1790101814.png
1.2、相关注解
JSR107 将一些常用的 API 方法封装为注解,使用注解来简化编码的复杂度,低落缓存对于业务逻辑的侵入性,使得业务开发人员更加专注于业务本身的开发。
注解说明@CacheResult将指定的 key 和 value 存入到缓存容器中@CachePut更新缓存容器中对应 key 的缓存内容@CacheRemove移除缓存容器中对应 key 的缓存记录@CacheRemoveAll移除缓存容器中的所有缓存记录@CacheKey指定缓存的 key,用于方法参数前面@CacheValue指定缓存的 value,用于方法参数前面上述注解主要是添加在方法上面,用于自动将方法的入参与返回结果之间进行一个映射与自动缓存,对于后续请求如果命中缓存则直接返回缓存结果而无需再次实行方法的详细处理,以此来提拔接口的响应速度与承压本领。
1.3、值存储和引用存储
JSR-107 中定义了两种存储 Entry 的方法,即按值存储(Store-By-Value)和按引用存储(Store-By-Reference)。
• 按值存储是默认机制,也就是在存储键值对时,先对 key 和 value 进行拷贝,然后将拷贝的副本存储到 Cache 中;当访问 Cache 时,返回的是数据的副本。
• 按引用存储是别的一种可选的机制,存储键值对时,Cache 中存储的是 key 和 value 的引用。当应用程序修改键值对时,应用程序无需再次修改 Cache 中的数据。
1.4、一致性
一致性是指当并发访问缓存时,需要保证修改的可见性在并发线程/历程间是一致的。为了保证一致性,所有的实现框架都应该支持默认一致性模子:
在实行大部分 Cache 操作时,就好像为 Cache 中的每个 key 加了锁,当某个操作获取该 key 的排它性读写锁时,后面对该 key 的所有操作都会被阻塞,直到这个锁释放。注意,这里的操作可以是单个 JVM 历程内的,也可以是跨 JVM 的操作。对于某些具有返回值的 Cache 操作,返回的缓存值需要是最新值。但是这个最新值,可以根据缓存的详细实现定义,比如当并发修改时,这个返回值可以是修改前的值,也可以是修改后的值。
1.5、Cache 和 Map 的差别
相同点:
[*]都是通过 key 进行存储和访问。
[*]每个 key 都与一个 value 对应。
[*]当使用可变对象作为 key 时,修改 key 值可能导致获取不到 key 对应的 value。
[*]使用自定义类作为 key 时,需要覆盖 Object.equals() 和 Object.hashCode() 方法。
不同点:
[*]Cache 的 key 和 value 不许为 null,如果设置了 null,则会抛出 NullPointerException。
[*]Cache 中的 Entry 可能会逾期(Expire)。
[*]Cache 中的 Entry 可能被驱逐(Evicted)。
[*]为了支持原子比力和互换(compare-and-swap, CAP),Cache 中的自定义 key 应覆盖 Object.equals() 和 Object.hashCode() 方法。
[*]Cache 中的 key 和 value 是需要可被序列化的。
[*]Cache 可以设置使用值存储或引用存储来存储 Entry。
[*]Cache 可以选择逼迫的安全性限定,如果违规操作,可以抛出 SecurityException 异常。
2、JCache 使用
JCache 只是定义了一组接口,要使用还需引入详细的实现框架。
2.1、Caffeine 中使用 JCache
2.1.1、引入依靠
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>jcache</artifactId>
<version>2.9.3</version>
</dependency>2.1.2、简单使用
@Test
public void caffeine() {
CachingProvider cachingProvider = Caching.getCachingProvider("com.github.benmanes.caffeine.jcache.spi.CaffeineCachingProvider");
CacheManager cacheManager = cachingProvider.getCacheManager();
MutableConfiguration<Integer, String> mutableConfiguration = new MutableConfiguration<Integer, String>()
.setTypes(Integer.class, String.class)
.setStoreByValue(false)
.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.MINUTES, 5)));
Cache<Integer, String> myCache = cacheManager.createCache("myCache", mutableConfiguration);
myCache.put(1, "aaa");
log.info(myCache.get(1));
cacheManager.close();
}2.2、Ehcache3 中使用 JCache
2.2.1、引入依靠
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.10.8</version>
<exclusions>
<exclusion>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</exclusion>
</exclusions>
</dependency>2.2.2、简单使用
@Test
public void ehcache3() {
CachingProvider cachingProvider = Caching.getCachingProvider("org.ehcache.jsr107.EhcacheCachingProvider");
CacheManager cacheManager = cachingProvider.getCacheManager();
MutableConfiguration<Integer, String> mutableConfiguration = new MutableConfiguration<Integer, String>()
.setTypes(Integer.class, String.class)
.setStoreByValue(false)
.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.MINUTES, 5)));
Cache<Integer, String> myCache = cacheManager.createCache("myCache", mutableConfiguration);
log.info(myCache.getClass().getName() + "|" + myCache.getClass().getCanonicalName());
myCache.put(1, "aaa");
log.info(myCache.get(1));
cacheManager.close();
} Caffeine 及 Ehcache3 中使用 JCache 的完整代码:
https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gifhttps://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gifpackage com.abc.demo.cache;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import javax.cache.Cache;
import javax.cache.CacheManager;
import javax.cache.Caching;
import javax.cache.configuration.MutableConfiguration;
import javax.cache.expiry.CreatedExpiryPolicy;
import javax.cache.expiry.Duration;
import javax.cache.spi.CachingProvider;
import java.util.concurrent.TimeUnit;
@Slf4j
public class JCacheCase {
@Test
public void caffeine() {
CachingProvider cachingProvider = Caching.getCachingProvider("com.github.benmanes.caffeine.jcache.spi.CaffeineCachingProvider");
CacheManager cacheManager = cachingProvider.getCacheManager();
MutableConfiguration<Integer, String> mutableConfiguration = new MutableConfiguration<Integer, String>()
.setTypes(Integer.class, String.class)
.setStoreByValue(false)
.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.MINUTES, 5)));
Cache<Integer, String> myCache = cacheManager.createCache("myCache", mutableConfiguration);
myCache.put(1, "aaa");
log.info(myCache.get(1));
cacheManager.close();
}
@Test
public void ehcache3() {
CachingProvider cachingProvider = Caching.getCachingProvider("org.ehcache.jsr107.EhcacheCachingProvider");
CacheManager cacheManager = cachingProvider.getCacheManager();
MutableConfiguration<Integer, String> mutableConfiguration = new MutableConfiguration<Integer, String>()
.setTypes(Integer.class, String.class)
.setStoreByValue(false)
.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.MINUTES, 5)));
Cache<Integer, String> myCache = cacheManager.createCache("myCache", mutableConfiguration);
log.info(myCache.getClass().getName() + "|" + myCache.getClass().getCanonicalName());
myCache.put(1, "aaa");
log.info(myCache.get(1));
cacheManager.close();
}
}JCacheCase.java2.3、SpringBoot 中 JCache 注解使用
2.3.1、引入依靠
这里使用 Caffeine 作为 JCache 的实现框架。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>jcache</artifactId>
</dependency>
</dependencies>2.3.2、配置缓存名称
spring:
cache:
type: jcache
cacheNames: myCache2.3.3、启用缓存
启动类上增加 @EnableCaching 注解。
@SpringBootApplication
@EnableCaching
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}2.3.4、JCache 注解使用
package com.abc.general.service.impl;
import com.abc.general.service.ICacheService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.cache.annotation.*;
@Slf4j
@Service
public class CacheServiceImpl implements ICacheService {
@CacheResult(cacheName = "myCache")
@Override
public String queryById(@CacheKey int id) {
log.info("queryById,id={}", id);
return "value" + id;
}
@CachePut(cacheName = "myCache")
@Override
public String updateById(@CacheKey int id, @CacheValue String newValue) {
log.info("updateById,id={},newValue={}", id, newValue);
return newValue;
}
@CacheRemove(cacheName = "myCache")
@Override
public void deleteById(@CacheKey int id) {
log.info("deleteById,id={}", id);
}
}
参考:https://developer.aliyun.com/article/786959。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]