spring boot統合ehcache 2.xはhibernate 2級キャッシュに使用されます。


本論文では、どのようにspring bootにehcacheをヒップホップとして一体化するかを紹介します。各フレームのバージョンは以下の通りです。
  • spring book:1.4.3.RELEASE
  • スプリングフレームワーク:4.3.5.RELEASE
  • hibernate:5.0.11.Final(spring-book-starter-data-jpaデフォルト依存)
  • ehcache:2.1.3
  • プロジェクト依存
    
    <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    
    <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    
    <dependency>
     <groupId>org.hibernate</groupId>
     <artifactId>hibernate-ehcache</artifactId>
     <exclusions>
      <exclusion>
       <groupId>net.sf.ehcache</groupId>
       <artifactId>ehcache-core</artifactId>
      </exclusion>
     </exclusions>
    </dependency>
    
    <dependency>
     <groupId>net.sf.ehcache</groupId>
     <artifactId>ehcache</artifactId>
     <version>2.10.3</version>
    </dependency> 
    
    
    Ehcache概要
    ehcacheは純粋なJavaのキャッシュフレームであり、一つの汎用キャッシュとして使用することもできるし、hibernateの二級キャッシュとして使用することもできる。キャッシュデータは、次の3つのストレージを選択できます。
  • MemoryStore C On-heap memory used to hold cache elemens.This tier is subject to Java garbage collection.
  • OffHeappore C Provides overflow capacity to the MemoryStore.Limited in size only by available RAM.Not subject to Java garbage collection(GC).Available only with Terracotta BigMemory product
  • Disc Store C Backs up in-memory cache elemens and provides overflow capacity to the other tiers.
  • ヒベルナ2級キャッシュの設定
    hibernateの二級キャッシュは、entityとqueryレベルのキャッシュをサポートしています。org.hibernate.ache.spi.RegionFactoryは、各種の抜き差し可能なキャッシュプロバイダとhibernateの集積を提供しています。
    
    #   hibernate    
    spring.jpa.properties.hibernate.generate_statistics=true
    
    #       
    spring.jpa.properties.hibernate.cache.use_second_level_cache=true
    
    #       
    spring.jpa.properties.hibernate.cache.use_query_cache=true
    
    #     provider
    spring.jpa.properties.hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
    
    #   shared-cache-mode
    spring.jpa.properties.javax.persistence.sharedCache.mode=ENABLE_SELECTIVE
    
    hibernateキャッシュに関するすべての構成はヒベルナ5.0公式文書を参照することができる。
    ehcacheプロファイル
    ehcache 2.xプロファイル見本は公式サイトを参照してのehcache.xmlを提供します。本例で使用するプロファイルを以下に示します。
    
    <?xml version="1.0" encoding="UTF-8"?>
    
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="http://www.ehcache.org/ehcache.xsd"
      updateCheck="true" monitoring="autodetect"
      dynamicConfig="true">
    
     <diskStore path="user.dir/cache"/>
     <transactionManagerLookup class="net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup"
            properties="jndiName=java:/TransactionManager" propertySeparator=";"/>
     <cacheManagerEventListenerFactory class="com.yangyi.base.ehcache.CustomerCacheManagerEventListenerFactory" properties=""/>
    
     <defaultCache
      maxEntriesLocalHeap="0"
      eternal="false"
      timeToIdleSeconds="1200"
      timeToLiveSeconds="1200">
      <!--<terracotta/>-->
     </defaultCache>
    
     <cache name="entityCache"
       maxEntriesLocalHeap="1000"
       maxEntriesLocalDisk="10000"
       eternal="false"
       diskSpoolBufferSizeMB="20"
       timeToIdleSeconds="10"
       timeToLiveSeconds="20"
       memoryStoreEvictionPolicy="LFU"
       transactionalMode="off">
      <persistence strategy="localTempSwap"/>
      <cacheEventListenerFactory class="com.yangyi.base.ehcache.CustomerCacheEventListenerFactory" />
     </cache>
    
     <cache name="org.hibernate.cache.internal.StandardQueryCache"
       maxEntriesLocalHeap="5" eternal="false" timeToLiveSeconds="120">
      <persistence strategy="localTempSwap" />
      <cacheEventListenerFactory class="com.yangyi.base.ehcache.CustomerCacheEventListenerFactory" />
     </cache>
    
     <cache name="org.hibernate.cache.spi.UpdateTimestampsCache"
       maxEntriesLocalHeap="5000" eternal="true">
      <persistence strategy="localTempSwap" />
      <cacheEventListenerFactory class="com.yangyi.base.ehcache.CustomerCacheEventListenerFactory" />
     </cache>
    </ehcache>
    
    
    ehcache事件監聴
    ehcacheには、cacheのinit/addedなどの二種類のイベントがあります。二番目はcahche関連のイベントで、例えばcache put/expireなどです。ehcacheでは、デフォルトではこれらの2つのイベントのモニターはなく、自主的にモニターとモニター工場の種類を実現してからehcache.xmlに配置すると、効果があります。
    上記ehcache.xml構成では、カスタムcacheにcacheEventListenerFactoryを配置し、キャッシュイベントを傍受する。cacheManager Factory実現クラスも搭載しています。具体的な実現コードは以下の通りです。
    CacheManager Event Listenerが簡単に実現します。
    
    package com.yangyi.base.ehcache;
    
    import net.sf.ehcache.CacheException;
    import net.sf.ehcache.CacheManager;
    import net.sf.ehcache.Status;
    import net.sf.ehcache.event.CacheManagerEventListener;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * ehcache customer cacheManagerEventListener
     * Created by yangjinfeng on 2017/1/5.
     */
    public class CustomerCacheManagerEventListener implements CacheManagerEventListener {
    
     private Logger logger = LoggerFactory.getLogger(getClass());
    
     private final CacheManager cacheManager;
    
     public CustomerCacheManagerEventListener(CacheManager cacheManager) {
      this.cacheManager = cacheManager;
     }
    
     @Override
     public void init() throws CacheException {
      logger.info("init ehcache...");
     }
    
     @Override
     public Status getStatus() {
      return null;
     }
    
     @Override
     public void dispose() throws CacheException {
      logger.info("ehcache dispose...");
     }
    
     @Override
     public void notifyCacheAdded(String s) {
      logger.info("cacheAdded... {}", s);
      logger.info(cacheManager.getCache(s).toString());
     }
    
     @Override
     public void notifyCacheRemoved(String s) {
    
     }
    }
    
    
    CacheManagerEventListenerFactoryの簡単な実現
    
    package com.yangyi.base.ehcache;
    
    import net.sf.ehcache.CacheManager;
    import net.sf.ehcache.event.CacheManagerEventListener;
    import net.sf.ehcache.event.CacheManagerEventListenerFactory;
    
    import java.util.Properties;
    
    /**
     * Created by yangjinfeng on 2017/1/5.
     */
    public class CustomerCacheManagerEventListenerFactory extends CacheManagerEventListenerFactory {
     @Override
     public CacheManagerEventListener createCacheManagerEventListener(CacheManager cacheManager, Properties properties) {
      return new CustomerCacheManagerEventListener(cacheManager);
     }
    }
    
    
    Cacheevent Listenerの簡単な実現
    
    package com.yangyi.base.ehcache;
    
    import net.sf.ehcache.CacheException;
    import net.sf.ehcache.Ehcache;
    import net.sf.ehcache.Element;
    import net.sf.ehcache.event.CacheEventListener;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * Created by yangjinfeng on 2017/1/5.
     */
    public class CustomerCacheEventListener implements CacheEventListener {
    
     private Logger logger = LoggerFactory.getLogger(getClass());
    
     @Override
     public void notifyElementRemoved(Ehcache ehcache, Element element) throws CacheException {
      logger.info("cache removed. key = {}, value = {}", element.getObjectKey(), element.getObjectValue());
     }
    
     @Override
     public void notifyElementPut(Ehcache ehcache, Element element) throws CacheException {
      logger.info("cache put. key = {}, value = {}", element.getObjectKey(), element.getObjectValue());
     }
    
     @Override
     public void notifyElementUpdated(Ehcache ehcache, Element element) throws CacheException {
      logger.info("cache updated. key = {}, value = {}", element.getObjectKey(), element.getObjectValue());
     }
    
     @Override
     public void notifyElementExpired(Ehcache ehcache, Element element) {
      logger.info("cache expired. key = {}, value = {}", element.getObjectKey(), element.getObjectValue());
     }
    
     @Override
     public void notifyElementEvicted(Ehcache ehcache, Element element) {
      logger.info("cache evicted. key = {}, value = {}", element.getObjectKey(), element.getObjectValue());
     }
    
     @Override
     public void notifyRemoveAll(Ehcache ehcache) {
      logger.info("all elements removed. cache name = {}", ehcache.getName());
     }
    
     @Override
     public Object clone() throws CloneNotSupportedException {
      throw new CloneNotSupportedException();
     }
    
     @Override
     public void dispose() {
      logger.info("cache dispose.");
     }
    }
    
    
    CacheventListenerFactoryの簡単な実現
    
    package com.yangyi.base.ehcache;
    
    import net.sf.ehcache.event.CacheEventListener;
    import net.sf.ehcache.event.CacheEventListenerFactory;
    
    import java.util.Properties;
    
    /**
     * Created by yangjinfeng on 2017/1/5.
     */
    public class CustomerCacheEventListenerFactory extends CacheEventListenerFactory {
     @Override
     public CacheEventListener createCacheEventListener(Properties properties) {
      return new CustomerCacheEventListener();
     }
    }
    
    
    上記のイベントモニターの実装と構成を完了したら、アプリケーションを起動し、各イベントモニターから出力されたロゴを確認して、有効かどうかを確認します。
    
    2017-01-07 10:27:07.810 INFO 4264 --- [   main] com.yangyi.Application     : Starting Application on yangjinfeng-pc with PID 4264 (E:\JavaWorkSpace\spring-boot-ehcache3-hibernate5-jcache\target\classes started by yangjinfeng in E:\JavaWorkSpace\spring-boot-ehcache3-hibernate5-jcache)
    2017-01-07 10:27:07.810 INFO 4264 --- [   main] com.yangyi.Application     : No active profile set, falling back to default profiles: default
    2017-01-07 10:27:07.865 INFO 4264 --- [   main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@2ef3eef9: startup date [Sat Jan 07 10:27:07 CST 2017]; root of context hierarchy
    2017-01-07 10:27:09.155 INFO 4264 --- [   main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [class org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$6eb4eae9] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
    2017-01-07 10:27:09.191 INFO 4264 --- [   main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cache.annotation.ProxyCachingConfiguration' of type [class org.springframework.cache.annotation.ProxyCachingConfiguration$$EnhancerBySpringCGLIB$$b7c72107] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
    2017-01-07 10:27:09.206 INFO 4264 --- [   main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration' of type [class org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration$$EnhancerBySpringCGLIB$$ac3ae5ab] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
    2017-01-07 10:27:09.285 INFO 4264 --- [   main] trationDelegate$BeanPostProcessorChecker : Bean 'spring.cache-org.springframework.boot.autoconfigure.cache.CacheProperties' of type [class org.springframework.boot.autoconfigure.cache.CacheProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
    2017-01-07 10:27:09.291 INFO 4264 --- [   main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.boot.autoconfigure.cache.CacheManagerCustomizers' of type [class org.springframework.boot.autoconfigure.cache.CacheManagerCustomizers] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
    2017-01-07 10:27:09.293 INFO 4264 --- [   main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration' of type [class org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration$$EnhancerBySpringCGLIB$$46d9b2a9] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
    2017-01-07 10:27:09.418 INFO 4264 --- [   main] .y.b.e.CustomerCacheManagerEventListener : init ehcache...
    2017-01-07 10:27:09.487 INFO 4264 --- [   main] .y.b.e.CustomerCacheManagerEventListener : cacheAdded... org.hibernate.cache.spi.UpdateTimestampsCache
    2017-01-07 10:27:09.487 INFO 4264 --- [   main] .y.b.e.CustomerCacheManagerEventListener : [ name = org.hibernate.cache.spi.UpdateTimestampsCache status = STATUS_ALIVE eternal = true overflowToDisk = true maxEntriesLocalHeap = 5000 maxEntriesLocalDisk = 0 memoryStoreEvictionPolicy = LRU timeToLiveSeconds = 0 timeToIdleSeconds = 0 persistence = LOCALTEMPSWAP diskExpiryThreadIntervalSeconds = 120 cacheEventListeners: com.yangyi.base.ehcache.CustomerCacheEventListener ; orderedCacheEventListeners: maxBytesLocalHeap = 0 overflowToOffHeap = false maxBytesLocalOffHeap = 0 maxBytesLocalDisk = 0 pinned = false ]
    2017-01-07 10:27:09.487 INFO 4264 --- [   main] .y.b.e.CustomerCacheManagerEventListener : cacheAdded... org.hibernate.cache.internal.StandardQueryCache
    2017-01-07 10:27:09.487 INFO 4264 --- [   main] .y.b.e.CustomerCacheManagerEventListener : [ name = org.hibernate.cache.internal.StandardQueryCache status = STATUS_ALIVE eternal = false overflowToDisk = true maxEntriesLocalHeap = 5 maxEntriesLocalDisk = 0 memoryStoreEvictionPolicy = LRU timeToLiveSeconds = 120 timeToIdleSeconds = 0 persistence = LOCALTEMPSWAP diskExpiryThreadIntervalSeconds = 120 cacheEventListeners: com.yangyi.base.ehcache.CustomerCacheEventListener ; orderedCacheEventListeners: maxBytesLocalHeap = 0 overflowToOffHeap = false maxBytesLocalOffHeap = 0 maxBytesLocalDisk = 0 pinned = false ]
    2017-01-07 10:27:09.503 INFO 4264 --- [   main] .y.b.e.CustomerCacheManagerEventListener : cacheAdded... entityCache
    2017-01-07 10:27:09.503 INFO 4264 --- [   main] .y.b.e.CustomerCacheManagerEventListener : [ name = entityCache status = STATUS_ALIVE eternal = false overflowToDisk = true maxEntriesLocalHeap = 1000 maxEntriesLocalDisk = 10000 memoryStoreEvictionPolicy = LFU timeToLiveSeconds = 20 timeToIdleSeconds = 10 persistence = LOCALTEMPSWAP diskExpiryThreadIntervalSeconds = 120 cacheEventListeners: com.yangyi.base.ehcache.CustomerCacheEventListener ; orderedCacheEventListeners: maxBytesLocalHeap = 0 overflowToOffHeap = false maxBytesLocalOffHeap = 0 maxBytesLocalDisk = 0 pinned = false ]
    2017-01-07 10:27:09.503 INFO 4264 --- [   main] trationDelegate$BeanPostProcessorChecker : Bean 'ehCacheCacheManager' of type [class net.sf.ehcache.CacheManager] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
    2017-01-07 10:27:09.503 INFO 4264 --- [   main] trationDelegate$BeanPostProcessorChecker : Bean 'cacheManager' of type [class org.springframework.cache.ehcache.EhCacheCacheManager] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
    2017-01-07 10:27:09.503 INFO 4264 --- [   main] trationDelegate$BeanPostProcessorChecker : Bean 'cacheAutoConfigurationValidator' of type [class org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration$CacheManagerValidator] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
    2017-01-07 10:27:09.829 INFO 4264 --- [   main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
    2017-01-07 10:27:09.839 INFO 4264 --- [   main] o.apache.catalina.core.StandardService : Starting service Tomcat
    2017-01-07 10:27:09.839 INFO 4264 --- [   main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.6
    2017-01-07 10:27:09.924 INFO 4264 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]  : Initializing Spring embedded WebApplicationContext
    2017-01-07 10:27:09.924 INFO 4264 --- [ost-startStop-1] o.s.web.context.ContextLoader   : Root WebApplicationContext: initialization completed in 2061 ms
    
    2017-01-07 10:32:41.876 INFO 4264 --- [nio-8080-exec-1] c.y.b.e.CustomerCacheEventListener  : cache put. key = com.yangyi.entity.User#1, value = org.hibernate.cache.ehcache.internal.strategy.AbstractReadWriteEhcacheAccessStrategy$Item@1c13194d
    2017-01-07 10:32:41.877 INFO 4264 --- [nio-8080-exec-1] c.y.b.e.CustomerCacheEventListener  : cache put. key = com.yangyi.entity.Authority#1, value = org.hibernate.cache.ehcache.internal.strategy.AbstractReadWriteEhcacheAccessStrategy$Item@2accc177
    2017-01-07 10:32:41.878 INFO 4264 --- [nio-8080-exec-1] c.y.b.e.CustomerCacheEventListener  : cache put. key = com.yangyi.entity.Authority#2, value = org.hibernate.cache.ehcache.internal.strategy.AbstractReadWriteEhcacheAccessStrategy$Item@2b3b9c7e
    2017-01-07 10:32:41.879 INFO 4264 --- [nio-8080-exec-1] c.y.b.e.CustomerCacheEventListener  : cache put. key = com.yangyi.entity.Authority#3, value = org.hibernate.cache.ehcache.internal.strategy.AbstractReadWriteEhcacheAccessStrategy$Item@4c31e58c
    
    
    注釈方式は二級キャッシュを使用します。
    entity cacheを使うには、entityに対応する注釈を付ける必要があります。javax.persistence.acheable注釈は、当該entityが2級キャッシュを使用し、org.hibernate.annotations.ache注釈はキャッシュポリシーを指定し、どのキャッシュエリアに格納するかを指定します。
    キャッシュポリシーに関する詳細情報はヒベルナ5.0公式文書を参照することができる。
    
    package com.yangyi.entity;
    
    import org.hibernate.annotations.Cache;
    import org.hibernate.annotations.CacheConcurrencyStrategy;
    import javax.persistence.Cacheable;
    import javax.persistence.Entity;
    import javax.persistence.JoinTable;
    
    @Entity
    @Table(name = "users")
    @Cacheable
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "entityCache")
    public class User implements Serializable {
    
    }
    
    
    最後に、私達はspring boot応用面でcache機能を開けて、org.springframe ebook.cache.annotations.EnballCaching注釈を使う必要があります。
    
    package com.yangyi;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cache.annotation.EnableCaching;
    
    @SpringBootApplication
    @EnableCaching
    public class Application {
    
     public static void main(String[] args) {
      SpringApplication.run(Application.class, args);
     }
    }
    
    
    完全コード
    完全コードの例はgithubを参照してください。
    以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。