使用EhCache和Spring AOP实现计算结果缓存

40 篇文章 0 订阅
19 篇文章 0 订阅
原文:[url]http://kim-miao.iteye.com/blog/1622686[/url]

一.Ehcache简介
EhCache是一个纯Java的进程内缓存框架,具有如下特点:
1. 快速简单,非常容易和应用集成。
2.支持多种缓存策略 。
3. 缓存数据有两级:内存和磁盘,因此无需担心容量问题 。
4. 缓存数据会在虚拟机重启的过程中写入磁盘 。
5. 可以通过RMI、可插入API等方式进行分布式缓存。
6. 具有缓存和缓存管理器的侦听接口 。
7. 支持多缓存管理器实例,以及一个实例的多个缓存区域 等特点。

二.Ehcache配置的相关参数
Ehcache的配置很灵活,官方提供的配置方式有好几种,你可以通过声明配置、在xml中配置、在程序里配置或者调用构造方法时传入不同的参数。下面以最常用的XML配置为例说下配置的相关参数的意义,ehcache.xml是最常见的一个文件,ehcache一般会通过CacheManager从classpath加载该文件完成Cache的实例化。

1.ehcache.xml中的配置信息
ehcache.xml片段:

<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
name="name"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
</ehcache>

2.Cache中常用参数的具体意义
(1)name:Cache的唯一标识。
(2)maxElementsInMemory:内存中最大缓存对象数。
(3)eternal:Element是否永久有效,一旦设置true,timeout将不起作用。
(4)timeToIdleSeconds:设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
(5)timeToLiveSeconds:设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用,默认是0.,也就是element存活时间无穷大。
(6)overflowToDisk:配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中。
(7)maxElementsOnDisk:磁盘中最大缓存对象数,若是0表示无穷大。
(8) memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理缓存中的内容。默认策略是LRU(最近最少使用),你也可以设置为FIFO(先进先出)或是LFU(较少使用)

三.Spring和Ehcache的集成
1.ehcache.xml


<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd">

<diskStore path="java.io.tmpdir" />

<defaultCache maxElementsInMemory="10000" eternal="false"
timeToIdleSeconds="600" overflowToDisk="false">
</defaultCache>

<cache name="levelOneCache" maxElementsInMemory="1000" eternal="false"
timeToIdleSeconds="300" timeToLiveSeconds="1000" overflowToDisk="false" />
</ehcache>

2.beans.xml的配置


<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation">
<value>classpath:ehcache.xml</value>
</property>
</bean>

<bean id="levelOneCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<ref local="cacheManager" />
</property>
<property name="cacheName">
<value>configCache</value>
</property>
</bean>

3.测试类

       package org.mango.cache.ehcache;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

public class EhcacheTest {

public static void main(String[] args) {
Resource res = new ClassPathResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(res);

CacheManager cacheManager = (CacheManager) factory.getBean("cacheManager");
Cache levelOneCache = cacheManager.getCache("levelOneCache");
CacheObject cacheObject = null;
for (int i = 0; i < 10; i++) {
Element element = levelOneCache.get("key");

if (element == null) {
cacheObject = new CacheObject("test");
element = new Element("key", cacheObject);
levelOneCache.put(element);
System.out.println("cacheObject[" + cacheObject + "]" + ",无法从缓存中取到");
} else {
cacheObject = (CacheObject) element.getValue();
System.out.println("cacheObject[" + cacheObject + "]" + ",从缓存中取到");
}
}
}
}

输出如下:


cacheObject[name:test],无法从缓存中取到
cacheObject[name:test],从缓存中取到
cacheObject[name:test],从缓存中取到
cacheObject[name:test],从缓存中取到
cacheObject[name:test],从缓存中取到

四.利用Spring AOP和Ehcache实现线程级方法缓存
在复杂的业务逻辑或在一次计算中需多次调用同一个DAO或远程服务,在这种情况下,均可对计算结果缓存起来,不但可以减少了不必要的调用次数,还同时可以提高系统运算性能。下面以缓存一个service为例说明一下其用法。

1.TestService接口

public interface TestService {

/**
* 根据userId取得用户名。
*
* @param userId
* @return
*/
public String getUserName(String userId);
}

2.TestServiceImpl实现类
public class TestServiceImpl implements TestService {
/*
* @see org.mango.cache.ehcache.TestService#getUserName(java.lang.String)
*/
public String getUserName(String userId) {
return userId;
}
}

3.拦截器的实现
public class CacheInterceptor implements MethodInterceptor {

private Cache cache;

/**
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
*/
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
String methodName = method.getName();
Object[] arguments = invocation.getArguments();
Object result = invocation.proceed();

String targetName = method.getDeclaringClass().getName();
String key = getCacheKey(targetName, methodName, arguments);

Element element = cache.get(key);

if (element == null) {

result = invocation.proceed();
System.out.println("第一次调用方法并缓存其值:" + result);
cache.put(new Element(key, result));
} else {
result = element.getValue();
System.out.println("从缓存中取得的值为:" + result);
}
return result;

}

