1. 程式人生 > >spring boot整合ehcache 2.x 用於hibernate二級快取

spring boot整合ehcache 2.x 用於hibernate二級快取

spring boot整合ehcache 2x 用於hibernate二級快取
專案依賴
Ehcache簡介
hibernate二級快取配置
ehcache配置檔案
ehcache事件監聽
註解方式使用二級快取
完整程式碼
本文將介紹如何在spring boot中整合ehcache作為hibernate的二級快取。各個框架版本如下

spring boot:1.4.3.RELEASE
spring framework: 4.3.5.RELEASE
hibernate:5.0.1.Final(spring-boot-starter-data-jpa預設依賴)
ehcache:2.10.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>   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Ehcache簡介
ehcache是一個純java的快取框架,既可以當做一個通用快取使用,也可以作為將其作為hibernate的二級快取使用。快取資料可選擇如下三種儲存方案

MemoryStore – On-heap memory used to hold cache elements. This tier is subject to Java garbage collection.

OffHeapStore – 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 products.

DiskStore – Backs up in-memory cache elements and provides overflow capacity to the other tiers.

hibernate二級快取配置
hibernate的二級快取支援entity和query層面的快取,org.hibernate.cache.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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
關於hibernate快取相關的所有配置可參考hibernate5.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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
ehcache事件監聽
在ehcache中,有兩大類事件,一是cacheManager相關的事件,如cache的init/added等;二是cahche相關的事件,如cache put/expire等。在ehcache中,預設沒有這兩類事件的監聽器,需要自主實現監聽器以及監聽器工廠類,然後配置到ehcache.xml中,方可生效。 
上述ehcache.xml配置中,給自定義cache都配置了cacheEventListenerFactory,用於監聽快取事件。同時也配置了cacheManager Factory實現類。具體實現程式碼如下

CacheManagerEventListener簡單實現

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) {

    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CacheEventListener的簡單實現

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.");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
CacheEventListenerFactory的簡單實現

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();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
完成上述事件監聽器的實現和配置後,我們可以啟動應用,檢視下相應事件監聽器中輸出的log,以驗證是否生效

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[email protected]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.ehcach[email protected]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.ehcach[email protected]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.ehcach[email protected]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.ehcach[email protected]4c31e58c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
註解方式使用二級快取
要使用entity cache,需要在entity上配上相應的註解方可生效。javax.persistence.Cacheable註解標記該entity使用二級快取,org.hibernate.annotations.Cache註解指定快取策略,以及存放到哪個快取區域。 
有關快取策略詳細資訊可參考hibernate5.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 {

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
最後,我們需要在spring boot應用層面開啟cache功能,使用org.springframework.cache.annotation.EnableCaching註解

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);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
完整程式碼
完整程式碼示例見github spring-boot-ehcache2.x-hibernate-second-level-cache
--------------------- 
作者:yiduyangyi 
來源:CSDN 
原文:https://blog.csdn.net/yiduyangyi/article/details/54176453 
版權宣告:本文為博主原創文章,轉載請附上博文連結!