13.2、Spring学习—— Spring 缓存集成 ehcache

前言

本文使用 编程方式 实现 Spring+ehcache

Spring 版本

本文使用 Spring framework 版本为 4.3.0.RELEASE

Spring 缓存注解的介绍

Spring 缓存相关的四个注解

测试方案和基础代码

方案

首先,我们先提供一个简单的 Service 以及几个简单的实现,然后添加 ehcache 相关配置,之后通过测试方法展示Spring 和 ehcache 结合的效果

实体类

package com.bestcxx.test;

public class User {
	private Long id;
	private String userName;
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	@Override
	public String toString() {
		return "User [id=" + id + ", userName=" + userName + "]";
	}
}

Service 接口

public interface AInterface {
	String aMethod(User user);
	void bMethod(User user);
	String cMethod(User user);
	String dMethod(User user);
	String eMethod(Long id);
	String fMethod(Long id);
}

接口具体实现

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Component;

@Component
public class AImpl implements AInterface {
	/**
	 * @Cacheable 适用场景:单纯查询方法的缓存
	 * value 是缓存规则的名字,可以指定多个,指定多个就会有多个缓存
	 * key 是缓存的名字,可以用 Spel 表达式直接从方法入参获取
	 * condition 是条件判断,满足条件的才会被缓存
	 * sync 是否同步,true 为支持,Spring 4.3 后开始支持
	 */
	//@Cacheable(value = {"ehcache_test"},key = "#user.id",condition = "#user.id>100",sync=true)
	//@Cacheable(value = {"ehcache_test"},key = "#user.id",condition = "#user.id>100")
	@Cacheable(value = {"ehcache_test"},key = "#p0.id",condition = "#p0.id>100")
	@Override
	public String aMethod(User user) {
		System.out.println("invoke aMethod");
		return Math.random()+"";
	}
	
	/**
	 * @CacheEvict 适用场景:该注解修饰的方法,在调用时会清除指定的缓存,可以一次指定多个
	 * value 是缓存规则的名字,可以指定多个,指定多个就会有多个缓存
	 * key 缓存的名字,可以用 Spel 表达式直接从方法入参获取
	 * condition 是条件判断,满足条件的才会起作用
	 * allEntries 默认为只有 key 值匹配的才会被清楚缓存,设置为true则所有的缓存都失效,不可与key同时指定
	 * beforeInvocation 是否在方法调用前清楚缓存,默认为false 即只有方法完全调用成功才可以
	 */
	@CacheEvict(value = { "ehcache_test" },key = "#user.id",condition = "#user.id>100")
	@Override
	public void bMethod(User user) {
		System.out.println("invoke bMethod()");
	}
	
	/**
	 * @CachePut 适用场景
	 * value 是缓存规则的名字,可以指定多个,指定多个就会有多个缓存
	 * key 缓存的名字,可以用 Spel 表达式直接从方法入参获取
	 * condition 是条件判断,满足条件的才会起作用
	 */
	@CachePut(value = { "ehcache_test" },key = "#user.id",condition="#user.id>100")
	@Override
	public String cMethod(User user) {
		System.out.println("invoke cMethod");
		return Math.random()+"";
	}

	/**
	 * 这个方法看看就行,一般不会这么使用
	 * @Caching 可以同时配置多个@Cacheable、@CacheEvict、@CachePut
	 * 内部规则就是所有分规则的集合
	 * 需要注意的是
	 */
	@Caching(cacheable = {@Cacheable(value={"ehcache_test"},key="#p0.id"),@Cacheable(value={"ehcache_test"},key="#p0.id")},
			evict = {@CacheEvict(value={"ehcache_test","demo"},key= "#p0.id")},
			put = {@CachePut(value={"ehcache_test"},key="#p0.id")})
	@Override
	public String dMethod(User user) {
		System.out.println("invoke dMethod");
		return Math.random()+"";
	}
	
	/**
	 * #root.method.name 可以省略 #root.
	 */
	//@Cacheable(value="ehcache_test",key="#root.method.name")
	@Cacheable(value="ehcache_test",key="method.name")
	@Override
	public String eMethod(Long id) {
		System.out.println("invoke eMethod");
		return id+"";
	}
	
	/**
	 * #root.caches[index] 可以省略 #root
	 * #root.args[index] 可以省略 #root
	 */
	//@Cacheable(value="ehcache_test",key="caches[0]")
	@Cacheable(value="ehcache_test",key="args[0]")
	@Override
	public String fMethod(Long id) {
		System.out.println("invoke fMethod");
		return id+"";
	}
}

