Caching di Musim Semi dengan Anotasi EhCache
Diterbitkan: 2022-03-11EhCache adalah cache Java murni yang banyak digunakan yang dapat dengan mudah diintegrasikan dengan kerangka kerja Java paling populer, seperti Spring dan Hibernate. Ini sering dianggap sebagai pilihan paling nyaman untuk aplikasi Java karena dapat diintegrasikan ke dalam proyek dengan mudah. Khususnya:
- Itu dapat diatur hanya dengan memasukkan JAR dalam proyek Anda. Tidak diperlukan langkah instalasi tambahan.
- Ini berjalan dalam proses yang sama dengan aplikasi, jadi cepat. Tidak ada layanan tambahan yang diperlukan untuk menjalankan.
Singkatnya, EhCache adalah pilihan tepat untuk aplikasi Java murni apa pun.
Selain itu, EhCache Spring Annotations memungkinkan integrasi tanpa batas ke aplikasi Spring apa pun hanya dengan menambahkan anotasi ke metode yang dapat di-cache, tanpa memodifikasi implementasi metode.
Sementara EhCache menyediakan API yang kaya dan langsung untuk memanipulasi cache secara terprogram, artikel ini terutama berfokus pada peningkatan aplikasi Spring Anda dengan cara yang tidak terlalu mengganggu dengan EhCache Spring Annotations. Kami akan menyiapkan proyek Spring MVC dan menyebarkan layanan web RESTful di Tomcat. Kemudian, EhCache akan diintegrasikan ke layanan web.
Ulasan Proyek
Kami akan mendemonstrasikan Anotasi EhCache dalam konteks proyek contoh. Kami akan menyiapkan layanan web berbasis MVC Spring yang dihosting di server Tomcat 8.
Saya mengembangkan proyek di Eclipse, yang dapat diinstal dengan mengikuti petunjuk di sini.
Tomcat versi stabil terbaru, Tomcat 8, dapat diunduh di sini.
Tentu saja, platform khusus ini bukan persyaratan untuk EhCache; Anda selalu dapat memilih IDE dan server favorit Anda.
JAR Anotasi Musim Semi EhCache tersedia di sini. Seperti yang bisa kita lihat, ada dua JAR untuk setiap versi: satu dengan dependensi dan satu tanpa dependensi. Yang dengan dependensi juga menyertakan EhCache 2 dan Spring 3, yang diperlukan agar anotasi EhCache berfungsi. Lebih mudah untuk mengatur jika kita mengunduh yang memiliki dependensi dan menambahkannya ke jalur build kita.
EhCache Spring Annotations juga kompatibel dengan Spring 4, meskipun harus dikonfigurasi secara terpisah. Tidak jelas apakah proyek tersebut akan mendukung EhCache 3 dalam waktu dekat. Bagi mereka yang menggunakan, atau berniat menggunakan, EhCache 3, pendekatan anotasi yang dibahas dalam artikel ini tidak disarankan.
Terakhir, kita akan menggunakan Maven untuk mengatur semuanya. Maven sudah dikemas dengan sebagian besar instalasi Eclipse, tetapi juga dapat diperoleh di sini. Ketergantungan Spring MVC dan EhCache Spring Annotations dapat ditambahkan dengan cukup mudah, seperti yang ditunjukkan nanti dalam artikel ini.
Pengaturan Proyek
Jika Anda belum pernah membuat proyek Musim Semi sebelumnya, Anda mungkin juga menemukan posting Stefan Varga tentang subjek yang informatif.
Untuk demonstrasi ini, kami akan menyiapkan proyek dasar menggunakan arketipe Maven maven-archetype-webapp
. Struktur file keseluruhan akan terlihat seperti ini:
Buat direktori, src/main/java
, dengan tiga paket: com.toptal.blog
, com.toptal.blog.cache
, dan com.toptal.blog.service
. Sumber aplikasi kami akan masuk dalam paket-paket ini, seperti yang dijelaskan lebih lanjut.
Mari kita definisikan servlet Tomcat yang disebut "springrest" di web.xml
:
<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>
Kecuali ditentukan lain secara eksplisit, Spring MVC DispatcherServlet
akan mencari file konfigurasi XML bernama {servlet-name}-servlet.xml
di direktori WEB-INF
. Mari buat file konfigurasi bernama springrest-servlet.xml
. Untuk mengaktifkan metode pengontrol proses Spring yang dianotasi dengan @RequestMapping
, cukup tambahkan <mvc:annotation-driven />
ke file ini. Juga, mari kita definisikan paket dasar untuk Spring untuk memindai dan mendaftarkan kacang secara otomatis dengan menambahkan <context:component-scan base-package="com.toptal.blog" />
. springrest-servlet.xml
menjadi:
<beans ... > <mvc:annotation-driven /> <context:component-scan base-package="com.toptal.blog" /> </beans>
Layanan Web RESTful Sederhana
Sekarang proyek kita telah dikonfigurasi dengan benar, mari kita implementasikan API “message service” sederhana. Dalam paket dasar kami, project.toptal.blog
, kami akan menambahkan SpringRestControllerWithEhCache.java
, dengan satu metode GET untuk mendapatkan pesan berdasarkan ID, dan satu metode POST untuk menetapkan pesan berdasarkan ID:
@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; } }
Kami akan mendefinisikan kelas MessageService
di com.toptal.blog.service
. Ini akan mengakses pesan yang disimpan di System of Records (SOR) kami. Dalam aplikasi produksi, SOR akan menjadi sesuatu seperti database relasional. Untuk kesederhanaan, kami akan menggunakan 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 ); } }
Sekarang, jika kita mengekspor proyek sebagai WAR dan menyebarkannya di Tomcat, kita seharusnya dapat mengatur pesan, misalnya “test_message”, untuk ID=1, dengan membuat permintaan HTTP POST di http://localhost:8080/EhCacheExample/message/set/1/test_message
. Kami kemudian harus bisa mendapatkan "test_message" kembali dengan permintaan HTTP GET di http://localhost:8080/EhCacheExample/message/1
. Saya menggunakan Insomnia sebagai REST Client yang nyaman untuk melakukan pengujian saya.
Pasang Anotasi Pegas EhCache
Sekarang mari buat EhCache bekerja untuk kita. Hanya diperlukan beberapa langkah cepat untuk mengonfigurasi proyek kami agar dapat menjalankan EhCache dengan benar.
Langkah 1: Perbarui Dependensi untuk menggunakan EhCache Spring Annotations
Tambahkan ketergantungan EhCache Spring Annotations di pom.xml
Maven :
<!-- ehcache --> <dependency> <groupId>com.googlecode.ehcache-spring-annotations</groupId> <artifactId>ehcache-spring-annotations</artifactId> <version>1.2.0</version> </dependency>
Langkah 2: Siapkan Pengelola Cache Khusus
Spring memiliki pengelola cache EhCache bawaan, org.springframework.cache.ehcache.EhCacheManagerFactoryBean
. Ini cocok untuk sebagian besar situasi caching, tetapi saya telah menemukan mendefinisikan pengelola cache khusus berguna karena memungkinkan saya untuk mengontrol cache baik secara terprogram, atau dengan anotasi, menggunakan pengelola cache yang sama. Artikel ini berfokus pada anotasi, tetapi mari kita lanjutkan dan tentukan pengelola cache khusus sehingga kita akan siap jika kita membutuhkannya. Jika Anda lebih memilih untuk tetap menggunakan pengelola cache default, Anda dapat melewati langkah ini.

