Spring缓存机制实例代码
spring的缓存机制非常灵活,可以对容器中任意bean或者bean的方法进行缓存,因此这种缓存机制可以在javaee应用的任何层次上进行缓存。
spring缓存底层也是需要借助其他缓存工具来实现,例如ehcache(hibernate缓存工具),上层则以统一api编程。
要使用spring缓存,需要以下三步
- 1.向spring配置文件导入context:命名空间
- 2.在spring配置文件启用缓存,具体是添加 <cache:annotation-driven cache-manager="缓存管理器id" />
- 3.配置缓存管理器,不同的缓存实现配置不同,如果是ehcache,需要先配置一个ehcache.xml
例如
<?xml version="1.0" encoding="utf-8"?> <ehcache> <diskstore path="java.io.tmpdir" /> <!-- 配置默认的缓存区 --> <defaultcache maxelementsinmemory="10000" eternal="false" timetoidleseconds="120" timetoliveseconds="120" maxelementsondisk="10000000" diskexpirythreadintervalseconds="120" memorystoreevictionpolicy="lru"/> <!-- 配置名为users的缓存区 --> <cache name="users" maxelementsinmemory="10000" eternal="false" overflowtodisk="true" timetoidleseconds="300" timetoliveseconds="600" /> </ehcache>
上面的ehcache.xml
配置了两个缓存区,spring中的bean将会缓存在这些缓存区中,一般的,spring容器中有多少个bean,就会在ehcache中定义多少个缓存区。
接着在spring配置文件中配置缓存管理器如下,其中第一个bean是一个工厂bean,用来配置ehcache的cachemanager, 第二个bean才是为spring缓存配置的缓存管理器,所以将第一个bean注入第二个bean。
<cache:annotation-driven cache-manager="cachemanager" /> <!-- 配置ehcache的cachemanager 通过configlocation指定ehcache.xml文件的位置 --> <bean id="ehcachemanager" class="org.springframework.cache.ehcache.ehcachemanagerfactorybean" p:configlocation="classpath:ehcache.xml" p:shared="false" /> <!-- 配置基于ehcache的缓存管理器 并将ehcache的cachemanager注入该缓存管理器bean --> <bean id="cachemanager" class="org.springframework.cache.ehcache.ehcachecachemanager" p:cachemanager-ref="ehcachemanager" > </bean>
下面是一个完整的spring配置,
<?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:p="http://www.springframework.org/schema/p" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:context="http://www.springframework.org/schema/context" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:component-scan base-package="com.service"/> <cache:annotation-driven cache-manager="cachemanager" /> <!-- 配置ehcache的cachemanager 通过configlocation指定ehcache.xml文件的位置 --> <bean id="ehcachemanager" class="org.springframework.cache.ehcache.ehcachemanagerfactorybean" p:configlocation="classpath:ehcache.xml" p:shared="false" /> <!-- 配置基于ehcache的缓存管理器 并将ehcache的cachemanager注入该缓存管理器bean --> <bean id="cachemanager" class="org.springframework.cache.ehcache.ehcachecachemanager" p:cachemanager-ref="ehcachemanager" > </bean> </beans>
下面将以@cacheable
为例,演示spring基于ehcache缓存的用法。 cacheable
用于修饰类或者方法,如果修饰类,则类中所有方法都会被缓存。
类级别的缓存
例如有如下bean类,
@service("userservice") @cacheable(value="users") public class userserviceimpl implements userservice { @override public user getusersbynameandage(string name, int age) { system.out.println("正在执行getusersbynameandage().."); return new user(name,age); } @override public user getanotheruser(string name, int age) { system.out.println("正在执行getanotheruser().."); return new user(name,age); } }
基于类的缓存,将会缓存类中的所有方法,缓存之后,程序调用该类实例的任何方法,只要传入的参数相同,spring将不会真正执行该方法,而是直接根据传入的参数去查找缓存中的数据!
比如像下面这样使用缓存数据,
public static void test2() { applicationcontext ctx = new classpathxmlapplicationcontext("beans.xml"); userservice us = ctx.getbean("userservice", userservice.class); user u1 = us.getusersbynameandage("张三", 50); //由于第二次调用userservice方法时,使用了相同参数,那么真正的方法将不会执行, //spring将直接从缓存按参数查找数据 user u2 = us.getanotheruser("张三", 50); system.out.println(u1==u2); }
输出结果,
正在执行getusersbynameandage()..
true
可以看到,上面的getanotheruser()并没有真正执行,因为传入的参数与之前的方法传入的参数相同,于是spring直接从缓存区数据了。
上面的bean类中的注解@cacheable
除了必选属性value之外,还有key, condition,, unless属性,后面三个都是用来设置spring存储策略,对于基于类的缓存来说,spring默认以方法传入的参数作为key去缓存中查找结果。
当然我们也可以修改key的策略,让spring按照其他标准,比如按照第一个参数是否相同来作为key,在缓存中查找结果。
将上面的bean类修改如下,
@service("userservice") @cacheable(value="users", key="#name") public class userserviceimpl implements userservice { @override public user getusersbynameandage(string name, int age) {
意味着我们传入相同的name,spring就不会真正执行方法。只有name不同的时候,方法才会真正执行,例如下面,
public static void test2() { applicationcontext ctx = new classpathxmlapplicationcontext("beans.xml"); userservice us = ctx.getbean("userservice", userservice.class); user u1 = us.getusersbynameandage("张三", 50); //将@cacheable的key参数改为key="#name"之后,下面的方法将可以执行。 user u2 = us.getanotheruser("李四", 50); system.out.println(u1==u2); }
可以看到这回getanotheruser()
方法得到执行了,
1 正在执行getusersbynameandage()..
2 正在执行getanotheruser()..
3 false
我们也可以设置condition属性,例如,
@service("userservice") @cacheable(value="users", condition="#age<100") public class userserviceimpl implements userservice { @override public user getusersbynameandage(string name, int age) {
那么对于下面的代码来说,两个方法都不会被缓存,spring每次都是执行真正的方法取结果,
public static void test2() { applicationcontext ctx = new classpathxmlapplicationcontext("beans.xml"); userservice us = ctx.getbean("userservice", userservice.class); user u1 = us.getusersbynameandage("张三", 500); user u2 = us.getanotheruser("李四", 500); system.out.println(u1==u2); }
执行结果,
正在执行getusersbynameandage()..
正在执行getanotheruser()..
false
方法级别的缓存
方法级别的缓存则只会对方法起作用了,不同的方法可以设置不用的缓存区,例如下面这样,
@service("userservice") public class userserviceimpl implements userservice { @cacheable("users1") @override public user getusersbynameandage(string name, int age) { system.out.println("正在执行getusersbynameandage().."); return new user(name,age); } @cacheable("users2") @override public user getanotheruser(string name, int age) { system.out.println("正在执行getanotheruser().."); return new user(name,age); } }
使用下面的测试代码,
public static void test2() { applicationcontext ctx = new classpathxmlapplicationcontext("beans.xml"); userservice us = ctx.getbean("userservice", userservice.class); //第一次执行方法,方法将会真正执行并缓存 user u1 = us.getusersbynameandage("张三", 500); //虽然下面方法传入相同参数,但是因为这两个方法在不同的缓存区,所以无法使用缓存数据 user u2 = us.getanotheruser("张三", 500); system.out.println(u1==u2); //上面已经缓存过,这里不会真正执行,直接使用缓存 user u3 = us.getanotheruser("张三", 500); system.out.println(u3==u2); }
执行结果,
正在执行getusersbynameandage()..
正在执行getanotheruser()..
false
true
使用@cacheevict清除缓存
被@cacheevict修饰的方法可以用来清除缓存,使用@cacheevict
可以指定如下属性。
allentries, 是否清空整个缓存区
beforeinvocation: 是否在执行方法之前清除缓存。默认是方法执行成功之后才清除。
condiition以及key, 与@cacheable
中一样的含义。
下面示范简单用啊,
@service("userservice") @cacheable("users") public class userserviceimpl implements userservice { @override public user getusersbynameandage(string name, int age) { system.out.println("正在执行getusersbynameandage().."); return new user(name,age); } @override public user getanotheruser(string name, int age) { system.out.println("正在执行getanotheruser().."); return new user(name,age); } //指定根据name,age参数清楚缓存 @cacheevict(value="users") public void evictuser(string name, int age) { system.out.println("--正在清空"+name+","+age+"对应的缓存--"); } //指定清除user缓存区所有缓存的数据 @cacheevict(value="users", allentries=true) public void evictall() { system.out.println("--正在清空整个缓存--"); } }
下面是测试类,
public static void test2() { applicationcontext ctx = new classpathxmlapplicationcontext("beans.xml"); userservice us = ctx.getbean("userservice", userservice.class); //系统会缓存两个方法 user u1 = us.getusersbynameandage("张三", 500); user u2 = us.getanotheruser("李四",400); //调用evictuser()方法清除缓冲区指定的数据 us.evictuser("李四", 400); //前面清除了 李四, 400 的缓存,下面的方法返回的数据将会再次被缓存 user u3 = us.getanotheruser("李四", 400); system.out.println(us == u3); //false //前面已经缓存了 张三, 500的数据,下面方法不会重新执行,直接取缓存中的数据 user u4 = us.getanotheruser("张三", 500); system.out.println(u1==u4); //输出true //清空整个缓存 us.evictall(); //由于整个缓存都已经被清空,下面的代码都会被重新执行 user u5 = us.getanotheruser("张三", 500); user u6 = us.getanotheruser("李四", 400); system.out.println(u1==u5); //输出false system.out.println(u3==u6); //输出false }
执行结果,
正在执行getusersbynameandage()..
正在执行getanotheruser()..
--正在清空李四,400对应的缓存--
正在执行getanotheruser()..
false
true
--正在清空整个缓存--
正在执行getanotheruser()..
正在执行getanotheruser()..
false
false
总结
以上就是本文关于spring缓存机制实例代码的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!
下一篇: java+mysql实现商品抢购功能
推荐阅读
-
SpringBoot加入Guava Cache实现本地缓存代码实例
-
nodejs redis 发布订阅机制封装实现方法及实例代码
-
Spring boot + mybatis + Vue.js + ElementUI 实现数据的增删改查实例代码(一)
-
Spring boot + mybatis + Vue.js + ElementUI 实现数据的增删改查实例代码(二)
-
iOS清除所有缓存的实例代码
-
Spring Boot中使用Redis做缓存的方法实例
-
Spring动态配置计时器触发时间的实例代码
-
Spring Boot项目利用Redis实现集中式缓存实例
-
iOS中的缓存计算和清除完整实例代码
-
从源代码分析Android Universal ImageLoader的缓存处理机制