** 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ベースのプロジェクトです。そのまま実行します。