Panduan Untuk Caching di Musim Semi

1. Abstraksi Cache?

Di artikel ini, kami akan menunjukkan cara menggunakan Abstraksi Caching di Musim Semi - dan secara umum, meningkatkan kinerja sistem Anda.

Kami akan mengaktifkan caching sederhana untuk beberapa contoh metode dunia nyata dan kami akan membahas bagaimana kami secara praktis dapat meningkatkan kinerja panggilan ini melalui manajemen cache cerdas.

2. Memulai

Abstraksi caching inti yang disediakan oleh Spring berada dalam modul konteks pegas . Jadi, saat menggunakan Maven, pom.xml kita harus berisi dependensi berikut:

 org.springframework spring-context 5.2.8.RELEASE 

Menariknya, ada modul lain bernama spring-context-support, yang berada di atas modul konteks-pegas dan menyediakan beberapa CacheManager yang didukung oleh orang-orang seperti EhCache atau Caffeine. Jika Anda akan menggunakannya sebagai penyimpanan cache, gunakan modul dukungan konteks pegas sebagai gantinya:

 org.springframework spring-context-support 5.2.8.RELEASE 

Karena modul dukungan konteks pegas secara transitif bergantung pada modul konteks pegas , tidak diperlukan deklarasi ketergantungan terpisah untuk konteks pegas.

2.1. Sepatu Musim Semi

Jika Anda adalah pengguna Spring Boot, gunakan paket starter spring-boot-starter-cache untuk menambahkan dependensi caching dengan mudah:

 org.springframework.boot spring-boot-starter-cache 2.3.3.RELEASE 

Di bawah kap, starter dilengkapi modul pendukung konteks pegas .

3. Aktifkan Caching

Untuk mengaktifkan caching, Spring memanfaatkan anotasi dengan baik, seperti mengaktifkan fitur tingkat konfigurasi lainnya dalam kerangka kerja.

Fitur caching dapat diaktifkan secara deklaratif hanya dengan menambahkan anotasi @EnableCaching ke salah satu kelas konfigurasi:

@Configuration @EnableCaching public class CachingConfig { @Bean public CacheManager cacheManager() { return new ConcurrentMapCacheManager("addresses"); } }

Anda tentu saja dapat mengaktifkan manajemen cache dengan konfigurasi XML juga:

Catatan: Setelah kita mengaktifkan caching - untuk pengaturan minimal - kita harus mendaftarkan cacheManager .

3.1. Menggunakan Spring Boot

Saat menggunakan Spring Boot, kehadiran paket starter di classpath bersama anotasi EnableCaching akan mendaftarkan ConcurrentMapCacheManager yang sama . Jadi, tidak perlu deklarasi kacang terpisah.

Selain itu, kita dapat menyesuaikan CacheManager yang dikonfigurasi secara otomatis menggunakan satu atau lebih kacang CacheManagerCustomizer :

@Component public class SimpleCacheCustomizer implements CacheManagerCustomizer { @Override public void customize(ConcurrentMapCacheManager cacheManager) { cacheManager.setCacheNames(asList("users", "transactions")); } }

The CacheAutoConfiguration auto-konfigurasi mengambil penyesuai ini dan berlaku mereka untuk saat ini CacheManager sebelum inisialisasi lengkap.

4. Gunakan Caching Dengan Anotasi

Setelah kita mengaktifkan caching, langkah selanjutnya adalah mengikat perilaku caching ke metode dengan anotasi deklaratif.

4.1. @ Dapat disimpan dalam cache

Cara termudah untuk mengaktifkan perilaku caching untuk sebuah metode adalah dengan membatasi dengan @Cacheable dan membuat parameter dengan nama cache di mana hasilnya akan disimpan:

@Cacheable("addresses") public String getAddress(Customer customer) {...} 

The getAddress () panggilan pertama akan memeriksa cache alamat sebelum benar-benar memanggil metode dan kemudian caching hasilnya.

Meskipun dalam banyak kasus, satu cache sudah cukup, framework Spring juga mendukung beberapa cache untuk diteruskan sebagai parameter:

@Cacheable({"addresses", "directory"}) public String getAddress(Customer customer) {...}

Dalam kasus ini, jika salah satu cache berisi hasil yang diperlukan, hasilnya dikembalikan dan metode tidak dipanggil.

4.2. @ Cache

Sekarang, apa masalah jika membuat semua metode @Cacheable ?

Masalahnya adalah ukuran - kami tidak ingin mengisi cache dengan nilai yang tidak sering kami perlukan . Cache bisa tumbuh cukup besar, cukup cepat, dan kami mungkin menyimpan banyak data yang sudah usang atau tidak digunakan.

