详解spring boot集成ehcache 2.x 用于hibernate二级缓存
本文将介绍如何在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>
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
关于hibernate缓存相关的所有配置可参考hibernate5.0官方文档#缓存
ehcache配置文件
ehcache 2.x配置文件样板参考官方网站提供。本例中使用的配置文件如下所示
<?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简单实现
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); } }
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."); } }
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(); } }
完成上述事件监听器的实现和配置后,我们可以启动应用,查看下相应事件监听器中输出的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.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官方文档#缓存
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注解
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); } }
完整代码
完整代码示例见
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。