1. Pengambilan Cache?
Dalam artikel ini, kami akan menunjukkan cara menggunakan Caching Abstraction pada Musim Bunga - dan secara amnya, meningkatkan prestasi sistem anda.
Kami akan mengaktifkan cache mudah untuk beberapa contoh kaedah dunia nyata dan kami akan membincangkan bagaimana kami dapat secara praktikal meningkatkan prestasi panggilan ini melalui pengurusan cache pintar.
2. Bermula
Pengabaian cache inti yang disediakan oleh Spring terdapat dalam modul konteks musim bunga . Jadi, semasa menggunakan Maven, pom.xml kami harus mengandungi kebergantungan berikut:
org.springframework spring-context 5.2.8.RELEASE
Menariknya, terdapat satu lagi modul bernama spring-konteks-support, yang berada di atas modul spring-konteks dan menyediakan beberapa lagi CacheManagers yang disokong oleh orang-orang seperti EhCache atau Caffeine. Sekiranya anda akan menggunakannya sebagai simpanan cache anda, gunakan modul sokongan konteks musim semi sebagai gantinya:
org.springframework spring-context-support 5.2.8.RELEASE
Oleh kerana modul sokongan konteks musim semi secara sementara bergantung pada modul konteks musim bunga , tidak ada keperluan untuk deklarasi ketergantungan yang terpisah untuk konteks musim bunga.
2.1. Spring Boot
Sekiranya anda pengguna Spring Boot, gunakan pakej starter spring-boot-starter-cache untuk menambahkan pergantungan cache dengan mudah:
org.springframework.boot spring-boot-starter-cache 2.3.3.RELEASE
Di bawah tudung, pemula membawa modul sokongan konteks musim bunga .
3. Dayakan Caching
Untuk membolehkan caching, Spring menggunakan anotasi dengan baik, seperti mengaktifkan ciri tahap konfigurasi lain dalam rangka.
Fungsi caching dapat diaktifkan secara deklaratif dengan hanya menambahkan anotasi @EnableCaching ke mana-mana kelas konfigurasi:
@Configuration @EnableCaching public class CachingConfig { @Bean public CacheManager cacheManager() { return new ConcurrentMapCacheManager("addresses"); } }
Anda tentu saja dapat mengaktifkan pengurusan cache dengan konfigurasi XML juga:
Catatan: Setelah kita mengaktifkan cache - untuk persediaan minimum - kita mesti mendaftarkan cacheManager .
3.1. Menggunakan Spring Boot
Semasa menggunakan Spring Boot, hanya kehadiran pakej starter di classpath di samping anotasi EnableCaching akan mendaftarkan ConcurrentMapCacheManager yang sama . Jadi, tidak ada keperluan untuk pengisytiharan kacang terpisah.
Juga, kita dapat menyesuaikan CacheManager yang dikonfigurasi secara automatik 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 memungut penyesuai ini dan menggunakannya untuk semasa CacheManager sebelum pengawalan yang lengkap.
4. Gunakan Caching Dengan Anotasi
Setelah kami mengaktifkan caching, langkah seterusnya adalah mengikat tingkah laku caching dengan kaedah dengan anotasi deklaratif.
4.1. @ Cacheable
Cara termudah untuk mengaktifkan tingkah laku cache untuk satu kaedah adalah dengan membezakannya dengan @Cacheable dan membuat parameter dengan nama cache di mana hasilnya akan disimpan:
@Cacheable("addresses") public String getAddress(Customer customer) {...}
The getAddress () Panggilan yang pertama akan memeriksa cache alamat sebelum benar-benar memohon kaedah dan kemudian cache keputusan.
Walaupun dalam kebanyakan kes, satu cache cukup, rangka Spring juga menyokong banyak cache untuk dilalui sebagai parameter:
@Cacheable({"addresses", "directory"}) public String getAddress(Customer customer) {...}
Dalam kes ini, jika ada cache yang berisi hasil yang diperlukan, hasilnya dikembalikan dan kaedahnya tidak digunakan.
4.2. @ CacheEvict
Sekarang, apa masalahnya dengan membuat semua kaedah @Cacheable ?
Masalahnya ialah ukuran - kami tidak mahu mengisi cache dengan nilai yang tidak sering kami perlukan . Cache dapat tumbuh cukup besar, cukup cepat, dan kita dapat menyimpan banyak data basi atau tidak terpakai.
The @CacheEvict anotasi digunakan untuk menunjukkan penyingkiran satu atau lebih / semua nilai - supaya nilai segar boleh dimuatkan ke dalam cache sekali 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 membersihkan semua entri di alamat cache dan menyiapkannya untuk data baru.
4.3. @ CachePut
Walaupun @CacheEvict mengurangkan overhead mencari entri dalam cache besar dengan membuang entri basi dan tidak digunakan, idealnya, anda ingin mengelakkan pengusiran terlalu banyak data dari cache .
Sebaliknya, anda ingin mengemas kini entri secara selektif dan cerdas setiap kali ia diubah.
Dengan anotasi @CachePut , anda boleh mengemas kini kandungan cache tanpa mengganggu pelaksanaan kaedah. Artinya, kaedah itu akan selalu dijalankan dan hasilnya disimpan dalam 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 dapat terbukti sangat berguna untuk mengurus hasil yang besar dan menyesuaikan tingkah laku berdasarkan parameter input dan bukannya menerapkan tingkah laku generik untuk semua operasi.
6. Caching berasaskan XML deklaratif
Sekiranya anda tidak memiliki akses ke kod sumber aplikasi anda atau ingin memasukkan tingkah laku cache secara luaran, anda juga dapat menggunakan cache berbasis XML deklaratif.
Berikut adalah konfigurasi XML kami:
7. Caching berasaskan Java
Dan inilah 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 Perkhidmatan PelangganData kami :
@Component public class CustomerDataService { @Cacheable(value = "addresses", key = "#customer.name") public String getAddress(Customer customer) { return customer.getAddress(); } }
8. Ringkasan
Dalam artikel ini, kami membincangkan asas-asas Caching in Spring dan bagaimana memanfaatkan abstraksi itu dengan penjelasan.
Pelaksanaan penuh artikel ini boleh didapati dalam projek GitHub.