缓存方法 : Srping+Ehcache 在Service层配置缓存

[size=large][color=red]自定义Key[/color][/size]
package cn.com.voge.system.service;

import org.springframework.cache.interceptor.KeyGenerator;

import java.lang.reflect.Method;

/**
* 项目名称: wp_idea_linux
* 功能说明:
* 创建者: Pandy,
* 邮箱: panyongzheng@163.com, 1453261799@qq.com
* 版权:
* 官网:
* 创建日期: 15-9-24.
* 创建时间: 上午11:25.
* 修改历史:
* -----------------------------------------------
*/
public class RhKeyGenerator implements KeyGenerator {

@Override
public Object generate(Object o, Method method, Object... objects) {
return o.toString();
}
}

<bean id="customGenerator" class="cn.com.voge.system.service.RhKeyGenerator">
<cache:annotation-driven cache-manager="cacheManager" key-generator="customGenerator" proxy-target-class="true"/>



@Cacheable 支持如下几个参数:
value:缓存位置名称,不能为空,如果使用EHCache,就是ehcache.xml中声明的cache的name
key:[color=red]缓存的key,默认为空,既表示使用方法的参数类型及参数值作为key[/color],支持SpEL
condition:触发条件,只有满足条件的情况才会加入缓存,默认为空,既表示全部都加入缓存,支持SpEL


[color=red][b]奇葩问题:[/b][/color]
@Cacheable(value="h1m0Cache", key="#params.toString() + ',' + #sessionData.getInstanceId()")
public ControllerContext setDropDownData(ArrayList<Map<String, Object>> params, SessionData sessionData,final String cacheKey) {
}

, 在开发环境下没问题,但是打包之后就出现问题 [color=red]Method call: Attempted to call method toString() on null context object[/color]
=====================>[color=red]一直找不到问题原因[/color],params参数不可能是null, 难道不能使用方法里面的参数来做key? [url]http://hanqunfeng.iteye.com/blog/1158824[/url], 这个文章已经推翻了, 可是为什么出现问题呢?


SpringMVC整合Ehcache(注解方式): [url]http://blog.csdn.net/jadyer/article/details/12257865[/url],[color=red]介绍很详细.[/color]
注释驱动的 Spring cache 缓存介绍 [url]https://www.ibm.com/developerworks/cn/opensource/os-cn-spring-cache/[/url], [color=red]里面介绍了注解和配置[/color].

[color=blue][b]@CachePut[/b][/color] 应用到写数据的方法上,如新增/修改方法,调用方法时会自动把相应的数据放入缓存
[color=blue][b]@CacheEvict[/b][/color] 即应用到移除数据的方法上,如删除方法,调用方法时会从缓存中移除相应的数据
[color=blue][b]@Cacheable[/b][/color] 应用到读取数据的方法上,即可缓存的方法,如查找方法:先从缓存中读取,如果没有再调用方法获取数据,然后把数据添加到缓存中


