春のキャッシングガイド
** 1キャッシュの抽象化
この記事では、
SpringでCaching Abstractionを使用する
方法、そして一般的にシステムのパフォーマンスを向上させる方法を説明します。
実際のメソッドの例で簡単なキャッシングを有効にし、スマートキャッシュ管理によってこれらの呼び出しのパフォーマンスを実質的に向上させる方法について説明します。
2キャッシングを有効にする
キャッシュを有効にするために、Springは、フレームワーク内の他の設定レベル機能を有効にするのと同じように、アノテーションをうまく利用します。
キャッシング機能を宣言的に有効にするには、
@ EnableCaching
アノテーションを任意の構成クラスに追加します。
@Configuration
@EnableCaching
public class CachingConfig {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("addresses");
}
}
もちろん、XML設定によるキャッシュ管理を有効にすることもできます。
<beans>
<cache:annotation-driven/>
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean
class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
name="addresses"/>
</set>
</property>
</bean>
</beans>
-
注意:
キャッシュを有効にした後 – 最小限の設定で – 私たちは
cacheManager
を
登録しなければなりません。 -
XMLを使用すると、キャッシングを設定するためのより柔軟なオプションが可能になります – 独自のCache-Manager、Cache-Resolver、Error-Handlerを指定し、通常はより高度なカスタマイズオプションを使用できます詳細については/current/javadoc-api/org/springframework/cache/annotation/CachingConfigurer.html[Javadocを参照してください]
3注釈付きキャッシングを使用する
キャッシュを有効にしたら、次のステップは、宣言的な注釈を使用してキャッシュ動作をメソッドにバインドすることです。
3.1. @
キャッシュ可能
メソッドのキャッシュ動作を有効にする最も簡単な方法は、それを
@ Cacheable
で区別し、結果が格納されるキャッシュの名前でパラメータ化することです。
@Cacheable("addresses")
public String getAddress(Customer customer) {...}
getAddress()呼び出しは、実際にメソッドを呼び出してから結果をキャッシュする前に、最初にキャッシュ
addresses__をチェックします。
ほとんどの場合、キャッシュは1つで十分ですが、Springフレームワークは複数のキャッシュをパラメータとして渡すこともサポートしています。
@Cacheable({"addresses", "directory"})
public String getAddress(Customer customer) {...}
この場合、いずれかのキャッシュに必要な結果が含まれていると、結果が返され、メソッドは呼び出されません。
3.2.
@
CacheEvict
__
**
-
__
では、すべてのメソッドを
@ Cacheable
にすることの問題は何でしょうか。
問題はサイズです – 私たちがキャッシュに必要としない値をキャッシュに入れたくないでしょう** 。キャッシュは非常に大きく、非常に速く成長する可能性があります。また、古いデータや未使用のデータを多数保持する可能性があります。
@ CacheEvict
アノテーションは、1つまたは複数の/すべての値の削除を示すために使用されます。そのため、新しい値をキャッシュに再度ロードすることができます。
@CacheEvict(value="addresses", allEntries=true)
public String getAddress(Customer customer) {...}
ここでは、空のキャッシュと一緒に追加のパラメータ
allEntries
を使用しています。キャッシュのすべてのエントリをクリアして、新しいデータ用に準備します。
3.3. @
CachePut __
@ CacheEvict
は、古くなった未使用のエントリを削除することによって大規模キャッシュ内のエントリを検索するオーバーヘッドを削減しますが、理想的には、** キャッシュから大量のデータを削除しないようにします。
代わりに、エントリが変更されたときはいつでもエントリを選択的かつインテリジェントに更新する必要があります。
@ CachePut
アノテーションを使用すると、メソッドの実行を妨げることなくキャッシュの内容を更新できます。つまり、メソッドは常に実行され、結果はキャッシュされます。
@CachePut(value="addresses")
public String getAddress(Customer customer) {...}
@ Cacheable
と
@ CachePut
の違いは、
@ Cacheable
は
メソッドの実行をスキップ
する一方、
@ CachePut
は実際に
メソッドを実行
してその結果をキャッシュに格納することです。
3.4. @
キャッシング
メソッドをキャッシュするために同じ型の複数のアノテーションを使いたい場合以下の誤った例を見てください。
@CacheEvict("addresses")
@CacheEvict(value="directory", key=customer.name)
public String getAddress(Customer customer) {...}
Javaは与えられたメソッドに対して同じタイプの複数のアノテーションを宣言することを許可していないので、上記のコードはコンパイルに失敗します。
上記の問題に対する回避策は次のとおりです。
@Caching(evict = {
@CacheEvict("addresses"),
@CacheEvict(value="directory", key="#customer.name") })
public String getAddress(Customer customer) {...}
上記のコードスニペットに示すように、
@ Caching__を使用して
複数のキャッシュアノテーション** をグループ化し、それを使用して独自のカスタマイズされたキャッシュロジックを実装できます。
3.5 @
CacheConfig
@ CacheConfig
アノテーションを使用すると、キャッシュ設定の一部を
クラスレベルで
単一の場所に合理化することができます。そのため、複数回宣言する必要はありません。
@CacheConfig(cacheNames={"addresses"})
public class CustomerDataService {
@Cacheable
public String getAddress(Customer customer) {...}
4条件付きキャッシング
場合によっては、キャッシングがすべての状況でメソッドに対してうまく機能しないことがあります。
たとえば、
@ CachePut
アノテーションの例を再利用すると、メソッドが実行されるだけでなく、結果が毎回キャッシュされます。
@CachePut(value="addresses")
public String getAddress(Customer customer) {...}
4.1条件パラメータ
アノテーションがアクティブになるタイミングをもっと制御したい場合は、
@ CachePut
をSpEL式をとる条件パラメーターでパラメーター化して、その式の評価に基づいて結果が確実にキャッシュされるようにします。
@CachePut(value="addresses", condition="#customer.name=='Tom'")
public String getAddress(Customer customer) {...}
4.2パラメータ以外
入力ではなくメソッドの出力に基づいてキャッシュを制御することもできます。
@CachePut(value="addresses", unless="#result.length()<64")
public String getAddress(Customer customer) {...}
上記のアノテーションは、アドレスが64文字より短い場合を除き、アドレスをキャッシュします。
condition
パラメータと
unless
パラメータはすべてのキャッシュアノテーションと一緒に使用できることを知っておくことは重要です。
この種の条件付きキャッシュは、すべての操作に一般的な動作を強制するのではなく、大きな結果を管理し、入力パラメータに基づいて動作をカスタマイズするのに非常に役立ちます。
5宣言型XMLベースのキャッシング
アプリケーションのソースコードにアクセスできない場合や、キャッシュ動作を外部に注入したくない場合は、宣言型XMLベースのキャッシュを使用することもできます。
これが私たちのXML設定です。
<!-- the service that you wish to make cacheable -->
<bean id="customerDataService"
class="com.your.app.namespace.service.CustomerDataService"/>
<bean id="cacheManager"
class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean
class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
name="directory"/>
<bean
class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
name="addresses"/>
</set>
</property>
</bean>
<!-- define caching behavior -->
<cache:advice id="cachingBehavior" cache-manager="cacheManager">
<cache:caching cache="addresses">
<cache:cacheable method="getAddress" key="#customer.name"/>
</cache:caching>
</cache:advice>
<!-- apply the behavior to all the implementations of CustomerDataService interface->
<aop:config>
<aop:advisor advice-ref="cachingBehavior"
pointcut="execution(** com.your.app.namespace.service.CustomerDataService.** (..))"/>
</aop:config>
6. Javaベースのキャッシング
そしてこれが同等のJava設定です:
@Configuration
@EnableCaching
public class CachingConfig {
@Bean
public CustomerDataService customerDataService() {
return new CustomerDataService();
}
@Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(
new ConcurrentMapCache("directory"),
new ConcurrentMapCache("addresses")));
return cacheManager;
}
}
そして、これが私たちの
CustomerDataService
です:
@Component
public class CustomerDataService {
@Cacheable(value = "addresses", key = "#customer.name")
public String getAddress(Customer customer) {
return customer.getAddress();
}
}
7. 概要
この記事では、Caching in Springの基本と、その抽象化を注釈でどのように活用するかについて説明しました。
この記事の完全な実装はhttps://github.com/eugenp/tutorials/tree/master/spring-all[GitHubプロジェクト]で見つけることができます – これはEclipseベースのプロジェクトです。そのまま実行します。