导入依赖
<!-- https://mvnrepository.com/artifact/com.github.ben-manes.caffeine/caffeine -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.1.7</version>
</dependency>
在Service层中调用Caffeine的接口
@Service
public class DiscussPostService {
private final static Logger logger = LoggerFactory.getLogger(DiscussPostService.class);
@Autowired
private DiscussPostMapper discussPostMapper;
@Value("${caffeine.posts.max-size}")
private int maxSize;
@Value("${caffeine.posts.expire-seconds}")
private int expireSeconds;
// Caffeine's core API: Cache, LoadingCache, AsyncLoadingCache
// posts list cache
private LoadingCache<String, List<DiscussPost>> postListCache;
// posts total number cache
private LoadingCache<Integer, Integer> postRowsCache;
@PostConstruct
public void init(){
// initialize the post list cache
postListCache = Caffeine.newBuilder()
.maximumSize(maxSize)
.expireAfterWrite(expireSeconds, TimeUnit.SECONDS)
.build(new CacheLoader<String, List<DiscussPost>>() {
@Override
public @Nullable List<DiscussPost> load(String key) throws Exception {
if(key == null || key.length() == 0){
throw new IllegalArgumentException("parameter error: key must not be null");
}
String[] params = key.split(":");
if(params == null || params.length != 2) {
throw new IllegalArgumentException("parameter error");
}
int offset = Integer.valueOf(params[0]);
int limit = Integer.valueOf(params[1]);
// in there, we can add second level cache, such as Redis
// if we can't find data in the Redis, then query it in MySQL
logger.debug("load post list from DB...");
return discussPostMapper.selectDiscussPosts(0, offset, limit, 1);
}
});
// initialize the post total number cache
postRowsCache = Caffeine.newBuilder()
.maximumSize(maxSize)
.expireAfterWrite(expireSeconds, TimeUnit.SECONDS)
.build(new CacheLoader<Integer, Integer>() {
@Override
public @Nullable Integer load(Integer key) throws Exception {
logger.debug("load post list from DB...");
return discussPostMapper.selectDiscussPostRows(key);
}
});
}
public List<DiscussPost> findDiscussPosts(int userId, int offset, int limit, int orderMode) {
if(userId == 0 && orderMode == 1){
return postListCache.get(offset + ":" + limit);
}
logger.debug("load post list from DB...");
return discussPostMapper.selectDiscussPosts(userId, offset, limit, orderMode);
}
public int findDiscussPostRows(int userId) {
if (userId == 0) {
return postRowsCache.get(userId);
}
logger.debug("load post rows from DB...");
return discussPostMapper.selectDiscussPostRows(userId);
}
}
测试
@SpringBootTest
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = MyCommunityApplication.class)
public class CaffeineTest {
@Autowired
private DiscussPostService postService;
@Test
public void testCache(){
System.out.println(postService.findDiscussPosts(0, 0, 10, 1));
System.out.println(postService.findDiscussPosts(0, 0, 10, 1));
System.out.println(postService.findDiscussPosts(0, 0, 10, 1));
System.out.println(postService.findDiscussPosts(0, 0, 10, 0));
}
}
结果:
可以看到,第一次记录还未加入缓存,所以是从DB中加载,而后两次访问记录都是从Caffeine中加载的;最后一次访问是强制要求从DB中访问的。