guva缓存+redis缓存应用

本文介绍使用Guava实现本地缓存的具体案例,包括初始化配置、数据加载与刷新策略等关键环节,并对比Spring Boot自带缓存机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

guava本地缓存应用

        我的应用场景是模糊查询框

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.ListenableFuture;
import com.kevin.demo.pojo.DeveloperCache;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.concurrent.TimeUnit;


public class LocalCacheDemo {

    @Value("${developer.caches.initial-capacity:3000}")
    private Integer initialCapacity;

    @Value("${developer.caches.concurrency-level:16}")
    private Integer concurrencyLevel;

    @Value("${developer.caches.maximum-size:30000}")
    private Integer maximumSize;

    @Value("${developer.caches.entry-timeout:60}")
    private Integer entryTimeout;

    private LoadingCache<String, List<DeveloperCache>> derpSynResps;

    private LoadingCache<String, List<DeveloperCache>> noDerpSynResps;

    @PostConstruct
    void initialize() {
        // derp异步信息
        derpSynRespsInit();

        // derp未异步信息
        noDerpSynRespsInit();
    }

    private void derpSynRespsInit() {
        derpSynResps = CacheBuilder.newBuilder()
                // 初始容量
            .initialCapacity(initialCapacity)
                // 并发级别
            .concurrencyLevel(concurrencyLevel)
                // 最大size
            .maximumSize(maximumSize)
                // 当缓存项上一次更新操作之后的多久会被刷新
            .refreshAfterWrite(entryTimeout, TimeUnit.SECONDS)
            .build(new CacheLoader<String, List<DeveloperCache>>() {
            @Override
            public List<DeveloperCache> load(String unused) throws Exception {
                List<DeveloperCache> developerCacheList = derpStateMapper.queryNameAndPhone();
                developerCacheList.forEach(temp -> {
                    if (!StringUtils.isEmpty(temp.getFullName())) {
                        // 解密
                        temp.setFullName(AESUtils.decrypt(temp.getFullName()));
                    }
                });
                return developerCacheList;
            }

            @Override
            public ListenableFuture<List<DeveloperCache>> reload(String key, List<DeveloperCache> oldValue)
                    throws Exception {
                return super.reload(key, oldValue);
            }
        });
    }

    private void noDerpSynRespsInit() {
        noDerpSynResps = CacheBuilder.newBuilder()
            .initialCapacity(initialCapacity)
            .concurrencyLevel(concurrencyLevel)
            .maximumSize(maximumSize)
            .refreshAfterWrite(entryTimeout, TimeUnit.SECONDS)
            .build(new CacheLoader<String, List<DeveloperCache>>() {
            @Override
            public List<DeveloperCache> load(String unused) throws Exception {
                List<DeveloperCache> developerCacheList = developerMapper.queryNameAndPhone();
                developerCacheList.forEach(temp -> {
                    if (!StringUtils.isEmpty(temp.getFullName())) {
                        temp.setFullName(AESUtils.decrypt(temp.getFullName()));
                    }
                    if (!StringUtils.isEmpty(temp.getContactEmail())) {
                        temp.setContactEmail(AESUtils.decrypt(temp.getContactEmail()));
                    }
                    if (!StringUtils.isEmpty(temp.getContactPhoneNum())) {
                        temp.setContactPhoneNum(AESUtils.decrypt(temp.getContactPhoneNum()));
                    }
                });
                return developerCacheList;
            }

            @Override
            public ListenableFuture<List<DeveloperCache>> reload(String key, List<DeveloperCache> oldValue)
                    throws Exception {
                return super.reload(key, oldValue);
            }
        });
    }

    @SneakyThrows
    private void getDeveloperList() {
        List<DeveloperCache> derpSynRespsList;
        derpSynRespsList = derpSynResps.get("");

        // TODO
    }
}

springboot自带的缓存:存储一些简单的数据结构。

只有在触发@CacheEvict(cacheNames = {DICT_LIST, DICT_VALUE}, allEntries = true)

才会更新缓存

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class SysDictServiceImpl extends ServiceImpl<SysDictDao, SysDict> implements SysDictService {
    @Autowired
    private SysDictDao sysDictDao;

    private static final String DICT_LIST = "dict:list";

    private static final String DICT_VALUE = "dict:value";

    @Override
    @Cacheable(cacheNames = DICT_LIST, key = "#code")
    public List<SysDict> getList(String code) {
        return sysDictDao.getList(code);
    }

    @Override
    @Cacheable(cacheNames = DICT_VALUE, key = "#code+'_'+#dictKey")
    public String getValue(String code, Integer dictKey) {
        return sysDictDao.getValue(code, dictKey);
    }

    @Override
    @CacheEvict(cacheNames = {DICT_LIST, DICT_VALUE}, allEntries = true)
    public void remove(List<Integer> ids) {
        ids.forEach(id -> sysDictDao.deleteById(id));
    }

    @Override
    @CacheEvict(cacheNames = {DICT_LIST, DICT_VALUE}, allEntries = true)
    public void addOrUpdate(SysDict sysDict) {
        Integer count = sysDictDao.getCount(sysDict.getCode(), sysDict.getDictKey());
        if (count > 0) {
            throw new ServiceException("当前字典键值已存在!");
        } else {
            saveOrUpdate(sysDict);
        }
    }
}

