Guava Cache 缓存

实现示例

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.util.concurrent.TimeUnit;

public class GuavaCacheExample {
    public static void main(String[] args) {
        Cache<String, String> cache = CacheBuilder.newBuilder()
                .maximumSize(100) // 设置缓存最大容量
                .expireAfterWrite(10, TimeUnit.MINUTES) // 设置写入后的过期时间
                .build();

        // 添加键值对到缓存
        cache.put("key1", "value1");

        // 从缓存中获取值
        String value = cache.getIfPresent("key1");
        System.out.println(value); // 输出: value1

        // 移除缓存中的键值对
        cache.invalidate("key1");
    }
}

Ehcache 缓存

实现示例

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;

public class EhcacheExample {
    public static void main(String[] args) {
        CacheManager cacheManager = CacheManager.newInstance();

        Cache cache = new Cache("myCache", 10000, false, false, 60, 30);
        cacheManager.addCache(cache);

        // 添加键值对到缓存
        Element element = new Element("key1", "value1");
        cache.put(element);

        // 从缓存中获取值
        Element result = cache.get("key1");
        System.out.println(result.getObjectValue()); // 输出: value1

        // 移除缓存中的键值对
        cache.remove("key1");

        cacheManager.shutdown();
    }
}

Caffeine 缓存

实现示例

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;

import java.util.concurrent.TimeUnit;

public class CaffeineCacheExample {
    public static void main(String[] args) {
        Cache<String, String> cache = Caffeine.newBuilder()
                .maximumSize(100) // 设置缓存最大容量
                .expireAfterWrite(10, TimeUnit.MINUTES) // 设置写入后的过期时间
                .build();

        // 添加键值对到缓存
        cache.put("key1", "value1");

        // 从缓存中获取值
        String value = cache.getIfPresent("key1");
        System.out.println(value); // 输出: value1

        // 移除缓存中的键值对
        cache.invalidate("key1");
    }
}

ConcurrentHashMap&FutureTask 建立高速缓存

此实现中ConcurrentHashMap 提供了线程安全的哈希表,而 FutureTask 用来包装计算任务,支持异步计算。

实现示例

import java.util.concurrent.*;

public class SimpleCacheWithFutureTask<K, V> {
    private final ConcurrentHashMap<K, FutureTask<V>> cache = new ConcurrentHashMap<>();

    public V get(K key, Callable<V> valueLoader) throws ExecutionException, InterruptedException {
        FutureTask<V> futureTask = cache.get(key);
        if (futureTask != null) {
            return futureTask.get(); // 如果缓存中存在,直接返回值
        } else {
            FutureTask<V> newTask = new FutureTask<>(valueLoader);
            futureTask = cache.putIfAbsent(key, newTask); // 如果key不存在,则添加任务到缓存
            if (futureTask == null) {
                futureTask = newTask;
                newTask.run(); // 启动新的计算任务
            }
            return futureTask.get(); // 返回计算结果
        }
    }

