在Spring上集成使用ehcache缓存框架以及实现集群缓存同步

来源:互联网 发布:linux 查看内存使用 编辑:程序博客网 时间:2024/06/10 21:49

周一第一天实习,老大给了个任务给我,让我看看j2cache两级缓存框架,然后我在开源中国了解到,开源中国目前就用到这个缓存框架,主要是为了减少redis的负荷,这个两级缓存框架使用了ehcache作为一级L1缓存,使用redis作为二级L2缓存,了解到这个之后,我果断学习了一波ehcache在spring的使用。

一、依赖jar包

这里使用maven:

<properties>    <spring.version>4.3.5.RELEASE</spring.version>    <ehcache.version>2.8.0</ehcache.version></properties><dependency>    <groupId>net.sf.ehcache</groupId>    <artifactId>ehcache</artifactId>     <version>${ehcache.version}</version></dependency><dependency>    <groupId>org.springframework</groupId>    <artifactId>spring-context-support</artifactId>    <version>${spring.version}</version></dependency>

二、spring配置EhCacheCacheManager和EhCacheManagerFactoryBean托管

<!-- 使用cache注解 --><cache:annotation-driven cache-manager="cacheManager"/><bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">    <property name="cacheManager" ref="cacheManagerFactory"/></bean><bean name="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">    <property name="configLocation" value="classpath:ehcache.xml"/>    <!--<property name="shared" value="true"/>--></bean>

上面的这个配置是使用到cache的注解功能,后面我会用例子解析

<cache:annotation-driven cache-manager="cacheManager"/>

三、配置ehcache.xml

该配置文件是ehcache使用的一些配置

<?xml version="1.0" encoding="utf-8" ?><ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">    <diskStore path="java.io.tmpdir"/>    <cache name="testCache" eternal="false" maxElementsInMemory="10" maxElementsOnDisk="20"           overflowToDisk="true" timeToIdleSeconds="5" timeToLiveSeconds="240"/></ehcache>

diskStore:配置一个diskStore的保存路径用于保存数据到磁盘
cache:配置一个cache,这个东西有点像是一个数据仓库
eternal:true代表cache的数据会一直有效,而false则相反
maxElementsInMemory:配置内存中最大保存对象个数
maxElementsOnDisk:配置磁盘中最大保存对象个数
overflowToDisk:true代表当内存不能存下更多数据时将会保存到磁盘
timeToIdleSeconds:配置cache保存的key-value多长时间不使用后将会被清楚(单位:秒)
timeToLiveSeconds:配置cache保存的key-value能保存多久(单位:秒)

好了,一个最简的使用就此完成,让我们试试效果。

四、测试1

1、非注解方式使用

Cache cache = cacheManager.getCache("testCache");Element e = new Element("key","value");cache.put(e);Element e1 = cache.get("key");System.out.println(e1.getObjectValue());Thread.sleep(6000);Element e2 = null;e2 = cache.get("key");if (e2 == null){    System.out.println("null");}else {    System.out.println(e2.getObjectValue());}

最后输出结果为:value

2、使用注解方式

