本文将介绍如何在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
项目依赖
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
|
< 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的二级缓存使用。缓存数据可选择如下三种存储方案
- 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的集成。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# 打开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缓存相关的所有配置可参考hibernate5.0官方文档#缓存
ehcache配置文件
ehcache 2.x配置文件样板参考官方网站提供的ehcache.xml。本例中使用的配置文件如下所示
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
|
<? 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中,有两大类事件,一是cacheManager相关的事件,如cache的init/added等;二是cahche相关的事件,如cache put/expire等。在ehcache中,默认没有这两类事件的监听器,需要自主实现监听器以及监听器工厂类,然后配置到ehcache.xml中,方可生效。
上述ehcache.xml配置中,给自定义cache都配置了cacheEventListenerFactory,用于监听缓存事件。同时也配置了cacheManager Factory实现类。具体实现代码如下
CacheManagerEventListener简单实现
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
|
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的简单实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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); } } |
CacheEventListener的简单实现
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
|
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." ); } } |
CacheEventListenerFactory的简单实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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(); } } |
完成上述事件监听器的实现和配置后,我们可以启动应用,查看下相应事件监听器中输出的log,以验证是否生效
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
|
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.Cacheable注解标记该entity使用二级缓存,org.hibernate.annotations.Cache注解指定缓存策略,以及存放到哪个缓存区域。
有关缓存策略详细信息可参考hibernate5.0官方文档#缓存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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.springframework.cache.annotation.EnableCaching注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://blog.csdn.net/yiduyangyi/article/details/54176453