    public static void main(String[] args) {
        SimpleCacheWithFutureTask<String, Integer> cache = new SimpleCacheWithFutureTask<>();

        try {
            int value = cache.get("key", () -> {
                System.out.println("Simulating expensive computation...");
                Thread.sleep(2000); // 模拟耗时操作
                return 42;
            });

            System.out.println("Value: " + value); // 输出: Value: 42

            // 再次获取相同的键,应该直接从缓存中获取值,而不需要重新计算
            int cachedValue = cache.get("key", () -> {
                throw new IllegalStateException("This should not be called.");
            });

            System.out.println("Cached value: " + cachedValue); // 输出: Cached value: 42

        } catch (ExecutionException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

ConcurrentHashMap&FutureTask缓存工具类

@Component
@Slf4j
public class CacheUtil {

    private static final ConcurrentMap<String, Future<String>> cache = new ConcurrentHashMap<>();

    /**
     * 获取缓存数据
     * @param key
     * @return
     */
    public static String getCache(String key) {
        Future<String> future = cache.get(key);
        if (future == null) {
            return null;
        }
        try {
            return future.get();
        } catch (Exception e) {
            log.error("从缓存获取key={}时异常:", key, e);
        }
        return null;
    }

    /**
     * 保存缓存数据
     * @param key
     * @param value
     * @return
     */
    public static String saveCache(String key, String value) {
        log.info("保存缓存key={}, value={}", key, value);
        Future<String> future = cache.get(key);
        if (future == null) {
            Callable<String> callable = new Callable<String>() {
                @Override
                public String call() throws Exception {
                    return new String(value);
                }
            };
            FutureTask<String> task = new FutureTask<>(callable);
            future = cache.putIfAbsent(key,task);
            if (future == null) {
                future = task;
                task.run();
            }
        }
        try {
            return future.get();
        } catch (Exception e) {
            cache.remove(key);
            log.error("保存缓存key={}, value={}时异常:", key, value, e);
        }
        return null;
    }

    /**
     * 更新缓存
     * @param key
     * @param value
     * @return
     */
    public static String updateCache(String key, String value) {
        log.info("更新缓存key={}, value={}", key, value);
        Future<String> future = cache.get(key);
        if (future == null) {
            log.info("缓存中无key={}数据,需要保存", key);
            return saveCache(key, value);
        }
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return new String(value);
            }
        };
        FutureTask<String> task = new FutureTask<>(callable);
        Future<String> replace = cache.replace(key, task);
        if (replace != null) {
            future = task;
            task.run();
        }
        try {
            return task.get();
        } catch (Exception e) {
            cache.remove(key);
            log.error("更新缓存key={}, value={}时异常:", key, value, e);
        }
        return null;
    }

    public static void removeKey(String key) {
        Future<String> future = cache.get(key);
        if (future == null) {
            return;
        }
        log.info("删除缓存key={}", key);
        cache.remove(key);
    }
}

Spring Cache 使用

注解说明

  • @Cacheable 是用来声明方法是可缓存的。将结果存储到缓存中以便后续使用相同参数调用时不需执行实际的方法。直接从缓存中取值。最简单的格式需要制定缓存名称。
  • @CachePut 更新缓存,@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
  • @CacheEvict 删除缓存,@CacheEvict要求指定一个或多个缓存,使之都受影响。此外,还提供了一个额外的参数allEntries 。表示是否需要清除缓存中的所有元素。默认为false,表示不需要。当指定了allEntries为true时,Spring Cache将忽略指定的key。有的时候我们需要Cache一下清除所有的元素。
  • @Caching 当一个注解不能满足功能,可以进行组合。
  • @CacheConfig 有时候一个类中可能会有多个缓存操作,而这些缓存操作可能是重复的。这个时候可以使用。
  • @CacheConfig,是一个类级别的注解,允许共享缓存的名称、KeyGenerator、CacheManager 和CacheResolver。

Caffeine 缓存

引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>     
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
</dependency>

开启缓存

@EnableCaching  //开启缓存
public class DemoApplication{
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
}

缓存配置

@Configuration
@EnableCaching
public class CaffeineCacheConfig extends CachingConfigurerSupport {

    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(caffeineCacheBuilder());
        return cacheManager;
    }

    Caffeine<Object, Object> caffeineCacheBuilder() {
        return Caffeine.newBuilder()
                .expireAfterWrite(10, TimeUnit.MINUTES) // 设置写入后的过期时间
                .maximumSize(100); // 设置缓存最大容量
    }
}

缓存使用

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class MyService {

    @Cacheable(value = "selectById", key = "#id")
    public String getData(int id) {
        // 从数据库或其他数据源获取数据的逻辑
        return "Data : " + id;
    }
}

Redis 缓存

引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

开启缓存

@EnableCaching  //开启缓存
public class DemoApplication{
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
}

缓存配置

@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(10)) // 设置缓存的默认过期时间
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        return RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(config)
                .build();
    }
}

缓存使用

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class MyService {

    @Cacheable(value = "selectById", key = "#id")
    public String getData(int id) {
        // 从数据库或其他数据源获取数据的逻辑
        return "Data : " + id;
    }
}