/*第一次执行会执行方法内逻辑,第二次执行不会再执行方法内逻辑,而是直接从缓存中读取,直至ttl*/@Servicepublic class EhcacheTestService {    @Cacheable(value = "testCache")//value指定使用哪个cache    public String getTime(){        long time = System.currentTimeMillis();        return String.valueOf(time);    }    @Cacheable(value = "testCache",key = "#id")//value指定使用哪个cache,key指定该缓存对象的key为id的值    public String getTime2(Integer id){        long time = System.currentTimeMillis();        System.out.println("exec");        return String.valueOf(time);    }    @Cacheable(value = "testCache",key = "#p[0]")//value指定使用哪个cache,key指定该缓存对象的key为索引为0的参数的值    public String getTime2(Integer id){        long time = System.currentTimeMillis();        System.out.println("exec");        return String.valueOf(time);    }    //若传入为对象,要使用对象的某个成员变量的值则为,例#u.id    @CacheEvict(value = "testCache",key = "#id")//删除缓存中key与id的值相同的对象    public void delTime(Integer id){    }    @CacheEvict(value = "testCache",allEntries = true)//删除所有该cache的缓存    public void delAllTime(){        System.out.println("del all");    }}

五、使用RMI方式集群(ehcache.xml配置,同一内网)

服务器1(ip:10.104.76.198,port:4001)

<?xml version="1.0" encoding="utf-8" ?><ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">    <diskStore path="java.io.tmpdir"/>    <!--<cacheManagerPeerProviderFactory-->            <!--class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"-->            <!--properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1,-->        <!--multicastGroupPort=4446, timeToLive=32"/>-->    <cacheManagerPeerProviderFactory            class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"            properties="peerDiscovery=manual,            rmiUrls=//10.104.76.199:40002/testCache"/>    <cacheManagerPeerListenerFactory            class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"            properties="hostName=10.104.76.198, port=40001,        socketTimeoutMillis=2000"/>    <cache name="testCache" eternal="false" maxElementsInMemory="1000" maxElementsOnDisk="10000"           overflowToDisk="true" timeToLiveSeconds="3600" diskPersistent="true" >        <cacheEventListenerFactory                class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>    </cache></ehcache>

服务器2(ip:10.104.76.199,port:4002)

<?xml version="1.0" encoding="utf-8" ?><ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">    <diskStore path="java.io.tmpdir"/>    <!--<cacheManagerPeerProviderFactory-->            <!--class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"-->            <!--properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1,-->        <!--multicastGroupPort=4446, timeToLive=32"/>-->    <cacheManagerPeerProviderFactory            class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"            properties="peerDiscovery=manual,            rmiUrls=//10.104.76.198:40001/testCache"/>    <cacheManagerPeerListenerFactory            class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"            properties="hostName=10.104.76.199, port=40002,        socketTimeoutMillis=2000"/>    <cache name="testCache" eternal="false" maxElementsInMemory="1000" maxElementsOnDisk="10000"           overflowToDisk="true" timeToLiveSeconds="3600" diskPersistent="true" >        <cacheEventListenerFactory                class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>    </cache></ehcache>

replicatePuts=true | false – 当一个新元素增加到缓存中的时候是否要复制到其他的peers. 默认是true。
replicateUpdates=true | false – 当一个已经在缓存中存在的元素被覆盖时是否要进行复制。默认是true。
replicateRemovals= true | false – 当元素移除的时候是否进行复制。默认是true。
replicateAsynchronously=true | false – 复制方式是异步的(指定为true时)还是同步的(指定为false时)。默认是true。
replicatePutsViaCopy=true | false – 当一个新增元素被拷贝到其他的cache中时是否进行复制指定为true时为复制,默认是true。
replicateUpdatesViaCopy=true | false – 当一个元素被拷贝到其他的cache中时是否进行复制(指定为true时为复制),默认是true。

六、使用jgroups方式集群(同一内网)

1、增加jgroups依赖

<dependency>  <groupId>net.sf.ehcache</groupId>  <artifactId>ehcache-jgroupsreplication</artifactId>  <version>1.7</version></dependency>

2、ehcache.xml配置
服务器1(ip:10.104.76.198,port:4001)

<?xml version="1.0" encoding="utf-8" ?><ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">    <diskStore path="java.io.tmpdir"/>    <cacheManagerPeerProviderFactory            class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"            properties="connect=TCP(bind_addr=10.104.76.198;bind_port=4001):            TCPPING(initial_hosts=10.104.76.198[4001],10.104.76.199[4002];            port_range=10;timeout=5000;num_initial_members=2):MERGE2(min_interval=3000;max_interval=5000):            FD_ALL(interval=5000;timeout=20000):FD(timeout=5000;max_tries=48;):VERIFY_SUSPECT(timeout=1500):            pbcast.NAKACK(retransmit_timeout=100,200,300,600,1200,2400,4800;discard_delivered_msgs=true):            pbcast.STABLE(stability_delay=1000;desired_avg_gossip=20000;max_bytes=0):pbcast.GMS(print_local_addr=true;join_timeout=5000)"            propertySeparator="::"/>    <cache name="testCache" eternal="false" maxElementsInMemory="1000" maxElementsOnDisk="10000"           overflowToDisk="true" timeToLiveSeconds="3600" diskPersistent="true" >        <cacheEventListenerFactory                class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"                properties="replicateAsynchronously=true, replicatePuts=true,                replicateUpdates=true, replicateUpdatesViaCopy=true, replicateRemovals=true"/>    </cache></ehcache>

服务器2(ip:10.104.76.199,port:4002)

<?xml version="1.0" encoding="utf-8" ?><ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">    <diskStore path="java.io.tmpdir"/>    <cacheManagerPeerProviderFactory            class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"            properties="connect=TCP(bind_addr=10.104.76.199;bind_port=4002):            TCPPING(initial_hosts=10.104.76.198[4001],10.104.76.199[4002];            port_range=10;timeout=5000;num_initial_members=2):MERGE2(min_interval=3000;max_interval=5000):            FD_ALL(interval=5000;timeout=20000):FD(timeout=5000;max_tries=48;):VERIFY_SUSPECT(timeout=1500):            pbcast.NAKACK(retransmit_timeout=100,200,300,600,1200,2400,4800;discard_delivered_msgs=true):            pbcast.STABLE(stability_delay=1000;desired_avg_gossip=20000;max_bytes=0):pbcast.GMS(print_local_addr=true;join_timeout=5000)"            propertySeparator="::"/>    <cache name="testCache" eternal="false" maxElementsInMemory="1000" maxElementsOnDisk="10000"           overflowToDisk="true" timeToLiveSeconds="3600" diskPersistent="true" >        <cacheEventListenerFactory                class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"                properties="replicateAsynchronously=true, replicatePuts=true,                replicateUpdates=true, replicateUpdatesViaCopy=true, replicateRemovals=true"/>    </cache></ehcache>

好了,最重要的配置都讲完了,只要你写个单元测试就能看到明显的结果了!!!