您的位置:首页 > 编程语言 > Java开发

encache整合spring应用实例

2013-02-21 17:47 441 查看
本文章摘编、转载需要注明来源 http://write.blog.csdn.net/postedit/8599512


缓存热点数据是提高访问效率的重要手段之一,下面我用encache演示下如何做service层的数据缓存

先写个方法拦截器,当然要先继承MethodInterceptor,encache的标识key我是将参数序列成json字符

 

可能强制部分会影响性能,建议判断null后再一次判断cache.get(key)是否为null,同步的第一人的操作已经执行完毕,那element里面就不为null,这样其他的并发用户就不需要

继续再执行put值的操作,这样做应该能比较好地降低synchronized带来的负面影响

/**
* 缓存方法拦截器核心代码
*
* @author shadow
* @email 124010356@qq.com
* @create 2012.04.28
*/
public class EhCacheMethodInterceptor implements MethodInterceptor,
InitializingBean {

// private static final Logger log = Logger.getLogger(MethodCacheInterceptor.class);

private Cache cache;

public EhCacheMethodInterceptor() {
super();
}

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

public void afterPropertiesSet() throws Exception {
// /log.info(cache A cache is required. Use setCache(Cache) to provide one.");
}

public Object invoke(MethodInvocation invocation) throws Throwable {
String targetName = invocation.getThis().getClass().getName();
String methodName = invocation.getMethod().getName();
Object[] arguments = invocation.getArguments();
String cacheKey = getCacheKey(targetName, methodName, arguments);
Element element = cache.get(cacheKey);

// 缓存节点不存在的情况
if (null == element) {
synchronized (this) {
// 这里判断是为了降低强制同步的负面影响,只需第一个操作该添加过程,后来者则跳过
if (null == cache.get(cacheKey))
element = putValueToCache(invocation, element, cacheKey);
}
}
// 返回缓存值
return element.getValue();

}

// 新增节点放到缓存区
private Element putValueToCache(MethodInvocation invocation,
Element element, String cacheKey) throws Throwable {
Object result = invocation.proceed();
element = new Element(cacheKey, (Serializable) result);
cache.put(element);
return element;
}

/**
*
* 返回具体的方法(全路径+方法名+参数值)
*
* @param targetName
*            全路径
* @param methodName
*            方法名称
* @param arguments
*            参数(转换成JSON格式方便比较)
* @return String
*/
private String getCacheKey(String targetName, String methodName,
Object[] arguments) {
StringBuffer buffer = new StringBuffer("");
buffer.append(targetName).append(".").append(methodName);
for (Object argument : arguments) {
buffer.append(".")
.append(BaseSupport.ContextUtil.getJSON(argument));
}
return buffer.toString();
}

}


再做个同步数据的限制类,当我们执行remove等那些方法的时候会清空encache里面的相关缓存的方法数据,下次再访问的时候会重新在数据库里读取更新后的数据,到这里基本就可以了

package com.shadow.extras.cache;

import java.util.List;

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

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;

/**
* 缓存数据变动后让数据保持同步状态
*
* @author shadow
* @email 124010356@qq.com
* @create 2012.04.28
*/
public class EhCacheMethodAfterAdvice {

protected final Logger logger = Logger.getLogger(getClass());

private CacheManager cacheManager;
private Cache cacheName;

/**
* 原始数据发生变更时保持强一致性(刪除緩存管理器里指定key的value)
*
* @param joinPoint
*/
public void afterReturning(JoinPoint joinPoint) {
// String methodName = joinPoint.getSignature().getName();// 得到执行的方法

if (cacheManager != null && cacheName != null) {
// 获取缓存堆
Class<?> clazz = joinPoint.getTarget().getClass();
List<?> list = cacheName.getKeys();
for (int i = 0, len = list.size(); i < len; i++) {
String key = String.valueOf(list.get(i));
if (key.startsWith(clazz.getName()))
cacheName.remove(key);
}
} else {
if (cacheManager == null)
logger.error("缓存管理器不存在!");
if (cacheName == null)
logger.error("缓存堆不存在!");
}
}

public CacheManager getCacheManager() {
return cacheManager;
}

public void setCacheManager(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}

public Cache getCacheName() {
return cacheName;
}

public void setCacheName(Cache cacheName) {
this.cacheName = cacheName;
}

}


然后是在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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:ehcache="http://www.springframework.org/schema/ehcache"
xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/ehcache http://www.springframework.org/schema/cache/springmodules-ehcache.xsd">
<!-- 配置缓存管理器 -->
<bean id="defaultCacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation">
<value>classpath:ehcache.xml</value>
</property>
</bean>

<!-- 配置一个简单的缓存工厂bean对象 -->
<bean id="defaultCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<ref local="defaultCacheManager" />
</property>
<!-- 使用缓存 关联ehcache.xml中的缓存配置 -->
<property name="cacheName" value="defaultCache" />
</bean>

<!-- 配置一个简单的缓存工厂bean对象 -->
<bean id="commonCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<ref local="defaultCacheManager" />
</property>
<!-- 使用缓存 关联ehcache.xml中的缓存配置 -->
<property name="cacheName" value="commonCache" />
</bean>

<!-- 配置一个缓存拦截器对象,处理具体的缓存业务 -->
<bean id="ehCacheMethodInterceptor" class="com.shadow.extras.cache.EhCacheMethodInterceptor">
<property name="cache" ref="defaultCache" />
</bean>

<!-- 参与缓存的切入点对象 (切入点对象,确定何时何地调用拦截器) -->
<bean id="methodCachePointCut"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!-- 配置缓存切面 -->
<property name="advice" ref="ehCacheMethodInterceptor" />
<!--
配置哪些方法参与缓存策略 .表示符合任何单一字元 ### +表示符合前一个字元一次或多次 ### *表示符合前一个字元零次或多次 ###
\Escape任何Regular expression使用到的符号
-->
<!-- .*表示前面的前缀(包括包名) 表示print方法-->
<property name="patterns">
<list>
<value>
com.xshadow.mvc.service\..*Service.*\.find.*
</value>
</list>
</property>
</bean>

<!-- 配置一个缓存拦截器对象,处理具体的同步缓存业务 -->
<bean id="ehCacheMethodAfterAdvice" class="com.shadow.extras.cache.EhCacheMethodAfterAdvice">
<property name="cacheManager" ref="defaultCacheManager" />
<property name="cacheName" ref="defaultCache" />
</bean>
<aop:config>
<aop:aspect id="methodCachePointCutAdviceAspect" ref="ehCacheMethodAfterAdvice">
<aop:after method="afterReturning"
pointcut="execution(* com.shadow.mvc.service.*Service.modify*(..))" />
<aop:after method="afterReturning"
pointcut="execution(* com.shadow.mvc.service.*Service.save*(..))" />
<aop:after method="afterReturning"
pointcut="execution(* com.shadow.mvc.service.*Service.remove*(..))" />
</aop:aspect>
</aop:config>

</beans>


以后我们配置需要缓存的地方就直接在文件里配置就可以了,至于分布式的缓存应用有空再写
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java javaee spring web