`
sdh88hf
  • 浏览: 67817 次
  • 性别: 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>

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

相关推荐

    网站性能优化 Web开发 JSP java

    页面缓存(局部缓存和全局缓存)(View,html代码) 缺点:不能做到实时更新 优点:比二级缓存性能更高 二级缓存(Model/业务层,domain对象)优点:可以做到实时更新 3.数据源 连接池放一些连接对象 4.SSI...

    工程硕士学位论文 基于Android+HTML5的移动Web项目高效开发探究

    鉴于市场上用户的手机型号、种类、屏幕分辨率等参差不齐,传统方式根据主流系统分别开发相应的系统耗时又耗力,为了高效开发并节约开发项目成本,本文采用Android+HTML5相结合的方式进行移动端Web系统的设计研发工作...

    基于 Java Web 项目的 SpringBoot 框架初始化模板,可基于此快速开发毕设等中小型项目

    基于 Java Web 项目的 SpringBoot 框架初始化模板,该模板整合了常用的框架,保证大家在此基础上能够快速开发自己的项目,该模板针对于后端启动开发小而精,本项目会由作者持续更新。 业务特性: 1、使用 Undertow ...

    sping springmvc mybatis框架的maven web项目,整合了log4j日志 redis缓存 quartz定时任务

    本人搭建的ssm框架的maven web项目,用maven管理项目的jar包,项目架构搭好,用的都是现阶段最新的jar包,整合了log4j日志,redis缓存,quartz定时任务,全局配置文件在代码中使用等,controller层/service层/bo层/dao层都...

    ASP.NET 2.0开发技术大全

    包括认识ASP.NET 2.0、ASP.NET 2.0网页语法、字符串与日期处理、Page对象、Response和Request对象、Application和Session对象、Server对象、Cookie对象、Cache对象、Global.asax全局程序集文件、标准服务器控件、...

    网页框架 基于HPSOCKET开发

    基于EFLASK Web框架优化魔改, 剔除了复杂的套壳流程 ,优化了代码。封装列表:。1.Mimalloc 内存管理库。2.队列操作。3.MMKV。4.HashMap。5.快速文本。6.快速字节集。7.键值表。8.正则表达式。9.Zlib压缩。10.对象工厂...

    ASP.NET 3.5 开发大全11-15

    第11章 用户控件和自定义控件 11.1 用户控件 11.1.1 什么是用户控件 11.1.2 编写一个简单的控件 11.1.3 将Web窗体转换成用户控件 11.2 自定义控件 11.2.1 实现自定义控件 11.2.2 复合自定义控件 11.3 用户控件和...

    Node.js 开发指南.pdf

    第5章 使用Node.js进行Web开发 79 5.1 准备工作 80 5.1.1 使用http模块 82 5.1.2 Express框架 83 5.2 快速开始 84 5.2.1 安装Express 84 5.2.2 建立工程 85 5.2.3 启动服务器 86 5.2.4 工程的结构...

    SpringBoot新手学习手册.pdf

    三、 Web开发 5 3.1、静态资源访问 5 3.2、全局捕获异常 5 3.3、渲染Web页面 6 3.4、使用Freemarker模板引擎渲染web视图 6 3.4.1、pom文件引入: 6 3.4.2、后台代码 6 3.4.3、前台代码 7 3.4.4、Freemarker...

    ASP.NET 2.0开发技术大全光盘

    Web Part部件、母版页、主题、sQL语句在ASP.NET中的应用、高性能数据处理技术、ADO.NET数据库技术、数据绑定控件、ASP.NET数据缓存技术、站点导航和导航控件、Web用户控件、创建ASP.NET服务器控件、 WebService基础...

    SpringBoot新手学习手册

    三、 Web开发 5 3.1、静态资源访问 5 3.2、渲染Web页面 5 3.3、使用Freemarker模板引擎渲染web视图 6 3.3.1、pom文件引入: 6 3.3.2、后台代码 6 3.3.3、前台代码 6 3.3.4、Freemarker其他用法 7 3.3.5、...

    Java 开发框架1

    引入条件构造器插件扩展自定义全局操作增删改查全局配置缓存和其他框架的整合逆向工程什么是MVC?请求与响应配置执行过程事务新功能Java WebJava Web前

    sping4.2.5 springmvc4.2.5 mybatis3.4框架(SSM)的maven web项目,整合了log4j redis quartz

    本人搭建的ssm框架的maven web项目,用maven管理项目的jar包,项目架构搭好,用的都是现阶段最新的jar包,整合了log4j日志,redis缓存,quartz定时任务,全局配置文件在代码中使用等,controller层/service层/bo层/dao层都...

    百度地图开发java源码-flutter_qinlinApp:Flutter实际开发常用工具类(全局提示,请求封装,常用窗帘动画及布局)

    实际开发常用工具类(全局提示,请求封装,token缓存,验证码倒计时、常用窗帘动画及布局) 1. Flutter 是什么? Flutter 是 Google 开源的 UI 工具包,帮助开发者通过一套代码库高效构建多平台精美应用, 支持移动...

    新浪阅读器的二次开发

    A:使用全局变量(省略一部分代码) private bool isfullscreen = false; private void toolStripButton15_Click(object sender, EventArgs e) { if (isfullscreen ==false ) { isfullscreen = true; panel1....

    SpaceBuilder v1.1 Build 080718 源码版.zip

    SpaceBuilder是一套基于Web2.0思想设计、采用asp.net2.0开发的社区门户产品。它同时也是一套Web2.0全面解决方案,包含:个人门户、博客、相册、网摘、文件、圈子、活动、消息中心、SNS等功能,可以根据客户需求任意 ...

    SpaceBuilder v1.1 Build 080718 安装版.zip

    SpaceBuilder是一套基于Web2.0思想设计、采用asp.net2.0开发的社区门户产品。它同时也是一套Web2.0全面解决方案,包含:个人门户、博客、相册、网摘、文件、圈子、活动、消息中心、SNS等功能,可以根据客户需求任意 ...

Global site tag (gtag.js) - Google Analytics