Spring xml 配置

<context:component-scan base-package="com.bestcxx.test"/>

增加缓存配置——这里结合ehcache

  • 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">
 <!-- 默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。 -->    
 <defaultCache
           eternal="false"
           maxElementsInMemory="10000"
           overflowToDisk="false"
           diskPersistent="false"
           timeToIdleSeconds="1800"
           timeToLiveSeconds="259200"
           memoryStoreEvictionPolicy="LRU"/>
	<!-- 有命名的 cache,可以定义多个 -->
   <cache name="ehcache_test"
           eternal="false"
           maxElementsInMemory="5000"
           overflowToDisk="false"
           diskPersistent="false"
           timeToIdleSeconds="10"
           timeToLiveSeconds="20"
           memoryStoreEvictionPolicy="LRU"/>
</ehcache>
<!-- name:缓存名称。
     maxElementsInMemory:缓存最大数目
     maxElementsOnDisk:硬盘最大缓存个数。
     eternal:对象是否永久有效,一但设置了,timeout将不起作用。
     overflowToDisk:是否保存到磁盘,当系统当机时
     maxBytesLocalHeap="50m" 最大存储为50m
     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,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
  -->

ehcache 配置类

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;


@Configuration
@EnableCaching
public class ConfigCache {
	@Bean
	public EhCacheCacheManager ehCacheManager(net.sf.ehcache.CacheManager cm) {
		return new EhCacheCacheManager(cm);
	}
	@Bean
	public EhCacheManagerFactoryBean ehCache() {
		EhCacheManagerFactoryBean ehCacheFactoryBean=new EhCacheManagerFactoryBean();
		ehCacheFactoryBean.setConfigLocation(new ClassPathResource("com/bestcxx/test/ehcache.xml"));
		return ehCacheFactoryBean;
	}
}

测试方法

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestClass {
	
	@SuppressWarnings("resource")
	public static void main(String[] args) {
		//加载配置文件,获取 applicationContext 对象
		ApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:applicationContext2.xml");
		
		AInterface aInterface=applicationContext.getBean(AInterface.class);
		User user=new User();
		user.setId(99l);
		user.setUserName("Jecket");
		//条件测试->100 才会触发缓存机制
		System.out.println("--缓存条件触发测试--");
		System.out.println(aInterface.aMethod(user));
		System.out.println(aInterface.aMethod(user));
		
		//第一次设置缓存,第二次直接读取缓存
		System.out.println("--缓存初次二次查询测试--");
		user.setId(199l);
		System.out.println(aInterface.aMethod(user));
		System.out.println(aInterface.aMethod(user));
		
		//清除缓存测试,再次查询会发现缓存失效
		System.out.println("--清除缓存测试--");
		aInterface.bMethod(user);
		System.out.println(aInterface.aMethod(user));
		System.out.println(aInterface.aMethod(user));
		
		//强制更新缓存测试-会直接更新缓存
		System.out.println("--强制更新缓存测试--");
		System.out.println(aInterface.cMethod(user));
		System.out.println(aInterface.aMethod(user));
		System.out.println(aInterface.aMethod(user));
		
		//尝试从 root 获取缓存配置信息
		System.out.println("--尝试从 root 获取缓存配置信息--");
		aInterface.bMethod(user);
		System.out.println(aInterface.eMethod(user.getId()));
		System.out.println(aInterface.eMethod(user.getId()));
		
		System.out.println("--尝试从 root 获取缓存配置信息--");
		aInterface.bMethod(user);
		System.out.println(aInterface.fMethod(user.getId()));
		System.out.println(aInterface.fMethod(user.getId()));
		
	}
}

测试输出结果

--缓存条件触发测试--
invoke aMethod
0.5251943952019077
invoke aMethod
0.7259120572321393
--缓存初次二次查询测试--
invoke aMethod
0.501591345010235
0.501591345010235
--清除缓存测试--
invoke bMethod()
invoke aMethod
0.7954256410911823
0.7954256410911823
--强制更新缓存测试--
invoke cMethod
0.20779400279129234
0.20779400279129234
0.20779400279129234
--尝试从 root 获取缓存配置信息--
invoke bMethod()
invoke eMethod
199
199
--尝试从 root 获取缓存配置信息--
invoke bMethod()
invoke fMethod
199
199
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值