`
sdh88hf
  • 浏览: 69612 次
  • 性别: Icon_minigender_1
  • 来自: 绍兴
社区版块
存档分类
最新评论

Web开发学习11 全局缓存控制

 
阅读更多
缓存用的好可以减少数据库的压力,在大并发的情况下极大的提升服务器的性能,理论上缓存数据类型是按越接近用户端为最优先的,意思就是如果在web项目中满足业务需求的情况下优先备份html页面->业务处理层->数据获取层,备份html页面很常见,比如新闻中心的新闻详情页会事先根据录入的数据创建静态化页面,从而提高客户端访问速度.这种情况针对页面数据比较单一或者改动比较少的情况是比较好的,但如果改动多的话每次一改动页面中某个模块的数据就需要重新生成该页面那是很麻烦的,所以这种情况我们就需要降级缓存,把缓存做到service层,当用户端请求到达action的时候,调用各个service方法,如果service方法的返回数据被缓存了,那就从缓存中取就好了.今天我们主要介绍下ehcache的使用方式以及在项目架构中搭建全局缓存管理的功能.

我选择ehcache做为缓存框架的原因就是平时比较喜欢用hibernate,所以我是不需要为使用这个缓存框架导其他jar包的,如果你不是hibernate那你可能需要引入这些jar包
cglib-nodep-2.2.jar
ehcache-core-2.5.2.jar
ehcache-spring-annotations-1.2.0.jar
guava-13.0.1.jar
ehcache-terracotta-2.5.2.jar
slf4j-api-1.6.1.jar
slf4j-log4j12-1.6.1.jar
terracotta-toolkit-1.5-runtime-4.2.0.jar

首先添加一个ehcache.xml并在web.xml中配置加载
<?xml version="1.0" encoding="UTF-8"?>

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

	<!-- 指定缓存目录 -->
    <diskStore path="d:\\sdh\\ehcache" />

    <!-- 默认缓存
        maxEntriesLocalHeap :  堆内存中最大缓存对象数
        maxBytesLocalOffHeap :  堆内存最大占内存
        maxBytesLocalDisk  :  硬盘最大占内存
        maxEntriesLocalDisk :  硬盘中最大缓存对象数
        eternal  :  缓存是否永久有效
        timeToIdleSeconds  :  空闲多少时间将被销毁
        timeToLiveSeconds  :  创建起多少秒之后被销毁
        memoryStoreEvictionPolicy : LRU(Least Recently Used(最近最少使用))
        LFU(Less Frequently Used (最少使用)) FIFO(first in first out (先进先出))
    -->
    <defaultCache maxEntriesLocalHeap="10000000" maxBytesLocalOffHeap="30720" eternal="false"
        timeToIdleSeconds="1200000" timeToLiveSeconds="12000000" diskSpoolBufferSizeMB="30"
        maxEntriesLocalDisk="100000000" maxBytesLocalDisk="52428800" diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap" />
    </defaultCache>

    <!-- 针对框架对service层方法缓存 -->
    <cache name="serviceMethodCache" maxEntriesLocalHeap="10000"
        maxEntriesLocalDisk="100000" eternal="false" diskSpoolBufferSizeMB="50"
        timeToIdleSeconds="36000" timeToLiveSeconds="0"
        memoryStoreEvictionPolicy="LFU" transactionalMode="off">
        <persistence strategy="localTempSwap" />
    </cache>

    <!-- 永久缓存 -->
    <cache name="applicationCache" maxEntriesLocalHeap="10000" eternal="true"
        memoryStoreEvictionPolicy="LFU" />

</ehcache>

定义了三个缓存器,参数主要就是定义生命周期和大小限制,其中serviceMethodCache就是我们今天要用到的缓存器

来分析下我们需要完成的功能,当查询的service方法被调用前去查询当前方法返回值知否有被缓存,如果有返回缓存值,没有的话就继续调用当前方法并把结果做缓存处理,这里我们用spring拦截器去实现这个功能,spring的拦截器有类似代理的功效,他能在执行被拦截方法的前后自定义代码,看代码
package com.cn.sdh.common.intercepter;

import java.io.Serializable;

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

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.beanutils.PropertyUtils;
import org.springframework.beans.factory.InitializingBean;

import com.cn.sdh.common.Page;

public class EhcacheMethodIntercepter implements MethodInterceptor,
		InitializingBean {

	private Cache cache;
	
	@Override
	public void afterPropertiesSet() throws Exception {
		if(cache == null){
			throw new Exception("MethodCacheIntercepter set cache is null");
		}
	}

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		//被调用类名
		String targetName = invocation.getThis().getClass().getName();
		//被调用方法名
		String methodName = invocation.getMethod().getName();
		//方法传递的参数
		Object [] args = invocation.getArguments();
		
		//如果是分页
		Page np = null;
		if(args != null && args.length > 0){
			if(args[0] instanceof Page){
				np = (Page) args[0];
			}
		}
		
		//拼接key字符串
		String key = getKey(targetName, methodName, args);
		
		//从缓存中获取数据
		Element element = cache.get(key);
		
		//如果缓存中不存在
		if(element == null){
			//调用目标方法
			Object result = invocation.proceed();
			//把返回值缓存下来
			element = new Element(key, (Serializable)result);
			//element.setTimeToIdle(60 * 60 * 24);
			cache.put(element);
			
			//把分页数据缓存下来
			Element element2 = new Element(key+"_page", (Serializable)np);
			//element2.setTimeToIdle(60 * 60 * 24);
			cache.put(element2);
			
		}else if(np != null){
			//如果是分页的情况下,需要把之前缓存的分页信息还原回本次查询
			Object op = cache.get(key+"_page").getObjectValue();
			if(op != null){
				PropertyUtils.copyProperties(np, op);
			}else{
				cache.remove(key);
			}
		}
		return element.getObjectValue();
	}
	
	private String getKey(String targetName, String methodName, Object [] args){
		StringBuilder sr = new StringBuilder(targetName);
		sr.append(methodName);
		
		if(args != null && args.length > 0 ){
			for(Object v : args){
				sr.append(v);
			}
		}
		
		return sr.toString();
	}

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

}


我框架中一开始处理分页的方式是传递一个Page类的参数给dao层,然后dao层回去到总记录数会保存到这个page类中,因为类是引用类型,所以在调用方那边可以从这个参数page类中获取到本次分页条件的总记录数,但是方法级别的缓存值缓存返回值,所以要把这个page的参数也缓存下来,以便在后面从缓存中取结果集的时候把总记录数取到.其他就很简单了,通过被调用的类名方法名参数列表但生成一个key作为缓存的标识.

继续分析需求,被缓存的数据处理自己的生命周期外难道就不被销毁了吗,那肯定不是的,比如新闻一有改动就需要把新闻的缓存先删掉,保证下次读取新闻的时候会从数据库去取,所以我们需要做一个功能,当做删除新增更新的时候我们要把该模块的缓存数据都删掉,这个我们就要用spring的后置通知来解决了,看代码
package com.cn.sdh.common.intercepter;

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

import net.sf.ehcache.Cache;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.beans.factory.InitializingBean;

public class EhcacheMethodReturnAdvice implements AfterReturningAdvice,
		InitializingBean {

	private Cache cache;
	
	@Override
	public void afterPropertiesSet() throws Exception {
		if(cache == null){
			throw new Exception("MethodCacheIntercepter set cache is null");
		}
	}

	@Override
	public void afterReturning(Object arg0, Method arg1, Object[] arg2,
			Object arg3) throws Throwable {
		String className = arg3.getClass().getName();
		
		@SuppressWarnings("rawtypes")
		List keyList = cache.getKeys();
		for(int i = 0; i<keyList.size(); i++){
			String key = String.valueOf(keyList.get(i));
			if(key.startsWith(className)){
				cache.remove(key);
			}
		}
		
	}

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

非常的简单,在缓存中把当前模块的缓存项全部删除

写好这两个方法以后接下去就是配置文件了
<?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
           default-autowire="byName">
       
    <bean id="defaultCacheManage" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
    </bean>
    
    <bean id="serviceMethodCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
        <property name="cacheManager">
           <ref local="defaultCacheManage"/>
        </property>
        <property name="cacheName">
            <value>serviceMethodCache</value>
        </property>
    </bean>	
    
    <bean id="ehcacheMethodIntercepter" class="com.cn.sdh.common.intercepter.EhcacheMethodIntercepter">
        <property name="cache">
            <ref local="serviceMethodCache"/>
        </property>
    </bean>
    
    <bean id="ehcacheMethodReturnAdvice" class="com.cn.sdh.common.intercepter.EhcacheMethodReturnAdvice">
        <property name="cache">
            <ref bean="serviceMethodCache"/>
        </property>
    </bean>
    
    <bean id="ehcacheMethodIntercepterPointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice">
            <ref local="ehcacheMethodIntercepter"/>
        </property>
        <property name="patterns">
            <list>
                <value>.*Service.*query*</value>
                <value>.*Service.*find*</value>
            </list>
        </property>
    </bean>
    
    <bean id="ehcacheMethodReturnAdvicePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice">
            <ref local="ehcacheMethodReturnAdvice"/>
        </property>
        <property name="patterns">
            <list>
                <value>.*Service.*delete.*</value>
                <value>.*Service.*save.*</value>
            </list>
        </property>
         
    </bean>
    
    <!-- 激活自动代理功能 -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
   
</beans>

配置好切点,开始自动代理就能完成全局缓存了.
分享到:
评论

相关推荐

    JAVA_WEB_缓存技术

    在Java Web开发中,缓存技术是提高应用程序性能的关键手段之一。它通过存储常用的数据或计算结果,避免了每次请求时都直接从数据库或其他慢速存储中获取数据,从而显著提升了响应速度。在这个场景中,我们看到两个...

    C#读取web.config配置,建立高速缓存机制

    C#作为.NET平台上的主要开发语言,提供了丰富的API来读取web.config文件中的配置信息,并且可以通过建立高速缓存机制来优化应用程序的性能。 首先,Web.config配置文件的作用是给.NET应用程序提供一个统一的配置...

    显示所有缓存 清除所有缓存 Asp.net(C#)

    在Web开发中,缓存技术被广泛应用于提高应用程序的性能。通过缓存,我们可以存储经常访问的数据或计算结果,减少数据库查询次数,从而加快响应速度。本文将详细介绍如何在ASP.NET (C#) 应用程序中实现显示所有缓存...

    Django Web开发指南

    本书由Jeff Forcier、Paul Bissex与Wesley Chun共同编写,三位作者都是在Python及Web开发领域拥有丰富经验的专家。 #### 二、主要内容 本书主要介绍了如何使用Django框架来构建高效的Web应用程序。Django是一个用...

    MVC Web开发学习实录-配套源码.zip

    **MVC Web开发学习实录** 是一本深入探讨Web应用构建技术的书籍,重点在于Model-View-Controller(MVC)架构模式的应用。MVC是一种软件设计模式,它将应用程序的业务逻辑、用户界面和数据访问分离开来,使得各部分...

    PHP 缓存详情机制

    在现代Web开发中,缓存技术扮演着极其重要的角色。合理的缓存策略不仅能显著提升应用性能,还能改善用户体验。对于PHP开发者而言,深入理解PHP缓存机制对于构建高效稳定的Web应用至关重要。本文将围绕PHP缓存机制...

    Java Web开发实战宝典 第18章

    这些知识点构成了Java Web开发的关键组成部分,通过学习和实践,开发者能够构建出高效、稳定且用户友好的Web应用。王国辉等作者的这本书为读者提供了全面的指导,帮助他们掌握这些核心技术,并应用于实际项目中。

    Django Web开发指南 python

    **Django Web开发指南**是针对使用Python进行Web应用程序开发的专业资源,主要聚焦于Django这一强大的开源Web框架。Django以其“ batteries included ”的理念,提供了丰富的功能,旨在简化Web开发过程,让开发者...

    ASP.NET 2.0 Web开发入门指南

    ASP.NET 2.0是微软推出的一个用于构建Web...通过深入学习以上知识点,并结合“ASP.NET 2.0 Web开发入门指南”资源下载,初学者将能够逐步掌握ASP.NET 2.0 Web开发的基础,从而能够独立开发出功能完善的Web应用程序。

    Web数据缓存大全

    这种机制包括Page Output Cache(页面输出缓存)、Data Cache(数据缓存)和HttpRuntime.Cache(全局应用程序缓存)等,可以显著提高Web应用的性能。 2. **Page Output Cache**:这是ASP.NET用于缓存整个页面或页面...

    php+ajax web2.0编程技术与项目开发大全中的FYblog可安装代码

    《PHP+Ajax Web2.0编程技术与项目开发大全》是一部深入探讨现代Web开发的著作,其中涵盖...通过研究这个代码库,不仅可以学习到基本的编程技巧,还能了解到如何将这些技术应用到实际项目中,以满足现代Web开发的需求。

    asp.net缓存 缓存

    ASP.NET缓存是微软开发的Web应用程序框架中的一个重要特性,用于提高网站性能和减少服务器负载。缓存技术在.NET框架中扮演着至关重要的角色,它能够存储数据以便快速访问,从而减少对数据库或其他慢速资源的依赖。在...

    Grails技术精解与web开发实践2-10章

    通过学习这些章节,读者不仅可以熟练掌握Grails的开发技巧,还能理解其背后的设计理念,从而在实际项目中发挥Grails的优势,高效地进行Web开发。这本书对于渴望深入了解Grails并提升Web开发技能的人来说,无疑是一份...

    springweb电子商城开发源代码

    `WEB-INF`目录是Java Web应用的标准结构部分,通常存放`web.xml`配置文件,该文件定义了Web应用的全局配置,包括Servlet、Filter和Listener等。此外,`WEB-INF`下还可能包含自定义的JSP页面、标签库(taglib)等资源...

    Java Web 整合开发

    总之,Java Web整合开发涵盖了Web基础、Spring、Struts2和Hibernate等多个知识点,这些内容对于想要深入学习Java Web开发的程序员来说至关重要。通过理论学习和实际项目经验的积累,开发者能够掌握构建复杂Web应用的...

    缓存经典例子

    在IT行业中,缓存是一种非常重要的技术,尤其是在Web开发领域,如ASP.NET。它能够显著提升网站性能,减少服务器负载,提高用户体验。本教程将通过一个经典的实例来深入讲解ASP.NET中的缓存机制。 首先,我们需要...

    Web开发+java+ssh框架

    ### Web开发+java+ssh框架知识点详述 ...总之,Web开发+Java+SSH框架涵盖了从前端设计到后端逻辑处理、数据库交互以及框架集成等多个方面,对于希望深入学习Web开发技术的人员来说,理解和掌握上述知识点是十分必要的。

    Python之web开发利刃2.zip

    通过深入学习和实践这些内容,你将能掌握Python Web开发的核心技能,并具备独立开发Web应用的能力。无论是初学者还是有经验的开发者,这个压缩包都能提供宝贵的资源,助你在Python Web开发领域更进一步。

    SSH使用缓存例子

    SSH(Struts2 + Spring + Hibernate)是一个经典的Java Web开发框架,它整合了Struts2的MVC设计模式、Spring的依赖注入与事务管理以及Hibernate的对象关系映射功能,为开发者提供了一套高效的开发工具集。...

Global site tag (gtag.js) - Google Analytics