Mise en cache en Java : Redis, Memcached et solutions intégrées : niveau avancé
\n\nLa mise en cache est l'un des outils clés pour améliorer les performances et l'évolutivité des applications Java. Au niveau avancé, le développeur est confronté au choix entre les systèmes distribués (Redis, Memcached) et les caches intégrés légers (Caffeine, Guava). Dans cet article, nous analyserons les différences architecturales, les scénarios d'utilisation et fournirons des exemples de code pratiques pour chaque solution.
\n\n1. Caches intégrés : Caffeine et Guava
\n\nLes caches intégrés fonctionnent au sein de la JVM et ne nécessitent pas de services externes. Ils sont idéaux pour stocker des données temporaires qui n'ont pas besoin d'être synchronisées entre les nœuds.
\n\nCaffeine — le standard moderne
\nCaffeine est une bibliothèque de mise en cache haute performance pour Java qui a succédé à Guava Cache. Elle utilise l'algorithme Window TinyLFU pour une éviction efficace des entrées.
\n\n// Dépendance Maven\n// <dependency>\n// <groupId>com.github.ben-manes.caffeine</groupId>\n// <artifactId>caffeine</artifactId>\n// <version>3.1.8</version>\n// </dependency>\n\nimport com.github.benmanes.caffeine.cache.Cache;\nimport com.github.benmanes.caffeine.cache.Caffeine;\n\nimport java.util.concurrent.TimeUnit;\n\npublic class CaffeineExample {\n public static void main(String[] args) {\n Cache<String, User> userCache = Caffeine.newBuilder()\n .expireAfterWrite(10, TimeUnit.MINUTES)\n .maximumSize(10_000)\n .recordStats()\n .build();\n\n // Écriture\n userCache.put("user:123", new User("Alice", "alice@example.com"));\n\n // Lecture\n User user = userCache.getIfPresent("user:123");\n System.out.println("Utilisateur en cache : " + user);\n\n // Lecture atomique avec chargement\n User result = userCache.get("user:456", key -> loadUserFromDB(key));\n }\n\n private static User loadUserFromDB(String key) {\n // Simulation de chargement depuis la base de données\n return new User("Bob", "bob@example.com");\n }\n\n static class User {\n private final String name;\n private final String email;\n\n User(String name, String email) {\n this.name = name;\n this.email = email;\n }\n\n @Override\n public String toString() {\n return "User{name='" + name + "', email='" + email + "'}";\n }\n }\n}\n\n\nGuava Cache — une solution éprouvée
\nGuava Cache de Google reste un choix populaire pour les projets qui utilisent déjà la bibliothèque Guava. Il prend en charge différentes stratégies d'éviction et des écouteurs.
\n\nimport com.google.common.cache.CacheBuilder;\nimport com.google.common.cache.CacheLoader;\nimport com.google.common.cache.LoadingCache;\n\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\n\npublic class GuavaCacheExample {\n public static void main(String[] args) throws ExecutionException {\n LoadingCache<String, String> cache = CacheBuilder.newBuilder()\n .expireAfterAccess(5, TimeUnit.MINUTES)\n .maximumSize(5000)\n .removalListener(notification -> \n System.out.println("Supprimé : " + notification.getKey()))\n .build(new CacheLoader<String, String>() {\n @Override\n public String load(String key) {\n return "Calculé : " + key.toUpperCase();\n }\n });\n\n // Écriture\n cache.put("key1", "value1");\n\n // Lecture avec chargement automatique\n String value = cache.get("key2");\n System.out.println(value); // "Calculé : KEY2"\n }\n}\n\n\n2. Mise en cache distribuée avec Redis
\n\nRedis est