/**
* 生成缓存中的KEY值。
*/
protected String getCacheKey(String targetName, String methodName, Object[] arguments) {
StringBuffer sb = new StringBuffer();
sb.append(targetName).append(".").append(methodName);
if ((arguments != null) && (arguments.length != 0)) {
for (int i = 0; i < arguments.length; i++) {
sb.append(".").append(arguments[i]);
}
}
return sb.toString();
}

public void setCache(Cache cache) {
this.cache = cache;
}

}

4.Bean的配置

<bean id="testService" class="org.mango.cache.ehcache.TestServiceImpl" />

<bean id="serviceMethodInterceptor" class="org.mango.cache.ehcache.CacheInterceptor">
<property name="cache">
<ref local="levelOneCache" />
</property>
</bean>

<bean id="serviceAutoProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<value>serviceMethodInterceptor</value>
</list>
</property>
<property name="beanNames">
<value>*Service</value>
</property>
</bean>

5.测试方法
public class ServiceTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
TestService testService = (TestService) context.getBean("testService");
for (int i = 0; i < 5; i++) {
testService.getUserName("mango");
}
}
}

其输出结果如下:
第一次调用方法并缓存其值:mango
从缓存中取得的值为:mango
从缓存中取得的值为:mango
从缓存中取得的值为:mango
从缓存中取得的值为:mango
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 使用SpringAOP可以实现缓存功能。具体实现方式是,在需要缓存的方法上添加@Cacheable注解,指定缓存的key和缓存的名称。当方法被调用时,Spring会先检查缓存中是否存在该key对应的缓存数据,如果存在则直接返回缓存数据,否则执行方法并将返回结果缓存起来。同时,还可以使用@CachePut注解更新缓存数据,或者使用@CacheEvict注解清除缓存数据。这样可以有效地提高系统性能和响应速度。 ### 回答2: 使用SpringAOP实现缓存功能的步骤如下: 1. 首先,需要在Spring配置文件中启用AOP功能,可以通过添加`<aop:aspectj-autoproxy/>`来实现。 2. 然后,创建一个用于缓存方法调用结果的类,该类需要实现`org.springframework.cache.Cache`接口,并提供对缓存的读取、写入、删除等操作方法。 3. 还需要创建一个切面类,该类需要使用`@Aspect`注解进行标记,并在需要缓存的方法上添加`@Cacheable`注解。在切面类中,使用`@Before`和`@After`等注解来定义缓存操作的切点和通知。 4. 在Spring配置文件中,将切面类声明为一个bean,并在`<aop:config>`中指定要应用缓存的方法和切面。 5. 最后,配置`ehcache.xml`(或其他缓存配置文件),并将其指定为Spring配置文件中缓存管理器的实现类,例如`<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"/>`。 这样,当被缓存的方法被调用时,AOP将切入切面类的通知方法,首先查询缓存是否存在该方法的结果,如果存在,则直接返回缓存中的结果;如果不存在,则调用原始方法,并将结果存入缓存中。在后续的调用中,如果参数相同,则直接从缓存中获取结果,从而减少了对原始方法的调用,提高了系统的性能和响应速度。 使用SpringAOP实现缓存功能可以大大简化代码,提高项目的可维护性和可扩展性,同时还能通过缓存数据减少对数据库等资源的访问,提升系统整体的性能。 ### 回答3: 使用SpringAOP可以很方便地实现缓存功能。AOP(面向切面编程)是一种编程范式,通过在程序运行时动态地将横切逻辑(如日志记录、事务管理、异常处理等)插入到应用程序的特定位置,以提供更好的代码结构和模块化。 在使用SpringAOP实现缓存功能时,我们可以通过以下步骤来实现: 1. 定义一个缓存注解:可以使用Spring提供的@Cacheable注解来定义缓存的方法。这个注解可以应用在方法上,用于标记被缓存的方法。 2. 配置缓存切面:通过AOP切面配置,将缓存注解和具体的缓存实现关联起来。可以使用Spring的@Aspect注解来定义一个切面类,该类可以包含多个增强方法用于处理缓存操作。 3. 配置缓存策略:在切面类中,可以通过使用Spring缓存管理器(如Ehcache、Redis等)来定义缓存的具体策略。可以配置缓存的过期时间、缓存的存储位置等。 4. 在目标方法中使用缓存注解:在需要被缓存的方法上添加之前定义的缓存注解。当方法被调用时,AOP切面会先检查缓存中是否存在对应的缓存数据,如果存在则直接返回缓存数据,否则执行方法逻辑并将结果存入缓存。 5. 测试缓存功能:执行目标方法,观察是否从缓存中获取数据以及方法执行的时间。 通过这种方式,我们可以很方便地在应用中加入缓存功能,提高系统性能和响应速度。同时,由于使用AOP的方式,可以很好地解耦和复用缓存相关的代码逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值