Caching im Frühjahr mit EhCache-Anmerkungen
Veröffentlicht: 2022-03-11EhCache ist ein weit verbreiteter, reiner Java-Cache, der problemlos in die gängigsten Java-Frameworks wie Spring und Hibernate integriert werden kann. Es wird oft als die bequemste Wahl für Java-Anwendungen angesehen, da es einfach in Projekte integriert werden kann. Bestimmtes:
- Es kann eingerichtet werden, indem Sie einfach das JAR in Ihr Projekt aufnehmen. Es sind keine zusätzlichen Installationsschritte erforderlich.
- Es läuft im selben Prozess wie die Anwendung, also ist es schnell. Für die Ausführung ist kein zusätzlicher Dienst erforderlich.
Kurz gesagt, EhCache ist eine großartige Wahl für jede reine Java-Anwendung.
Darüber hinaus ermöglichen EhCache Spring Annotations eine nahtlose Integration in jede Spring-Anwendung, indem einfach Annotationen zu Cache-fähigen Methoden hinzugefügt werden, ohne die Methodenimplementierungen zu ändern.
Während EhCache unkomplizierte, reichhaltige APIs zur programmgesteuerten Bearbeitung des Cache bereitstellt, konzentriert sich dieser Artikel hauptsächlich darauf, Ihre Spring-Anwendungen mit EhCache Spring Annotations auf weniger aufdringliche Weise zu verbessern. Wir richten ein Spring MVC-Projekt ein und stellen einen RESTful-Webdienst in Tomcat bereit. Dann wird EhCache in den Webdienst integriert.
Projektübersicht
Wir demonstrieren EhCache-Anmerkungen im Kontext eines Beispielprojekts. Wir richten einen Spring MVC-basierten Webdienst ein, der auf einem Tomcat 8-Server gehostet wird.
Ich habe das Projekt in Eclipse entwickelt, das gemäß den Anweisungen hier installiert werden kann.
Die neueste stabile Version von Tomcat, Tomcat 8, kann hier heruntergeladen werden.
Natürlich sind diese spezifischen Plattformen keine Voraussetzung für EhCache; Sie können jederzeit Ihre bevorzugte IDE und Ihren bevorzugten Server auswählen.
Die EhCache Spring Annotations JAR ist hier verfügbar. Wie wir sehen können, gibt es für jede Version zwei JARs: eines mit Abhängigkeiten und eines ohne. Der mit Abhängigkeiten enthält auch EhCache 2 und Spring 3, die erforderlich sind, damit EhCache-Anmerkungen funktionieren. Es ist einfacher einzurichten, wenn wir das mit den Abhängigkeiten herunterladen und es unserem Build-Pfad hinzufügen.
EhCache Spring Annotations ist auch mit Spring 4 kompatibel, muss jedoch separat konfiguriert werden. Es ist nicht klar, ob das Projekt EhCache 3 in naher Zukunft unterstützen wird. Für diejenigen, die EhCache 3 verwenden oder verwenden möchten, wird der in diesem Artikel beschriebene Annotationsansatz nicht empfohlen.
Schließlich werden wir Maven verwenden, um alles zu verwalten. Maven wird mit den meisten Eclipse-Installationen vorinstalliert geliefert, kann aber auch hier bezogen werden. Spring MVC- und EhCache Spring Annotations-Abhängigkeiten können ziemlich einfach hinzugefügt werden, wie später in diesem Artikel gezeigt wird.
Projektaufbau
Falls Sie noch nie ein Spring-Projekt aufgesetzt haben, finden Sie vielleicht auch den Beitrag von Stefan Varga zum Thema aufschlussreich.
Für diese Demonstration werden wir ein grundlegendes Projekt mit dem Maven-Archetyp maven-archetype-webapp . Die gesamte Dateistruktur sieht folgendermaßen aus:
Erstellen Sie ein Verzeichnis, src/main/java , mit drei Paketen: com.toptal.blog , com.toptal.blog.cache und com.toptal.blog.service . Unsere Anwendungsquelle wird in diese Pakete aufgenommen, wie weiter unten beschrieben.
Lassen Sie uns ein Tomcat-Servlet namens „springrest“ in web.xml definieren:
<web-app> ... <servlet> <servlet-name>springrest</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springrest</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app> Sofern nicht ausdrücklich anders angegeben, sucht ein Spring MVC DispatcherServlet nach einer XML-Konfigurationsdatei mit dem Namen {servlet-name}-servlet.xml im Verzeichnis WEB-INF . Lassen Sie uns eine Konfigurationsdatei namens springrest-servlet.xml . Um mit @RequestMapping kommentierte Spring-Prozesscontrollermethoden zu aktivieren, fügen wir dieser Datei einfach <mvc:annotation-driven /> hinzu. Lassen Sie uns außerdem das Basispaket für Spring definieren, um Beans automatisch zu scannen und zu registrieren, indem <context:component-scan base-package="com.toptal.blog" /> . Die springrest-servlet.xml Konfiguration wird zu:
<beans ... > <mvc:annotation-driven /> <context:component-scan base-package="com.toptal.blog" /> </beans>Ein einfacher RESTful-Webdienst
Nachdem unser Projekt nun richtig konfiguriert ist, implementieren wir eine einfache „Nachrichtendienst“-API. In unserem Basispaket project.toptal.blog fügen wir SpringRestControllerWithEhCache.java mit einer GET-Methode zum Abrufen einer Nachricht nach ID und einer POST-Methode zum Festlegen einer Nachricht nach ID hinzu:
@RestController @RequestMapping( "/" ) public class SpringRestControllerWithEhCache { @Autowired MessageService messageService; @RequestMapping( value = "/message/{id}", method = RequestMethod.GET ) public String getMessage( @PathVariable Integer id ) { String message = messageService.getMessage( id ); System.out.println( "get message ["+message+"] at "+new Date() ); return message; } @RequestMapping( value = "/message/set/{id}/{message}", method = RequestMethod.POST ) public String setMessage( @PathVariable Integer id, @PathVariable String message ) { System.out.println( "set message ["+message+"] at "+new Date() ); messageService.setMessage( id, message ); return message; } } Wir definieren die Klasse MessageService in com.toptal.blog.service . Es greift auf Nachrichten zu, die in unserem System of Records (SOR) gespeichert sind. In einer Produktions-App wäre die SOR so etwas wie eine relationale Datenbank. Der Einfachheit halber verwenden wir eine HashMap :
@Service public class MessageService { private ConcurrentHashMap<Integer, String> messages = new ConcurrentHashMap<Integer, String>(); public String getMessage( Integer id ) { System.out.println( "Getting data from SOR......" ); return messages.get( id ); } public void setMessage( Integer id, String message ){ messages.put( id, message ); } } Wenn wir nun das Projekt als WAR exportieren und in Tomcat bereitstellen, sollten wir in der Lage sein, eine Nachricht, zum Beispiel „test_message“, für ID=1 festzulegen, indem wir eine HTTP-POST-Anfrage unter http://localhost:8080/EhCacheExample/message/set/1/test_message erstellen http://localhost:8080/EhCacheExample/message/set/1/test_message . Wir sollten dann in der Lage sein, „test_message“ mit einer HTTP-GET-Anfrage unter http://localhost:8080/EhCacheExample/message/1 . Ich habe Insomnia als praktischen REST-Client für meinen Test verwendet.
Schließen Sie EhCache Spring-Anmerkungen an
Lassen Sie uns jetzt EhCache für uns arbeiten lassen. Es sind nur wenige schnelle Schritte erforderlich, um unser Projekt so zu konfigurieren, dass EhCache ordnungsgemäß ausgeführt wird.
Schritt 1: Aktualisieren Sie die Abhängigkeiten, um EhCache Spring-Anmerkungen zu verwenden
Fügen Sie die EhCache Spring Annotations-Abhängigkeit in Mavens pom.xml hinzu:
<!-- ehcache --> <dependency> <groupId>com.googlecode.ehcache-spring-annotations</groupId> <artifactId>ehcache-spring-annotations</artifactId> <version>1.2.0</version> </dependency>Schritt 2: Richten Sie einen benutzerdefinierten Cache-Manager ein
Spring verfügt über einen integrierten EhCache-Cache-Manager, org.springframework.cache.ehcache.EhCacheManagerFactoryBean . Dies ist für die meisten Caching-Situationen geeignet, aber ich habe festgestellt, dass die Definition eines benutzerdefinierten Cache-Managers nützlich ist, da ich damit den Cache entweder programmgesteuert oder mit Anmerkungen unter Verwendung desselben Cache-Managers steuern kann. Dieser Artikel konzentriert sich auf Anmerkungen, aber lassen Sie uns weitermachen und einen benutzerdefinierten Cache-Manager definieren, damit wir bereit sind, falls wir ihn brauchen. Wenn Sie lieber beim Standard-Cache-Manager bleiben möchten, können Sie diesen Schritt überspringen.