The @CacheEvict penjelasan digunakan untuk menunjukkan penghapusan satu atau lebih / semua nilai - sehingga nilai-nilai segar dapat dimuat ke dalam cache lagi:

@CacheEvict(value="addresses", allEntries=true) public String getAddress(Customer customer) {...}

Di sini, kami menggunakan parameter tambahan allEntries bersama dengan cache yang akan dikosongkan - untuk menghapus semua entri di alamat cache dan mempersiapkannya untuk data baru.

4.3. @ Cacheut

Meskipun @CacheEvict mengurangi pengeluaran untuk mencari entri dalam cache yang besar dengan menghapus entri lama dan tidak terpakai, idealnya, Anda ingin menghindari mengeluarkan terlalu banyak data dari cache .

Sebaliknya, Anda ingin memperbarui entri secara selektif dan cerdas setiap kali diubah.

Dengan anotasi @CachePut , Anda dapat memperbarui konten cache tanpa mengganggu eksekusi metode. Artinya, metode ini akan selalu dijalankan dan hasilnya di-cache.

@CachePut(value="addresses") public String getAddress(Customer customer) {...}

The difference between @Cacheable and @CachePut is that @Cacheable will skip running the method, whereas @CachePut will actually run the method and then put its results in the cache.

4.4. @Caching

What if you want to use multiple annotations of the same type for caching a method. Look at the incorrect example below:

@CacheEvict("addresses") @CacheEvict(value="directory", key=customer.name) public String getAddress(Customer customer) {...}

The above code would fail to compile since Java does not allow multiple annotations of the same type to be declared for a given method.

The workaround to the above issue would be:

@Caching(evict = { @CacheEvict("addresses"), @CacheEvict(value="directory", key="#customer.name") }) public String getAddress(Customer customer) {...}

As shown in the code snippet above, you can group multiple caching annotations with @Caching, and use it to implement your own customized caching logic.

4.5. @CacheConfig

With the @CacheConfig annotation, you can streamline some of the cache configuration into a single place – at the class level – so that you don't have to declare things multiple times:

@CacheConfig(cacheNames={"addresses"}) public class CustomerDataService { @Cacheable public String getAddress(Customer customer) {...}

5. Conditional Caching

Sometimes, caching might not work well for a method in all situations.

For example – reusing our example from the @CachePut annotation – this will both execute the method as well as cache the results each and every time:

@CachePut(value="addresses") public String getAddress(Customer customer) {...} 

5.1. Condition Parameter

Now – if we want more control over when the annotation is active – @CachePut can be parametrized with a condition parameter that takes a SpEL expression to ensure that the results are cached based on evaluating that expression:

@CachePut(value="addresses", condition="#customer.name=='Tom'") public String getAddress(Customer customer) {...}

5.2. Unless Parameter

We can also control the caching based on the output of the method rather than the input – via the unless parameter:

@CachePut(value="addresses", unless="#result.length()<64") public String getAddress(Customer customer) {...}

The above annotation would cache addresses unless they are shorter than 64 characters.

It's important to know that the condition and unless parameters can be used in conjunction with all the caching annotations.

Caching bersyarat semacam ini terbukti sangat berguna untuk mengelola hasil yang besar dan menyesuaikan perilaku berdasarkan parameter input alih-alih menerapkan perilaku umum ke semua operasi.

6. Caching berbasis XML deklaratif

Jika Anda tidak memiliki akses ke kode sumber aplikasi Anda atau ingin memasukkan perilaku caching secara eksternal, Anda juga bisa menggunakan cache deklaratif berbasis XML.

Berikut adalah konfigurasi XML kami:

7. Caching berbasis Java

Dan berikut adalah Konfigurasi Java yang setara:

@Configuration @EnableCaching public class CachingConfig { @Bean public CacheManager cacheManager() { SimpleCacheManager cacheManager = new SimpleCacheManager(); cacheManager.setCaches(Arrays.asList( new ConcurrentMapCache("directory"), new ConcurrentMapCache("addresses"))); return cacheManager; } }

Dan inilah CustomerDataService kami :

@Component public class CustomerDataService { @Cacheable(value = "addresses", key = "#customer.name") public String getAddress(Customer customer) { return customer.getAddress(); } }

8. Ringkasan

Dalam artikel ini, kita membahas dasar-dasar Caching di Spring dan cara memanfaatkan abstraksi tersebut dengan anotasi.

Implementasi lengkap artikel ini dapat ditemukan di proyek GitHub.