想深入了解可参考:

Redis+Guava,性能炸裂!这组合真的太顶了...._公众号-老炮说Java的博客-优快云博客

### Guava库中的多线程使用方法与示例 #### 什么是 `ListenableFuture`? `ListenableFuture` 是 Google 的 Guava 库提供的一种增强版的 Future 接口,它允许开发者注册回调函数,在异步操作完成时自动执行这些回调。相比标准 Java 中的 `Future`,`ListenableFuture` 提供了更灵活的功能[^1]。 #### 如何使用 `ListenableFuture`? 以下是基于 Guava 的 `ListenableFuture` 实现的一个简单示例: ```java import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ListenableFutureExample { public static void main(String[] args) throws Exception { ExecutorService executor = Executors.newSingleThreadExecutor(); // 创建一个 ListeningExecutorService 来支持 ListenableFuture var listeningExecutor = MoreExecutors.listeningDecorator(executor); // 定义一个 Callable 任务 Callable<String> task = () -> { Thread.sleep(2000); return "Task Completed"; }; // 提交任务并获取 ListenableFuture 对象 ListenableFuture<String> future = listeningExecutor.submit(task); // 添加成功回调 future.addListener(() -> { try { System.out.println("Result: " + future.get()); } catch (Exception e) { e.printStackTrace(); } }, executor); System.out.println("Waiting for the result..."); executor.shutdown(); } } ``` 上述代码展示了如何通过 Guava 的 `MoreExecutors.listeningDecorator()` 方法将普通的 `ExecutorService` 转换为支持 `ListenableFuture` 的服务。随后提交了一个耗时的任务,并为其添加了监听器来处理结果。 --- #### 结合 `Futures.transformAsync` 进行链式调用 如果需要对多个异步任务的结果进行组合或转换,可以使用 `Futures.transformAsync` 或其他类似的工具方法。下面是一个简单的链式调用示例: ```java import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class FuturesTransformExample { private static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(2); public static void main(String[] args) throws ExecutionException, InterruptedException { ListenableFuture<Integer> firstStage = createFirstStage(); // 将第一个阶段的结果乘以两倍 ListenableFuture<Integer> secondStage = Futures.transformAsync( firstStage, input -> createSecondStage(input * 2), MoreExecutors.directExecutor() ); System.out.println(secondStage.get()); // 输出最终结果 EXECUTOR.shutdown(); } private static ListenableFuture<Integer> createFirstStage() { return MoreExecutors.listeningDecorator(EXECUTOR).submit(() -> { Thread.sleep(1000); return 5; // 返回初始值 }); } private static ListenableFuture<Integer> createSecondStage(int value) { return MoreExecutors.listeningDecorator(EXECUTOR).submit(() -> { Thread.sleep(1000); return value * 3; // 计算第二阶段的结果 }); } } ``` 在这个例子中,`createFirstStage` 和 `createSecondStage` 分别代表两个独立的异步计算过程。通过 `Futures.transformAsync`,我们可以轻松地将它们串联起来形成一条完整的流水线。 --- #### 关于 `Callable` 和 `Runnable` 的对比 在传统的 Java 并发编程中,通常会使用 `Callable` 或 `Runnable` 来定义任务。其中 `Callable` 支持返回值和抛出异常,而 `Runnable` 则不支持这两者。因此,在需要返回值的情况下推荐优先考虑 `Callable` 配合 `Future` 使用[^2]。 例如: ```java // Runnable 不支持返回值 Runnable runnableTask = () -> System.out.println("Running without returning"); // Callable 可以返回值 Callable<Integer> callableTask = () -> { int sum = 0; for (int i = 1; i <= 10; i++) { sum += i; } return sum; }; ``` --- #### ImmutableMap 的使用场景 虽然本问题是关于多线程的内容,但值得一提的是,Guava 同样提供了许多实用的数据结构工具类,比如不可变集合 `ImmutableMap`。它可以用于安全地共享数据而不必担心被修改的情况[^3]。 创建方式如下所示: ```java import com.google.common.collect.ImmutableMap; public class ImmutableMapExample { public static void main(String[] args) { ImmutableMap<String, Integer> map = ImmutableMap.of("one", 1, "two", 2); System.out.println(map.get("one")); // 输出 1 } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值