Java web项目创建笔记18 之《spring整合ehcache2.x》

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值