[color=red]@Cacheable 注释,则当重复使用相同参数调用方法的时候,方法本身不会被调用执行,即方法本身被略过了,取而代之的是方法的结果直接从缓存中找到并返回了。[/color]
@Cacheable(value="accountCache"): 使用accountCache缓存.
@CacheEvict(value=”accountCache”,key=”#account.getName()”),其中的 Key 是用来指定缓存的 key 的,这里因为我们保存的时候用的是 account 对象的 name 字段,所以这里还需要从参数 account 对象中获取 name 的值来作为 key,前面的 # 号代表这是一个 SpEL 表达式,此表达式可以遍历方法的参数对象,具体语法可以参考 Spring 的相关文档手册。
@Cacheable(value="accountCache",condition="#userName.length() <= 4") condition=”#userName.length() <=4”,这里使用了 SpEL 表达式访问了参数 userName 对象的 length() 方法,条件表达式返回一个布尔值,true/false,当条件为 true,则进行缓存操作,否则直接调用方法执行的返回结果。
@Cacheable(value="accountCache",key="#userName.concat(#password)") key 属性,其中引用了方法的两个参数 userName 和 password

[color=red]@CachePut 注释,这个注释可以确保方法被执行,同时方法的返回值也被记录到缓存中。现实中并不总是如此,有些情况下我们希望方法一定会被调用,因为其除了返回一个结果,还做了其他事情,例如记录日志,调用接口等,这个时候,我们可以用 @CachePut 注释[/color]
@Cacheable(value="accountCache")// 使用了一个缓存名叫 accountCache 
public Account getAccountByName(String userName) {
// 方法内部实现不考虑缓存逻辑,直接实现业务
return getFromDB(userName);
}
@CachePut(value="accountCache",key="#account.getName()")// 更新 accountCache 缓存
public Account updateAccount(Account account) {
return updateDB(account);
}
private Account updateDB(Account account) {
System.out.println("real updating db..."+account.getName());
return account;
}


注解碰到的问题:
[color=red]Cannot find cache named xxxxxx CacheableOperation[/color] [url]http://m.bianceng.cn/Programming/Java/201309/37363_10.htm[/url]
<bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"/>
</bean>
<bean id="cacheManager1" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="cacheManagerFactory"/>
</bean>
<bean id="cacheManager"
class="org.springframework.cache.support.CompositeCacheManager">
<property name="cacheManagers">
<list>
<ref bean="cacheManager1" />
</list>
</property>
<property name="fallbackToNoOpCache" value="true" />
</bean>
<cache:annotation-driven cache-manager="cacheManager"/>

在找不到 accountCache,且没有将 fallbackToNoOpCache 设置为 true 的情况下,系统会抛出异常。


原文: [url]http://miaoxianjie.iteye.com/blog/1700379[/url]
[color=red]有些地方做了适当修改[/color]
1. ehcache 文件
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">  

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


<cache name="testServiceCache"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="200"
timeToLiveSeconds="300"
overflowToDisk="true"
/>

</ehcache>


2. applicationContext.xml 文件 相关代码
   <!-- Service Cache   Ehcache -->  

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

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

<!-- methodCacheInterceptor 要自己实现的代码 -->
<bean id="methodCacheInterceptor" class="com.miao.service.MethodCacheInterceptor">
<property name="cache">
<ref local="methodCache"/>
</property>
</bean>

<!-- 配置要拦截的service, 拦截service包下所有类的所有方法 -->
<aop:config>
<aop:pointcut id="methodCachePointCut" expression="execution(* com.miao.service.*.*(..))" />
<aop:advisor pointcut-ref="methodCachePointCut" advice-ref="methodCacheInterceptor" />
</aop:config>

<!-- 也可用此种方式 指定哪些方法使用cache-->
<!--
<bean id="methodCachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref local="methodCacheInterceptor"/>
</property>
<property name="patterns">
<list>
<value>.*getStepPartKitList</value>
</list>
</property>
</bean>
-->


3.MethodCacheInterceptor
package cn.com.voge.system.interceptor;

import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.factory.InitializingBean;

import java.io.Serializable;

/**
* 项目名称: wp_idea_linux
* 功能说明:
* 创建者: Pandy,
* 邮箱: panyongzheng@163.com, 1453261799@qq.com
* 版权:
* 官网:
* 创建日期: 15-9-16.
* 创建时间: 下午4:31.
* 修改历史:
* -----------------------------------------------
*/
public class MethodCacheInterceptor implements MethodInterceptor,InitializingBean {
//private static final Log LOGGER = LogFactory.getLog(MethodCacheInterceptor.class);

private Ehcache cache;//我使用的Spring版本使用Ehcache类,一些可能是使用Cache类.注意一下.

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


public Object invoke(MethodInvocation invocation) throws Throwable {

String targetName = invocation.getThis().getClass().getName();
String methodName = invocation.getMethod().getName();
Object[] arguments = invocation.getArguments();
Object result;

String cacheKey = getCacheKey(targetName, methodName, arguments);
Element element = cache.get(cacheKey);
System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
if (element == null) {
result = invocation.proceed(); //调用被拦截的目标方法
//LOGGER.info("Set into Cache");
element = new Element(cacheKey, (Serializable) result);
cache.put(element);
}
return element.getValue();
}


private String getCacheKey(String targetName, String methodName,Object[] arguments) {
StringBuffer sb = new StringBuffer();
//拼cacheKey 这里使用 className.methodName(arg1,arg2.....argN) 作为key
sb.append(targetName).append(".").append(methodName).append("(");
if ((arguments != null) && (arguments.length != 0)) {
for (int i = 0; i < arguments.length; i++) {
sb.append(arguments[i]);
if (i + 1 != arguments.length) {
sb.append(",");
}
}
}
sb.append(")");
return sb.toString();
}

public void afterPropertiesSet() throws Exception {
if(null == cache) {
throw new IllegalArgumentException("Cache should not be null.");
}
}

}



4.使用Junit测试即可,传递相同的参数,调用service内的同一个方法,只会进入DAO一次
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值