Le cache de Guava

L'objet ici est de présenter avec trois démos détaillées la prise en main d'un gestionnaire de cache de l'API utilitaire Guava fournie par google.

Cet article peut être rapproché de mon billet qui traitait Ehcache.

Chacune des démos est illustrée par un test unitaire.

Les sources de la démo1 sont fournies.

Passons à la mise en pratique.

DEMO 1.

Dans cette première démo, nous présentons un exemple simple permettant de prendre en main le gestionnaire de cache de Guava.

Etape1: Dépendances maven nécessaires

Dans le pom du projet, en plus des dépendances spring deux autres sont nécessaires.

La dépendance JSR-250 pour l'annotation @PostConstruct et celle de Guava.

Donc, le pom.xml doit avoir ces lignes :

      <!-- jsr 250 -->
      <dependency>
	<groupId>javax.annotation</groupId>
	<artifactId>jsr250-api</artifactId>
	<version>1.0</version>
     </dependency>
     <!-- guava -->
    <dependency>
	<groupId>com.google.guava</groupId>
	<artifactId>guava</artifactId>
	<version>12.0</version>
  </dependency>

Etape2: Les classes java de la démo

Il y a essentiellement deux classes java dans cette première démo:

  • La première est un objet POJO de la couche model.
  • La seconde est l'implémentation du service du cache.

La première classe est nommée Destination :

public class Destination {
 private String libelle;
 private String ville;
 private String pays;
 private String critere;
    //..getters setters omis

}

La seconde classe nommée DestinationCacheManager est celle qui nous intéresse ici.

Elle permet de définir les opérations liées à la gestion du cache.
Ces opérations sont résumées dans l'interface suivant:

public interface DestinationCacheManager {
 void remove(String key) ;
 void put(String key,Destination d);
 Destination get(String key) ;
}

Voici une implémentation de cette interface :

package fr.netapsys.gestioncacheguava.services;
import java.util.concurrent.*;
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;
import com.google.common.cache.*;
import fr.netapsys.gestioncacheguava.model.Destination;
@Component
public class DestinationCacheManagerImpl 
                  implements DestinationCacheManager{

	private Cache<String,Destination> cache;
	
	@PostConstruct
	public void init(){
	  cache = CacheBuilder.newBuilder().
			maximumSize(10).
			expireAfterWrite(1, TimeUnit.MINUTES).  
			/* expire 1 min apres ecriture (ttl)*/
			build();
	}
	
	public Destination get(String key) {
		return cache.getIfPresent(key);
	}
	public void remove(String key) {
		cache.invalidate(key);
	}
	public void put(String key,Destination d){
		cache.put(key, d);
	}
}

L'annotation @Component permet à Spring de gérer ce bean.

L'annotation @PostConstruct de la jsr-250 permet d'initialiser, post création, le bean via la méthode annotée.

Notez que l'implémentation de la méthode get s'appuie sur getIfPresent du CacheBuilder.

Celle-ci retourne null si l'objet n'est pas dans le cache sans lever d'exception.

Etape3: Configuration Spring

Notre démo s'appuie sur le framework Spring, voici son fichier de configuration qui contient une seule ligne.

Le fichier est nommé spring-context.xml et localisé dans src/main/resources/META-INF.

?xml version="1.0" encoding="UTF-8"?>
<beans 
    xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
  http://www.springframework.org/schema/beans 
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context.xsd">
 <context:component-scan base-package="fr.netapsys"/>
</beans>

La seule chose à remarquer est la ligne context:component qui indique le package de base dans lequel Spring doit chercher les beans utiles.

Etape4: Test unitaire

Nous générons une classe JUnit pour tester notre cache.

Voici le code de cette classe:

import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import fr.netapsys.gestioncacheguava.model.Destination;
import fr.netapsys.gestioncacheguava.services.DestinationCacheManager;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations=
     {"classpath*:META-INF/spring-context.xml"})
public class TestDestinationCache {
	@Autowired DestinationCacheManager dcm;
	@Test
	public void testSimple()  {
		Destination destFav=getDestDispo();
               ///mis en cache 
		dcm.put( "destFavorite", destFav);
		
		//first get from cache
		Destination d1=dcm.get("destFavorite");
		Assert.assertSame(d1, destFav);
				
		//another get from cache
		Destination d2=dcm.get("destFavorite");
		Assert.assertSame(d2, destFav);	
	}
	private Destination getDestDispo() {
	 Destination destDispo=new Destination();
	 destDispo.setLibelle("destinFavorite");
	 destDispo.setVille("Paris");
	 destDispo.setPays("France");
	 destDispo.setCritere("C1");
	 return destDispo;
     }
}

Quelques explications sont utiles:

  • l'annotation @RunWith permet de lancer le test JUnit via le lanceur de Spring.
  • l'annotation @ContextConfiguration précise le fichier de configuration de Spring mentionné à l'étape précédente.
  • l'annotation @Autowired permet d'injecter le bean implémentant l'interface DestinationCacheManager.

La méthode testSimple() construit une instance du POJO Destination et le met en cache.

Les appels successifs à la méthode get permettent de voir que, comme le prouve les assertions, l'objet est récupéré correctement du cache.

Pour conclure, la façon de créer et gérer le cache dans la démo1 n'est pas idéale.

Nous verrons dans la seconde démo comment mieux le gérer.

Enfin, le projet démo1 peut-être téléchargé ici.

DEMO 2.

Dans cette partie nous indiquons une autre façon (avancée) d'en tirer profit du gestionnaire de cache de Guava.

Partie 1. Utilisation du CacheLoader/LoadingCache

Partie 2. Utilisation du Callable

Nous nous basons sur les sources du projet de la démo1 que nous allons enrichir au fur et à mesure.

C'est ce que nous ferons dans la seconde partie de ce billet.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.