Wir definieren die neue Klasse in com.toptal.blog.cache.CustomCacheManager :
public class CustomCacheManager extends net.sf.ehcache.CacheManager{ public CustomCacheManager(){ super(); } /* Add your own cache methods here. * * public void myCustomCacheMethod(){ * // your code here * } * */ } Aktivieren Sie es, indem Sie springrest-servlet.xml wie folgt aktualisieren:
... <ehcache:annotation-driven cache-manager="customCacheManager" /> <bean class="com.toptal.blog.cache.CustomCacheManager" scope="singleton"></bean> ...Schritt 3: EhCache konfigurieren
Erstellen Sie abschließend die EhCache-Konfigurationsdatei ehcache.xml im Klassenpfad. Standardmäßig fügt Eclipse src/main/resources in den Klassenpfad ein, und wir platzieren die Datei hier. Diese Datei ist erforderlich, damit EhCache ordnungsgemäß funktioniert. Es definiert die Cache-Namen und einige Eigenschaften jedes Caches, wie z. B. timeToLiveSeconds :
<ehcache xmlms:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd"> <diskStore path="cache" /> <cache name="messageCache" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="0" timeToLiveSeconds="10" overflowToDisk="false" memoryStoreEvictionPolicy="LFU" /> </ehcache>Schritt 4: Testen Sie den Cache
Jetzt, da alles eingerichtet und einsatzbereit ist, sollte die Verwendung von EhCache eine einfache und glückliche Arbeit sein. Wir können einfach @Cacheable zu der Methode oder Klasse hinzufügen, die wir zwischenspeichern möchten. Beispielsweise habe ich @Cacheable zur Methode MessageService in getMessage hinzugefügt. So einfach ist das!
@Cacheable( cacheName = "messageCache" ) public String getMessage( Integer id ) { System.out.println( "Getting data from SOR......" ); return messages.get( id ); } Um zu testen, ob unser Cache funktioniert, können wir eine Nachricht für ID=1 erstellen, indem wir eine HTTP-POST-Anfrage unter http://localhost:8080/EhCacheExample/message/set/1/newMessage und dann die Nachricht für ID= abrufen 1 mehrmals mit GET-Anforderungen an http://localhost:8080/EhCacheExample/message/1 . Wie Sie in der Konsolenausgabe unten sehen können, fordert der Webdienst den SOR auf, die Nachricht zu erhalten, wenn wir die Nachricht zum ersten Mal anfordern, aber nicht für die nächsten beiden Anforderungen, sondern gibt stattdessen die zwischengespeicherte Nachricht zurück. Da wir die timeToLiveSeconds auf 10 definiert haben, ruft der Webdienst den SOR auf, um die Nachricht nach 10 Sekunden erneut zu erhalten:
set message [newMessage] at Sun Dec 06 23:55:39 MST 2015 get message [newMessage] at Sun Dec 06 23:55:42 MST 2015 Getting data from SOR...... get message [newMessage] at Sun Dec 06 23:55:47 MST 2015 get message [newMessage] at Sun Dec 06 23:55:49 MST 2015 get message [newMessage] at Sun Dec 06 23:55:54 MST 2015 Getting data from SOR......Aktualisieren des Caches
Jetzt genießen wir die Geschwindigkeit und Bequemlichkeit, die uns ein Cache bietet, und EhCache ist nett genug, um alle 10 Sekunden von selbst zu aktualisieren. Aber was ist, wenn wir es sofort nach der Aktualisierung unseres SOR aktualisieren möchten? EhCache Spring Annotation bietet @TriggersRemove an, um bestimmte Schlüssel aus dem Cache zu entfernen, wenn die kommentierte Methode aufgerufen wird. In unserer Nachrichtendienst-API sollte die zwischengespeicherte Nachricht aus dem Cache entfernt werden, wenn setMessage aufgerufen wird. Wenn also das nächste Mal eine getMessage Anforderung eingeht, holt der Cache einen neuen Datensatz aus dem SOR:
@Cacheable( cacheName = "messageCache", keyGenerator = @KeyGenerator ( // method name is not included in cache key to work with @TriggersRemove name = "HashCodeCacheKeyGenerator", properties = @Property( name="includeMethod", value="false" ))) public String getMessage( Integer id ) { System.out.println( "Getting data from SOR......" ); return messages.get( id ); } @TriggersRemove( cacheName = "messageCache", keyGenerator = @KeyGenerator ( name = "HashCodeCacheKeyGenerator", properties = @Property( name="includeMethod", value="false" ))) public void setMessage( @PartialCacheKey Integer id, String message ) { messages.put( id, message ); } Ein Schlüsselgenerator wird vom Cache-Manager verwendet, um den Cache-Schlüssel zu generieren. Eine Liste vordefinierter Cache-Key-Generatoren finden Sie hier. Standardmäßig @KeyGenerator sowohl den Methodennamen als auch die übergebenen Parameter, um den Cache-Schlüssel zu generieren. Da wir jedoch möchten, dass die setMessage Methode denselben Schlüssel wie getMessage und den mit diesem Schlüssel verknüpften zwischengespeicherten Wert löscht, müssen wir nur die Nachrichten-ID als Schlüssel verwenden und den Methodennamen für die Schlüsselgenerierung eliminieren. Daher setzen wir die Eigenschaft includeMethod des Schlüsselgenerators für beide Methoden auf false . Da setMessage zwei Argumente hat, verwenden wir außerdem die @ @PartialCacheKey -Annotation von EhCache für den id -Parameter, um anzugeben, dass dies die einzige ist, die vom Schlüsselgenerator verwendet werden soll. Denken Sie schließlich daran, dass wir einen dedizierten Cache, messageCache , für diesen Ressourcentyp konfiguriert haben, sodass die Verwendung nur der ID für den Schlüssel keine Gefahr von Konflikten mit anderen Ressourcentypen darstellt.
Wenn wir nun mehrere HTTP-Anforderungen für die Nachricht mit ID = 1 ausführen, gehen Sie wie folgt vor:
HTTP POST: http://localhost:8080/EhCacheExample/message/set/1/newMessage1 HTTP GET:http://localhost:8080/EhCacheExample/message/1 HTTP POST: http://localhost:8080/EhCacheExample/message/set/1/newMessage2 HTTP GET:http://localhost:8080/EhCacheExample/message/1Die Konsole zeigt:
set message [newMessage1] at Tue Dec 08 17:53:44 MST 2015 get message [newMessage1] at Tue Dec 08 17:53:47 MST 2015 Getting data from SOR...... set message [newMessage2] at Tue Dec 08 17:53:50 MST 2015 get message [newMessage2] at Tue Dec 08 17:53:53 MST 2015 Getting data from SOR......Fazit
Die endgültige Projektstruktur sieht wie folgt aus:
In diesem Beispiel haben wir zunächst eine einfache Spring MVC RESTful-Webanwendung erstellt. Ohne auch nur eine Zeile des vorhandenen Anwendungscodes zu ändern, haben wir EhCache dann mithilfe von EhCache Spring Annotations nahtlos in die Anwendung integriert. Wir haben gezeigt, dass EhCache Spring Annotations sowohl einfach zu installieren (durch Hinzufügen seiner Maven-Abhängigkeit) als auch elegant zu verwenden ist (durch Hinzufügen von Annotationen zu Methoden).
Weiterführende Lektüre
Die EhCache-Dokumentation finden Sie hier und die EhCache Spring Annotations-Dokumentation hier.
Sehen Sie sich auch das in diesem Artikel auf GitHub beschriebene Beispielprojekt an.