Kami akan mendefinisikan kelas baru di 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 * } * */ }
Aktifkan dengan memperbarui springrest-servlet.xml
sebagai berikut:
... <ehcache:annotation-driven cache-manager="customCacheManager" /> <bean class="com.toptal.blog.cache.CustomCacheManager" scope="singleton"></bean> ...
Langkah 3: Konfigurasikan EhCache
Terakhir, buat file konfigurasi ehcache.xml
di classpath. Secara default, Eclipse akan menyertakan src/main/resources
di classpath, dan kami akan menempatkan file di sini. File ini diperlukan agar EhCache berfungsi dengan baik. Ini mendefinisikan nama cache dan beberapa properti dari setiap cache, seperti 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>
Langkah 4: Uji Cache
Sekarang, dengan semua yang telah diatur dan siap digunakan, menggunakan EhCache seharusnya menjadi pekerjaan yang mudah dan menyenangkan. Kita cukup menambahkan @Cacheable
ke metode atau kelas yang ingin kita cache. Misalnya, saya menambahkan @Cacheable
ke metode getMessage
di MessageService
. Semudah itu!
@Cacheable( cacheName = "messageCache" ) public String getMessage( Integer id ) { System.out.println( "Getting data from SOR......" ); return messages.get( id ); }
Untuk menguji apakah cache kita berfungsi, kita dapat membuat pesan untuk ID=1 dengan mengeluarkan permintaan HTTP POST di http://localhost:8080/EhCacheExample/message/set/1/newMessage
, dan kemudian mendapatkan pesan untuk ID= 1 beberapa kali, dengan GET permintaan ke http://localhost:8080/EhCacheExample/message/1
. Seperti yang Anda lihat di keluaran konsol di bawah, layanan web meminta SOR untuk mendapatkan pesan saat pertama kali kami meminta pesan, tetapi tidak untuk dua permintaan berikutnya, sebagai gantinya mengembalikan pesan yang di-cache. Karena kami mendefinisikan timeToLiveSeconds
menjadi 10, layanan web memanggil SOR untuk mendapatkan pesan lagi setelah 10 detik:
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......
Menyegarkan Cache
Sekarang, kami menikmati kecepatan dan kemudahan yang diberikan cache, dan EhCache cukup bagus untuk menyegarkan dengan sendirinya setiap 10 detik. Tetapi bagaimana jika kita ingin segera me-refresh setelah SOR kita diperbarui? EhCache Spring Annotation menawarkan @TriggersRemove
untuk menghapus kunci tertentu dari cache saat metode beranotasi dipanggil. Di API layanan pesan kami, pesan yang di-cache harus dihapus dari cache saat setMessage
dipanggil. Jadi, saat berikutnya permintaan getMessage
masuk, cache akan mengambil catatan baru dari 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 ); }
Generator kunci digunakan oleh manajer cache untuk menghasilkan kunci cache. Daftar pembuat kunci cache yang telah ditentukan sebelumnya dapat ditemukan di sini. Secara default, @KeyGenerator
menggunakan nama metode dan parameter yang diteruskan untuk menghasilkan kunci cache. Tetapi karena kita ingin metode setMessage
menghasilkan kunci yang sama dengan getMessage
dan menghapus nilai cache yang terkait dengan kunci itu, kita harus menggunakan hanya ID pesan sebagai kunci dan menghilangkan nama metode untuk pembuatan kunci. Oleh karena itu, kami menetapkan properti includeMethod
generator kunci menjadi false
untuk kedua metode. Juga, karena setMessage
memiliki dua argumen, kami menggunakan anotasi @PartialCacheKey
pada parameter id
untuk menentukan bahwa itu adalah satu-satunya yang harus digunakan oleh generator kunci. Terakhir, ingat bahwa kami mengonfigurasi cache khusus, messageCache
, untuk jenis sumber daya ini, jadi hanya menggunakan ID untuk kunci tidak menimbulkan bahaya konflik dengan jenis sumber daya lainnya.
Sekarang, jika kita melakukan beberapa permintaan HTTP untuk pesan dengan ID=1, sebagai berikut:
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/1
Konsol akan menampilkan:
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......
Kesimpulan
Struktur proyek akhir terlihat seperti ini:
Dalam contoh ini, pertama-tama kita membuat aplikasi web Spring MVC RESTful sederhana. Tanpa memodifikasi satu baris pun dari kode aplikasi yang ada, kami kemudian dengan mulus mengintegrasikan EhCache ke dalam aplikasi menggunakan EhCache Spring Annotations. Kami telah menunjukkan bahwa EhCache Spring Annotations mudah dipasang (dengan menambahkan ketergantungan Maven-nya) dan elegan untuk digunakan (dengan menambahkan anotasi ke metode).
Bacaan lebih lanjut
Dokumentasi EhCache dapat ditemukan di sini dan dokumentasi EhCache Spring Annotations di sini.
Juga, lihat contoh proyek yang dijelaskan dalam artikel ini di GitHub.