`
78425665
  • 浏览: 125678 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

spring+ehcache应用

阅读更多
首页发现篇,虽然跟我的不一样,但思路大致相同,大家可以参考下咯
http://mixer-b.iteye.com/blog/1563872

以前没具体做过缓存,于是上网搜了下资料,于是得知spring+ehcache做缓存一些考虑因素:
1、缓存的切面放在哪一层最合适(大部分情况是service,dao),其实应用在哪一层都有各自的用武之地,如:
一、放在service,是缓存整个经过业务处理后的一个结果,这样的做法大大减少了系统逻辑处理,但如果业务方法里面涉及到多表操作,则比较麻烦,因为要考虑缓存数据更新的问题。
二、放在dao,大多数都放在这层,也是推荐放在这层,因为基本不用人为的考虑缓存及时更新的问题造成业务方法返回的结果不一致。只缓存数据,不牵扯到业务逻辑

2、对于某些特殊情况下的方法,不需要缓存,或者不需要更新缓存的方法,通过参数排除
3、考虑需要缓存更新,所以需要两个拦截器去拦截不同的方法,做不同的处理
一、缓存拦截器,在方法调用之前拦截,如(find,query,select,get方法),经过一些逻辑处理,再判断返回缓存还是真实的数据
二、更新缓存拦截器,在方法调用之后,如(save,insert,update,delete方法)

于是马上动手:
缓存拦截器 MethodCacheInterceptor
package com.eclink.cache;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;

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

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.log4j.Logger;
import org.junit.Assert;
import org.springframework.beans.factory.InitializingBean;

import com.eclink.common.Common;

public class MethodCacheInterceptor implements MethodInterceptor,
		InitializingBean {
	private static final Logger log = Logger.getLogger(MethodCacheInterceptor.class);
	
	private Cache cache;
	private List<String> noCacheMethod;
	

	public void setNoCacheMethod(List<String> noCacheMethod) {
		this.noCacheMethod = noCacheMethod;
	}

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

	/**
	 * 拦截service/dao中的方法,如果存在该结果,则返回cache中的值。<br>
	 * 否则,则从数据库中查询返回并放入cache中
	 * @throws Throwable 
	 */
	public Object invoke(MethodInvocation invocation) throws Throwable {
		String targetName = invocation.getThis().getClass().getName();
		String methodName = invocation.getMethod().getName();
		Object[] args = invocation.getArguments();
		Object result = null;
		
		// 排除不需要缓存的方法
		boolean noCache = false;
		if(!Common.isEmpty(noCacheMethod)){
			String s = targetName +"."+methodName;
			for (String method : noCacheMethod) {
				if(s.indexOf(method) != -1){
					noCache = true;
					break;
				}
			}
		}
		if(noCache){
			// 不需要缓存,直接调用方法返回值
			return invocation.proceed();
		}
		else{
			String cacheKey = getCacheKey(targetName, methodName, args);
			log.debug("find object from "+cache.getName()+" : "+cacheKey);
			Element e = cache.get(cacheKey);
			if(e == null){
				log.debug("can't find object in "+cache.getName()+", get method result and create the cache(key: "+cacheKey+").");
				result = invocation.proceed();
				if(result == null)return null;
				if(!(result instanceof Serializable)){
					// 如果返回结果不可序列化,则不缓存,直接返回
					log.info(result + "  is not Serializable,Can't use cache.");
					return result;
				}
				e = new Element(cacheKey, result);
				cache.put(e);
			}
			// 返回克隆的对象,这个看需求了,如果你想直接修改缓存里对象的值,就直接返回缓存里的对象
			return cloneObject(e.getValue());
		}
	}
	/**
	 * 克隆对象
	 * @param obj
	 * @return
	 */
	private Object cloneObject(Object obj){
		ByteArrayOutputStream bos = null;
		ObjectOutputStream oos = null;
		ByteArrayInputStream bis = null;
		ObjectInputStream ois = null;
		try {
			bos = new ByteArrayOutputStream();
			oos = new ObjectOutputStream(bos);
			oos.writeObject(obj);
			
			bis = new ByteArrayInputStream(bos.toByteArray());
			ois = new ObjectInputStream(bis);
			return ois.readObject();
		}catch(NotSerializableException e1){
			log.warn(obj+" can't be clone");
			e1.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			try {
				if(ois != null)
				ois.close();
				if(bis != null)
				bis.close();
				if(oos != null)
				oos.close();
				if(bos != null)
				bos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return obj;
	}
	
	/**
	 * 构建缓存的key。
	 * 获得cacheKey的方法. key为:包名.类名.方法名 如:com.eclink.service.buscert.BusCertService.getBusCertList
	* @param targetName 类名
	* @param methodName 方法名
	* @param args 参数
	* @return String
	 */
	private String getCacheKey(String targetName, String methodName, Object[] args){
		StringBuilder sb = new StringBuilder();
		sb.append(targetName).append(".").append(methodName);
		if(!Common.isEmpty(args)){
			for (Object arg : args) {
				// 这里将参数克隆,防止直接修改传入的对象参数。
				// TODO 只判断了简单的map,和object[]这种特殊情况,具体情况视项目情况再完善
				Object o = cloneObject(arg);
				if(o instanceof Map){
					Map mapo = (Map)o;
					Set<String> keys = mapo.keySet();
					for (String key : keys) {
						Object keyValue = mapo.get(key);
						if(keyValue instanceof Object[]){
							mapo.put(key, convertObjectArray((Object[])keyValue));
						}
					}
				}
				if (o instanceof Object[]) {
					sb.append(".").append(convertObjectArray((Object[])o));
				}else{
					sb.append(".").append(o);
				}
			}
		}
		
		return sb.toString();
	}
	/**
	 * 将数组原始的toString()方法,转换成字符串
	 * @param objs
	 * @return
	 */
	public String convertObjectArray(Object[] objs){
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		for (Object obj : objs) {
			sb.append(obj).append(",");
		}
		sb.append("]");
		return sb.toString();
	}
	public void afterPropertiesSet() throws Exception {
		Assert.assertNotNull("Need a cache,pleace use setCache(cache) create it.", cache);
	}

}



更新缓存拦截器,MethodCacheAfterAdvice
package com.eclink.cache;

import java.lang.reflect.Method;
import java.util.List;

import net.sf.ehcache.Cache;

import org.apache.log4j.Logger;
import org.junit.Assert;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.beans.factory.InitializingBean;

import com.eclink.common.Common;

public class MethodCacheAfterAdvice implements AfterReturningAdvice,
		InitializingBean {
	private static final Logger log = Logger.getLogger(MethodCacheAfterAdvice.class);
	
	private Cache cache;
	private List<String> noFlushCacheMethod;
	
	
	public void setNoFlushCacheMethod(List<String> noFlushCacheMethod) {
		this.noFlushCacheMethod = noFlushCacheMethod;
	}

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

	/**
	 * 刷新缓存(在目标方法执行之后,执行该方法)
	 */

	public void afterReturning(Object returnValue, Method method,
			Object[] args, Object target) throws Throwable {
		String className = target.getClass().getName();
		String methodName = method.getName();
		
		// 排除不需要刷新缓存的方法
		boolean noFlushCache = false;
		if(!Common.isEmpty(noFlushCacheMethod)){
			String s = className +"."+methodName;
			for (String m : noFlushCacheMethod) {
				if(s.indexOf(m) != -1){
					noFlushCache = true;
					break;
				}
			}
		}
		if(!noFlushCache){
			List<String> cacheKeys = cache.getKeys();
			for (String cacheKey : cacheKeys) {
				if(cacheKey.startsWith(className)){
					cache.remove(cacheKey);
					log.debug("remove cache "+cacheKey);
				}
			}
		}
	}


	public void afterPropertiesSet() throws Exception {
		Assert.assertNotNull("Need a cache,pleace use setCache(cache) create it.", cache);
	}

}


spring 配置文件
	   	<bean id="defaultCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
	   		<property name="configLocation">
	   			<value>classpath:ehcache.xml</value>
	   		</property>
	   	</bean>
	   	
	   	<!-- defind cache factory and set cacheName -->
	   	<bean id="ehCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
	   		<property name="cacheManager" ref="defaultCacheManager" />
	   		<property name="cacheName">
	   			<value>FDOL2_CACHE</value>
	   		</property>
	   	</bean>
		<!-- find/create cache -->
		<bean id="methodCacheInterceptor" class="com.eclink.cache.MethodCacheInterceptor">
			<property name="cache" ref="ehCache" />
			<property name="noCacheMethod">
				<list>
					<value>getNextSerialNo</value>
					<value>getNextNo</value>
				</list>
			</property>
		</bean>
		<!-- flush cache -->
		<bean id="methodCacheAfterAdvice" class="com.eclink.cache.MethodCacheAfterAdvice">
			<property name="cache" ref="ehCache" />
			<property name="noFlushCacheMethod">
				<list>
					<value>NoFlushCache</value>
				</list>
			</property>
		</bean>
		
		<bean id="methodCachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
			<property name="advice" ref="methodCacheInterceptor" />
			<property name="patterns">
				<list>
					<value>com.eclink.service.*?\.find.*</value>
					<value>com.eclink.service.*?\.query.*</value>
					<value>com.eclink.service.*?\.select.*</value>
					<value>com.eclink.service.*?\.get.*</value>
				</list>
			</property>
		</bean>
		<bean id="methodCachePointCutAdvice" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
			<property name="advice" ref="methodCacheAfterAdvice" />
			<property name="patterns">
				<list>
					<value>com.eclink.service.*?\.save.*</value>
					<value>com.eclink.service.*?\.insert.*</value>
					<value>com.eclink.service.*?\.update.*</value>
					<value>com.eclink.service.*?\.delete.*</value>
					<value>com.eclink.service.*?\.cancel.*</value>
					<value>com.eclink.service.*?\.confirm.*</value>
				</list>
			</property>
		</bean>


ehcache缓存配置文件:ehcache.xml
    <diskStore path="java.io.tmpdir"/>

    <defaultCache
            maxElementsInMemory="1000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            diskSpoolBufferSizeMB="30"
            maxElementsOnDisk="10000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
            />

    <cache name="FDOL2_CACHE"
           maxElementsInMemory="1000"
           maxElementsOnDisk="10000"
           eternal="false"
           overflowToDisk="true"
           diskSpoolBufferSizeMB="20"
           timeToIdleSeconds="300000"
           timeToLiveSeconds="600000"
           memoryStoreEvictionPolicy="LFU"
            />
分享到:
评论

相关推荐

    spring + ehcache + redis两级缓存

    当我们谈论“Spring + Ehcache + Redis”两级缓存时,我们实际上是在讨论如何在Java环境中利用Spring框架来集成Ehcache作为本地缓存,并利用Redis作为分布式二级缓存,构建一个高效且可扩展的缓存解决方案。...

    spring+ehcache示例整合Demo

    Spring 和 Ehcache 是两个在Java开发中非常重要的框架。Spring 是一个全面的后端开发框架,提供了依赖注入、AOP(面向切面编程)、MVC(模型-视图-控制器)等特性,使得应用程序的构建变得更加简洁和模块化。Ehcache...

    spring+ehcache demo

    【Spring + Ehcache 整合应用详解】 在Java企业级开发中,缓存技术是提高系统性能的关键之一。Spring框架提供了对多种缓存机制的支持,其中包括Ehcache。本示例"spring+ehcache demo"将带你深入理解如何在Spring...

    Spring+Ehcache集成

    Ehcache作为一款流行的开源缓存解决方案,因其轻量级、高性能和易于集成的特点,常被广泛应用于Spring框架中。本篇文章将详细介绍如何在Spring项目中集成Ehcache,以及如何通过Spring的AOP(面向切面编程)实现方法...

    maven+spring+ehcache

    总的来说,这个压缩包文件提供了一个基础的Java Web项目模板,展示了如何整合Maven、Spring、Spring MVC和Ehcache来实现一个具备缓存功能的Web应用。开发者可以通过学习和修改这个实例,加深对这些技术的理解并应用...

    spring+ibatis+ehcache整合例子

    在IT行业中,Spring、iBatis和Ehcache是三个非常重要的开源框架,它们分别用于企业级应用的依赖注入、数据库操作和缓存管理。这个"spring+ibatis+ehcache整合例子"是一个完整的示例项目,展示了如何将这三个框架无缝...

    springMVC+mybatis+ehcache整合

    在Spring中整合Ehcache,可以通过Spring的缓存抽象进行配置,定义缓存注解如`@Cacheable`、`@CacheEvict`、`@CachePut`来控制缓存的存取和清除。Ehcache的配置文件(ehcache.xml)可以指定缓存的大小、存活时间和...

    ssh,struts+hibernate+spring+ehcache集成

    SSH(Struts、Hibernate、Spring)是Java Web开发中常用的一种技术栈,它结合了三个强大的框架,用于构建高效、可扩展的企业级应用程序。在这个集成中,Struts提供了MVC(Model-View-Controller)架构,Hibernate...

    spring+ehcache完整示例demo

    在IT行业中,Spring框架是Java领域最常用的轻量级应用框架之一,而Ehcache则是一种广泛使用的内存缓存系统,常与Spring搭配用于提升应用性能。本示例旨在通过一个完整的Spring集成Ehcache的Demo,帮助开发者理解如何...

    Spring+Hibernate+ehcache整合

    Spring、Hibernate和Ehcache是Java开发中常用的三个框架,它们在企业级应用开发中扮演着重要的角色。Spring是一个全面的后端应用框架,提供依赖注入、AOP(面向切面编程)、MVC(模型-视图-控制器)等特性;...

    Spring+EhCache缓存实例

    EhCache提供了一个简单易用的API,可以方便地集成到各种Java应用程序中,包括Spring框架。 **2. Spring对缓存的支持** Spring框架自3.1版本开始引入了统一的缓存抽象,支持多种缓存实现,其中包括EhCache。Spring...

    Ehcache(一): Spring + Ehcache开场白

    总的来说,Spring与Ehcache的结合使用,使得开发人员可以方便快捷地在应用中实现高效的缓存管理。通过合理的配置和使用,可以大大提高系统的响应速度,降低数据库的负载,同时还能提供良好的可扩展性和维护性。

    Spring+ehcache整合

    在IT行业中,Spring框架是Java企业级应用开发的首选,而Ehcache则是一款广泛使用的内存缓存系统,尤其在处理大数据量、高并发场景下,能够显著提升系统的响应速度和性能。本教程将深入探讨如何在Spring 4.1版本中...

    Spring+Acegi+ehcache安全框架常用jar包.rar

    在Java开发领域,Spring框架是应用最广泛的轻量级框架之一,它提供了全面的编程和配置模型,使得开发者能够创建出高效、灵活且可维护的系统。而Acegi Security(现在已经更名为Spring Security)是Spring生态体系中...

    Shopping商城系统是采用Java语言开发的多用户商城系统,使用Spring+JPA+Velocity+Ehcache

    tensorflow Shopping商城系统是采用Java语言开发的多用户商城系统,使用Spring+JPA+Velocity+Ehcache作为基础开发架构,应用SpringSecurity框架管理系统权限,结合UR.zip

    Spring + Ehcache 注解形式配置

    在IT行业中,Spring框架是Java领域最常用的轻量级应用框架之一,而Ehcache则是一种广泛使用的缓存解决方案。本文将深入探讨如何在Spring框架中通过注解方式配置Ehcache,以便优化应用程序的性能。 首先,让我们理解...

    SpringMVC+hibernate+spring+shiro+Ehcache所需jar包

    SpringMVC负责处理HTTP请求和视图展示,Spring作为核心框架进行依赖管理和事务控制,Hibernate则处理数据库操作,Shiro保障应用的安全性,而Ehcache则优化了数据访问性能。这些jar包的组合使得开发者能够快速地搭建...

    spring+ehcache

    在IT行业中,Spring框架是Java企业级应用开发的首选,而Ehcache则是一个流行的、高性能的缓存系统。本文将深入探讨如何将Ehcache与Spring进行整合,以提高应用程序的性能和效率,主要基于提供的"spring+ehcache"入门...

    spring Security+Ehcache+quartz+swagger2+Mysql5.6+springjdbc

    以SpringBoot 为中心,模块化开发系统,用户可以随意删减除权限...复用,组装性强主要应用技术:spring Security+Ehcache+quartz+swagger2+Mysql5.6+springjdbc+druid+spring social+spring session + layerui+vue.js

    Spring AOP+ehCache简单缓存系统解决方案

    在本篇【Spring AOP+ehCache简单缓存系统解决方案】中,我们将探讨如何利用Spring AOP(面向切面编程)和ehCache框架来构建一个高效、简单的缓存系统,以提升应用程序的性能。ehCache是一款流行的开源Java缓存库,它...

Global site tag (gtag.js) - Google Analytics