2Guava缓存 · SpringCloud微服务实战 · 看云

导航

本节代码地址


1. Guava Cache 简介

Guava Cache 是一个全内存的本地缓存实现,它提供了线程安全的实现机制。整体上来说 Guava Cache 是本地缓存的不二之选,因为其简单易用,性能好。Guava Cache 不是一个单独的缓存框架,而是 Guava 中的一个模块。

Guava Cache 的优点体现在三个方面:

  • 本地缓存,读取效率高,不受网络因素影响。
  • 拥有丰富的功能,操作简单。
  • 线程安全。

Guava Cache 的不足之处也体现在三个方面:

  • 缓存为本地缓存,不能持久化数据。
  • 单机缓存,受机器内存限制,当应用重启数据时会丢失。
  • 分布式部署时无法保证数据的一致性。

2. 回收策略

Guava Cache 是本地缓存,对于数据的缓存一定要有限制,不能盲目缓存数据,我们可
以通过配置一些回收策略来进行缓存的回收
CacheBuilder 为基于时间的回收提供了两种方式

  1. 当缓存项在指定的时间段内没有被读或写就会被回收 这种回收策略类似于基于容量回收策略
 expireAfterAccess(long, TimeUnit)

  1. 当缓存项在指定的时间段内没有更新就会被回收 如果我们认为缓存数据在一段时间后不再可用,那么可以使用该种策略
expireAfterWrite(long, TimeUnit)

CacheBuilder 提供了显示移除的3种方式:

  1. CacheBuilder.invalidate(key)单个移除
  2. CacheBuilder.invalidteAll(keys)批 移除
  3. CacheBuilder.invalidateAll() 移除全部

CacheBuilder 还提供了通过设置最大容量来进行移除的方式当超出指定的容后缓存将尝试回收最近没有使用或总体上很少使用的缓存项

CacheBuilder.newBuilder().maximumSize(1000)

3. 新建模块

具体示例我们通过新建一个模块单独演示Guava Cache
fde74c587a0db9f67c901b1e68216d8a_MD5.webp

并且需要依赖guava包,这样就可以使用Guava Cache了,版本笔者使用的是22.0

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>${guava.version}</version>
</dependency>

4. 核心代码

笔者对外提供一个查询接口,就口中使用CacheBuilder定义了缓存的对象、超时时间、缓存数量的内容,接口访问的时候如果缓存有即走缓存,或者会走非缓存查询一次。


@Service
@Slf4j
public class UserServiceImpl implements UserService {

   private  LoadingCache<Long, User> cache = CacheBuilder
            .newBuilder()
            .maximumSize(1000)
            .expireAfterAccess(20, TimeUnit.MINUTES)
            .build(new CacheLoader<Long, User>() {
                @Override
                public User load(Long id) {
                    User user = getUserByDao(id);
                    return user;
                }
            });


    @Override
    public User getUserById(long id) {

        try {
            User user = cache.get(id);
            if (null != user) {
                cache.put(id, user);
                return user;
            }
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return null;
    }

    private User getUserByDao(long id) {
        List<User> userList = initUser().stream().filter(user -> user.getId() == id).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(userList)) {
            return new User(0, null, null, null, "这位顾客先拿一下腰牌!");
        }
        log.info("我是非缓存的,请多指教");
        return userList.get(0);
    }

5. 对外提供的接口

笔者对外提供了一个可以访问的获取用户接口,供测试

@RestController
@RequestMapping("user")
@Slf4j
public class GuavaController {

    @Autowired
    private UserService userService;

    @GetMapping("/{id:\\d+}")
    public User getUserById(@PathVariable Long id) {
        User user = userService.getUserById(id);
        user.setRemark(user.getRemark());
        return user;
    }



}

6. 启动项目

浏览器或Postman 输入 http://localhost:8801/user/1可以再控制台看到第一次输出是走的非缓存,后面再点击 http://localhost:8801/user/1控制台即不会输出非缓存的数据。
03c91838eec9b9ab9f922288bd3b3ff4_MD5.png

控制台信息如下

2020-03-19 11:44:02.846  INFO 42212 --- [nio-8801-exec-2] c.y.c.g.service.impl.UserServiceImpl     : 我是非缓存的,请多指教