Introdução: Por que usar cache em Java?
Aplicações Java modernas frequentemente enfrentam problemas de desempenho ao trabalhar com bancos de dados, APIs externas ou cálculos pesados. Cada requisição repetida a um recurso lento aumenta o tempo de resposta e a carga na infraestrutura. A solução para este problema é o cache.
O cache em Java permite armazenar temporariamente dados frequentemente solicitados em acesso rápido (geralmente na memória RAM), para que em requisições repetidas eles sejam entregues instantaneamente, evitando operações custosas. Isso é criticamente importante para sistemas de alta carga, aplicações web e microsserviços.
Neste artigo, vamos analisar três abordagens principais para cache em Java: soluções distribuídas (Redis, Memcached) e caches embutidos (in-memory). Você aprenderá quando escolher cada ferramenta e verá exemplos de código para cada uma delas.
1. Cache embutido em Java: Ehcache, Caffeine e HashMap
Caches embutidos são bibliotecas que funcionam dentro da JVM da sua aplicação. Eles não exigem a instalação de servidores externos e são ideais para aplicações monolíticas ou microsserviços com pequeno volume de dados.
1.1. Cache simples com HashMap (não para produção)
A maneira mais simples é usar ConcurrentHashMap. Mas esta abordagem não possui mecanismos de limpeza, TTL (tempo de vida) e controle de memória.
import java.util.concurrent.ConcurrentHashMap;
public class SimpleCache<K, V> { private final ConcurrentHashMap<K, V> cache = new ConcurrentHashMap<>();
public V get(K key) { return cache.get(key); }
public void put(K key, V value) { cache.put(key, value); }
public void evict(K key) { cache.remove(key); }}Desvantagens: sem limpeza automática, pode levar a OutOfMemoryError.
1.2. Caffeine — o padrão moderno em Java
Caffeine é uma biblioteca de cache de alto desempenho para Java 8+. Ela suporta limpeza automática baseada em tempo, tamanho e frequência de uso.
import com.github.benmanes.caffeine.cache.Cache;import com.github.benmanes.caffeine.cache.Caffeine;import java.util.concurrent.TimeUnit;
public class CaffeineExample { public static void main(String[] args) { Cache<String, String> cache = Caffeine.newBuilder() .expireAfterWrite(10, TimeUnit.MINUTES) .maximumSize(1000) .build();
// Escrita cache.put("user:123", "John Doe");
// Leitura String user = cache.getIfPresent("user:123"); System.out.println("Usuário em cache: " + user); }}Vantagens do Caffeine: alta velocidade, política de despejo configurável (LRU, LFU), carregamento assíncrono.
1.3. Ehcache — testado pelo tempo
Ehcache é uma das bibliotecas de cache mais antigas para Java. Suporta armazenamento em disco e clusterização.
import org.ehcache.Cache;import org.ehcache.CacheManager;import org.ehcache.config.builders.CacheConfigurationBuilder;import org.ehcache.config.builders.CacheManagerBuilder;import org.ehcache.config.builders.ResourcePoolsBuilder;
public class EhcacheExample { public static void main(String[] args) { CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder() .withCache("myCache", CacheConfigurationBuilder.newCacheConfigurationBuilder( String.class, String.class, ResourcePoolsBuilder.heap(100))) .build(); cacheManager.init();
Cache<String, String> cache = cacheManager.getCache("m