依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.1.6.RELEASE</version> </dependency> <!-- org.springframework.cache.ehcache.EhCacheCacheManager --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.1.6.RELEASE</version> </dependency> <!-- ehcache --> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache-core</artifactId> <version>2.6.11</version> </dependency> <!-- 缓存集群同步(jgroups) --> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache-jgroupsreplication</artifactId> <version>1.7</version> </dependency> <!-- test --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.1.6.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>
项目结构
│ pom.xml │ ├─src │ ├─main │ │ ├─java │ │ │ └─cn │ │ │ └─zno │ │ │ Person.java │ │ │ PersonService.java │ │ │ PersonServiceImpl.java │ │ │ │ │ └─resources │ │ applicationContext-Ehcache.xml │ │ ehcache.xml │ │ │ └─test │ ├─java │ │ └─ehcache │ │ TestEhcache.java │ │ │ └─resources
applicationContext-Ehcache.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"> <context:annotation-config /> <context:component-scan base-package="cn.zno" /> <!-- 启用缓存注解功能,这个是必须的,否则注解不会生效,另外,该注解一定要声明在spring主配置文件中才会生效 --> <cache:annotation-driven cache-manager="cacheManager" /> <!-- 声明cacheManager --> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="cacheManagerFactory" /> <!-- cacheManager工厂类,指定ehcache.xml的位置 --> <bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="classpath:ehcache.xml" p:shared="true" scope="singleton" /> </beans>
ehcache.xml (详细解释请看jgroups)
<?xml version="1.0" encoding="UTF-8"?> <ehcache updateCheck="false" dynamicConfig="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"> <diskStore path="java.io.tmpdir" /> <!-- UDP( mcast_addr:Multicast address to be used for discovery mcast_port:Multicast port for discovery packets. Default is 7555 bind_port:Port for discovery packets ip_ttl:The time-to-live (TTL) for multicast datagram packets. Default is 8 mcast_send_buf_size:Send buffer size of the multicast datagram socket. Default is 100'000 bytes mcast_recv_buf_size:Receive buffer size of the multicast datagram socket. Default is 500'000 bytes ) PING( timeout: num_initial_members:Minimum number of initial members to get a response from ) MERGE2( min_interval:Minimum time in ms between runs to discover other clusters max_interval:Maximum time in ms between runs to discover other clusters ) FD_SOCK( ) VERIFY_SUSPECT( timeout: ) pbcast.NAKACK( retransmit_timeout: ) UNICAST( ) pbcast.STABLE( desired_avg_gossip: ) FRAG( ) pbcast.GMS( join_timeout: print_local_addr: ) --> <cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory" properties="channel=ehcache^connect=UDP(mcast_addr=231.12.21.132;mcast_port=45566;bind_port=33433;ip_ttl=32; mcast_send_buf_size=150000;mcast_recv_buf_size=80000): PING(timeout=2000;num_initial_members=6): MERGE2(min_interval=5000;max_interval=10000): FD_SOCK:VERIFY_SUSPECT(timeout=1500): pbcast.NAKACK(retransmit_timeout=3000): UNICAST: pbcast.STABLE(desired_avg_gossip=20000): FRAG: pbcast.GMS(join_timeout=5000;print_local_addr=true)" propertySeparator="^" /> <!-- <defaultCache> 是名为"default" 的<cache> maxElementsInMemory:内存中最大元素个数。如果开启 overflowToDisk 则超出部分转移到磁盘;如未开启则会按照 memoryStoreEvictionPolicy 回收。 eternal:是否永驻内存 overflowToDisk:超出后转到磁盘。文件名为<cache> 的name 加后缀.data 例如:default.data diskPersistent:在虚拟机重启时是否进行磁盘存储 timeToIdleSeconds:两次访问该元素的最大时间间隔,超出后失效 timeToLiveSeconds:创建后生存时间 maxElementsOnDisk:磁盘中最大元素个数 diskExpiryThreadIntervalSeconds:磁盘缓存的清理线程运行间隔 memoryStoreEvictionPolicy:内存回收策略 --> <defaultCache maxElementsInMemory="1000000" eternal="false" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="120" timeToLiveSeconds="300" maxElementsOnDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> <!-- 同步缓存 --> <cacheEventListenerFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory" /> </defaultCache> <cache name="personCache" maxElementsInMemory="1000000" eternal="false" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="120" timeToLiveSeconds="300" maxElementsOnDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> <cacheEventListenerFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory" /> </cache> </ehcache>
bean 及 服务类:
package cn.zno; public class Person { private int age; private Car car; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Person [age=" + age + ", car=" + car + "]"; } } class Car { private String brand; public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } @Override public String toString() { return "Car [brand=" + brand + "]"; } }
PersonService.java
package cn.zno; public interface PersonService { public Person getPerson(); public void cleanPersonCache(); }
PersonServiceImpl.java
package cn.zno; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; @Service public class PersonServiceImpl implements PersonService { @Cacheable(value = "personCache", key = "123456") public Person getPerson(){ try { Thread.sleep(10000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } Person person = new Person(); Car car = new Car(); car.setBrand("benz"); person.setAge(11); person.setCar(car); return person; } @CacheEvict(value = "personCache", key = "123456") public void cleanPersonCache() { System.out.println("clean personCache[123456]"); } }
测试类:
package ehcache; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import cn.zno.PersonService; @ContextConfiguration(locations = { "classpath:applicationContext-Ehcache.xml" }) @RunWith(SpringJUnit4ClassRunner.class) public class TestEhcache { @Autowired private CacheManager cacheManager; @Autowired private PersonService personService; @Test public void show() { // 未缓存时耗时 long t1 = System.currentTimeMillis(); System.out.println(personService.getPerson().toString()); long t2 = System.currentTimeMillis(); System.out.println("耗时:" + (t2 - t1)); // 缓存后耗时 long t3 = System.currentTimeMillis(); System.out.println(personService.getPerson().toString()); long t4 = System.currentTimeMillis(); System.out.println("耗时:" + (t4 - t3)); // 清除缓存后耗时 long t5 = System.currentTimeMillis(); personService.cleanPersonCache(); System.out.println(personService.getPerson().toString()); long t6 = System.currentTimeMillis(); System.out.println("耗时:" + (t6 - t5)); // 再次获取 long t7 = System.currentTimeMillis(); System.out.println(personService.getPerson().toString()); long t8 = System.currentTimeMillis(); System.out.println("耗时:" + (t8 - t7)); } @Test public void create(){ cacheManager.addCache("testCache"); Cache cache = cacheManager.getCache("testCache"); cache.put(new Element("name", "xiaoming")); System.out.println(cache.get("name")); } }
show()运行结果:
十月 07, 2015 11:03:22 上午 org.springframework.test.context.support.DefaultTestContextBootstrapper getDefaultTestExecutionListenerClassNames 信息: Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener] 十月 07, 2015 11:03:22 上午 org.springframework.test.context.support.DefaultTestContextBootstrapper instantiateListeners 信息: Could not instantiate TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [javax/servlet/ServletContext] 十月 07, 2015 11:03:22 上午 org.springframework.test.context.support.DefaultTestContextBootstrapper instantiateListeners 信息: Could not instantiate TestExecutionListener [org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/interceptor/TransactionAttribute] 十月 07, 2015 11:03:22 上午 org.springframework.test.context.support.DefaultTestContextBootstrapper instantiateListeners 信息: Could not instantiate TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/TransactionDefinition] 十月 07, 2015 11:03:22 上午 org.springframework.test.context.support.DefaultTestContextBootstrapper getTestExecutionListeners 信息: Using TestExecutionListeners: [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@15a191e, org.springframework.test.context.support.DirtiesContextTestExecutionListener@270664] 十月 07, 2015 11:03:22 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [applicationContext-Ehcache.xml] 十月 07, 2015 11:03:22 上午 org.springframework.context.support.GenericApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.GenericApplicationContext@129df79: startup date [Wed Oct 07 11:03:22 CST 2015]; root of context hierarchy 十月 07, 2015 11:03:23 上午 org.springframework.cache.ehcache.EhCacheManagerFactoryBean afterPropertiesSet 信息: Initializing EhCache CacheManager SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. ------------------------------------------------------------------- GMS: address=pc012-16440, cluster=EH_CACHE, physical address=172.16.162.238:13451 ------------------------------------------------------------------- Person [age=11, car=Car [brand=benz]] 耗时:10031 Person [age=11, car=Car [brand=benz]] 耗时:0 clean personCache[123456] Person [age=11, car=Car [brand=benz]] 耗时:10000 Person [age=11, car=Car [brand=benz]] 耗时:0
create()运行结果:
------------------------------------------------------------------- GMS: address=pc012-40063, cluster=EH_CACHE, physical address=172.16.162.238:13550 ------------------------------------------------------------------- [ key = name, value=xiaoming, version=1, hitCount=1, CreationTime = 1444187930777, LastAccessTime = 1444187930777 ]
小结:
@Cacheable 的value是缓存名,key是在缓存中提取被缓存内容的key
<defaultCache 的作用是模板,不能通过default取出该缓存
<cache 可以配置到ehcache.xml 配置文件中,也可以在代码中手动添加(以<defaultCache 为模板)
mcast_addr 是组播地址,详细请查看jgroups
项目地址:git@github.com:witaste/ehcache.git