ehcache2.x和ehcache3.x区别:
ehcache2类名:net.sf.ehcache.CacheManager
ehcache3类名:org.ehcache.CacheManager
spring4的EhCacheManagerFactoryBean引用的是net.sf.ehcache.CacheManager
所以不支持ehcache3,spring5开始支持ehcache3
一、添加依赖
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.6</version>
</dependency>
二、在web模块src/main/resource下建立spring-cache.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"
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.xsd">
<!-- 启用注解驱动缓存 -->
<cache:annotation-driven />
<!--声明一个缓存管理器(EhCacheCacheManager) 这里的实现代码是通过传入EhCache的CacheManager实例实现的 -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcache" />
</bean>
<!--这里并不是EhCacheManagerFactoryBean的实例,而是EhCache中CacheManager的一个实例 -->
<bean id="ehcache"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:cache/ehcache.xml" />
<property name="shared" value="true" />
</bean>
</beans>
在applicationContext.xml内添加引用
<import resource="classpath:/spring-cache.xml"/>
好奇定义的时候是EhCacheManagerFactoryBean工厂类,注入到EhCacheCacheManager却是net.sf.ehcache.CacheManager的实例,spring是在哪里调用工厂类的getObject方法呢?
@Override
public CacheManager getObject() {
return this.cacheManager;
}
三、在web模块src/main/resource下建立cache目录
在目录内建立ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<!--
diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
user.home – 用户主目录
user.dir – 用户当前工作目录
java.io.tmpdir – 默认临时文件路径
-->
<diskStore path="java.io.tmpdir"/>
<!--
defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
-->
<!--
name:缓存名称。
maxElementsInMemory:缓存最大数目
maxElementsOnDisk:硬盘最大缓存个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
overflowToDisk:是否保存到磁盘,当系统当机时
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
FIFO,first in first out,这个是大家最熟的,先进先出。
LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
-->
<defaultCache
eternal="false"
maxElementsInMemory="10000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="259200"
memoryStoreEvictionPolicy="LRU"/>
<cache
name="cache.test"
eternal="false"
maxElementsInMemory="5000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
四、缓存执行过程
1、当方法调用时,会从指定的缓存中查找key
2、如果key存在,返回缓存中的对象
3、如果key不存在,则执行实际方法(查询数据库),将执行结果存入缓存中,返回对象
缓存实现相当于定义了一个切面,在方法调用前和调用后,从缓存中取数据,或写数据
五、spring的缓存注解
1、@Cacheable
表示此方法的结果是可以缓存的
2、@CachePut
调用方法之后获取结果去更新缓存
3、@CacheEvict
删除或回收缓存内容
4、参数
1)value:缓存的名称
2)key:缓存的key
3)condition:缓存的条件
4)allEntries:是否清空所有缓存内容,缺省为false
六、添加测试类
1、建立CacheTestComp.java
package com.study.base.component;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import com.study.base.dao.TeacherMapper;
import com.study.domain.testBean.Teacher;
@Component
public class CacheTestComp {
@Autowired
TeacherMapper teacherMapper;
@Cacheable(value="cache.test", key="#id")
public Teacher getTeacherById(int id) {
return teacherMapper.getTeacherById(id);
}
}
2、添加测试方法 testCache
package com.study.web.resources;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.study.base.annotation.TimeCount;
import com.study.base.component.CacheTestComp;
import com.study.base.exception.BizException;
import com.study.base.exception.SysException;
import com.study.base.sender.QueueSender;
import com.study.base.sender.TopicSender;
import com.study.domain.testBean.Teacher;
@Controller
@RequestMapping("mvc")
public class TestController {
private static Logger log = LoggerFactory.getLogger(TestController.class);
@Autowired
QueueSender queueSender;
@Autowired
TopicSender topicSender;
@Autowired
CacheTestComp cacheTestComp;
@RequestMapping("hello")
@TimeCount
public String hello() {
log.info("hello in...");
log.info("hello out...");
return "hello";
}
@RequestMapping("testError")
public void testError() {
log.info("testError in...");
log.info("testError out...");
throw new BizException("1234567890", "报错信息1");
}
@RequestMapping("testError2")
public void testError2() {
log.info("testError2 in...");
log.info("testError2 out...");
throw new SysException("0987654321", "报错信息2");
}
@RequestMapping("queueSend")
public void queueSend(HttpServletRequest request) {
String msg = request.getParameter("msg");
queueSender.send(msg);
}
@RequestMapping("topicSend")
public void topicSend(HttpServletRequest request) {
String msg = request.getParameter("msg");
topicSender.send(msg);
}
@RequestMapping("testCache")
public void testCache(HttpServletRequest request) {
String number = request.getParameter("number");
Teacher teacher = cacheTestComp.getTeacherById(Integer.parseInt(number));
log.info("name is: {}", teacher.getName());
}
}
3、依次访问
number=1
number=1
number=2
number=1
查看日志:
2019-08-23 14:26:22.535 [] [1566541581615-9907] [] [] INFO [http-nio-8080-exec-6] com.study.web.resources.TestController [71]:name is: 刘备
2019-08-23 14:26:36.417 [] [1566541596411-9831] [] [] INFO [http-nio-8080-exec-9] com.study.web.resources.TestController [71]:name is: 刘备
2019-08-23 14:26:41.600 [] [1566541601591-7857] [] [] INFO [http-nio-8080-exec-10] com.study.web.resources.TestController [71]:name is: 张飞
2019-08-23 14:26:51.118 [] [1566541611117-0937] [] [] INFO [http-nio-8080-exec-2] com.study.web.resources.TestController [71]:name is: 刘备
2019-08-23 14:26:22.438 [] [1566541581615-9907] [] [] DEBUG [http-nio-8080-exec-6] com.study.base.dao.TeacherMapper.getTeacherById [143]:==> Preparing: select ID, NAME from tbl_teacher_inf WHERE ID = ?
2019-08-23 14:26:22.446 [] [1566541581615-9907] [] [] DEBUG [http-nio-8080-exec-6] com.study.base.dao.TeacherMapper.getTeacherById [143]:==> Parameters: 1(Integer)
2019-08-23 14:26:22.527 [] [1566541581615-9907] [] [] TRACE [http-nio-8080-exec-6] com.study.base.dao.TeacherMapper.getTeacherById [149]:<== Columns: ID, NAME
2019-08-23 14:26:22.528 [] [1566541581615-9907] [] [] TRACE [http-nio-8080-exec-6] com.study.base.dao.TeacherMapper.getTeacherById [149]:<== Row: 1, 刘备
2019-08-23 14:26:22.529 [] [1566541581615-9907] [] [] DEBUG [http-nio-8080-exec-6] com.study.base.dao.TeacherMapper.getTeacherById [143]:<== Total: 1
2019-08-23 14:26:41.595 [] [1566541601591-7857] [] [] DEBUG [http-nio-8080-exec-10] com.study.base.dao.TeacherMapper.getTeacherById [143]:==> Preparing: select ID, NAME from tbl_teacher_inf WHERE ID = ?
2019-08-23 14:26:41.596 [] [1566541601591-7857] [] [] DEBUG [http-nio-8080-exec-10] com.study.base.dao.TeacherMapper.getTeacherById [143]:==> Parameters: 2(Integer)
2019-08-23 14:26:41.597 [] [1566541601591-7857] [] [] TRACE [http-nio-8080-exec-10] com.study.base.dao.TeacherMapper.getTeacherById [149]:<== Columns: ID, NAME
2019-08-23 14:26:41.597 [] [1566541601591-7857] [] [] TRACE [http-nio-8080-exec-10] com.study.base.dao.TeacherMapper.getTeacherById [149]:<== Row: 2, 张飞
2019-08-23 14:26:41.598 [] [1566541601591-7857] [] [] DEBUG [http-nio-8080-exec-10] com.study.base.dao.TeacherMapper.getTeacherById [143]:<== Total: 1
可以看到,只有首次请求的两个线程,访问了数据库,后面重复请求没有访问数据库,是从缓存中获取对象
七、其他
最新代码上传至https://github.com/csj50/webapp2.git
参考资料:
https://blog.csdn.net/u012240455/article/details/80844361
https://blog.csdn.net/Jul_11th/article/details/80735090
https://www.cnblogs.com/llzhang123/p/9037346.html