`
cjnetwork
  • 浏览: 179526 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论

java基于filter的应用缓存框架

阅读更多
java web 基于filter的缓存框架







目标、解决的问题:
浏览器客户端向服务器发起许多参数相同的请求,在服务器端的处理之后,在相同参数的情况下,返回的结果一致的情况下,使用该缓存框架,可以提高web服务器的性能。
在java的web开发的时候,有许多请求,在后台处理之后,可能返回相同的数据到浏览器端,或者在一定时间内,返回的结果可能都是一样的。因此可以将执行后的返回结果缓存起来,再下一次相同请求,相同参数的情况向可以直接从缓存中获取到处理结果。例如在一个用户管理系统中,普通的操作有添加、修改、删除、查询4个操作,在执行查询操作的时候,实际上,只要数据库中数据没有发生变化,则返回到浏览器端的数据都是一样的,因此可以给用户的查询增加缓存。
第一步:如下代码:
public String query() {
		String result = ERROR;
		try{
			List<User> allUser = userService.query();
			ServletActionContext.getRequest().setAttribute("allUser", allUser);
		}catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

代码中,使用userService从数据库中查询到用户列表,则该用户列表,当数据库中数据没有变化的时候,浏览器端访问该地址都将获取到相同的结果,因此可以将List<User> allUser缓存起来,等待下一次执行该请求的时候,直接从缓存中获取到用户列表,然后跳转到jsp页面做显示。但这种方式,对于单个的方法,需要在业务逻辑增添加代码,而且若这样的需要缓存的地址较多,则是一个比较繁琐的过程,维护多个地方的东西,也不容易。这种方法不是最理想的。考虑到web的请求都是request/response结构的,即都是浏览器端发起请求,由java的web后台处理,完成之后返回浏览器端一个response对象,因此可以直接将response中所有的内容进行缓存,下一次请求的时候直接将上次一次的处理结果中response的内容,设置到新的一次请求返回的response中,这一步可以在更高一层统一完成(filter层)。
查找HttpServletResponse的api后,发现没有直接从response中获取到返回内容的方法,因此采用代理的方式,自己写一个HttpServletResponseProxy,该类代理了所有HttpServletResponse的普通方法,并截获对应的getWriter()、getServletOutputStream()方法,到这一步骤之后,仍旧不能获取到在整个filter业务处理的过程中,往response中写入的内容,因此还需要增加对获取到的Writer的代理、ServletOutputStream的代理,新增加的两个代理PrintWriterProxy、ServletOutputStreamProxy,中便可以获取到写入response的内容,在代理写入方法的时候,写入的同时,将写入的内容copy一份,以便后续使用。那么在第一次请求的时候,所有写入到response的内容就可以获取到,则在第二次请求的时候,可以讲上一次的response中的内容取出并返回给浏览器端。
增加FilterCache.java,可以通过uri地址,判断该地址是否已经请求过,并且缓存尚未过期,没有过期则将缓存内容取出并返回。
第二步:完成到如上步骤,只是完成了简单的缓存,
public String query() {
		String result = ERROR;
		try{
			String username = ServletActionContext.getRequest().getParameter("username");
			List<User> allUser = userService.query(username);
			ServletActionContext.getRequest().setAttribute("allUser", allUser);
		}catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

在该段代码中,需要从request中获取到用户名作为查询条件,那么就需要把request中参数考虑到缓存存储的键的生成策略中,而不仅仅只使用请求的地址uri作为键的生成策略,考虑到request中请求的参数很多,为了不时缓存的键过长,需要将request中所有的参数拼接成一个字符串,并同uri地址连接,形成如同"userAction!query.action?username=a"这样的字符串,然后将该字符串进行md5编码,那么就可以得到一个定长且不是太长的字符串作为缓存的键。在拼接字符串的过程中,"userAction!query.action?username=a&groupname=b"和"userAction!query.action?groupname=b&username=a"其实是一样的,因此对从request中获取参数并拼接字符串的过程中,完成之后还需要对参数进行排序,这个可以使用key的字符串大小(英文排序)来确定,将以上可以遇到的两种情况排序后成为一种,然后才可以避免相同地址请求、相同参数的情况下导致缓键生成不同,而实际是相同的情况下,缓存了两个不同的结果的情况。
同样,session中的参数也需要拼接到请求参数中,并影响缓存键的生成。例如:
public String query() {
		String result = ERROR;
		try{
			String username = ServletActionContext.getRequest().getSession().getAttribute("username").toString();
			List<User> allUser = userService.query(username);
			ServletActionContext.getRequest().setAttribute("allUser", allUser);
		}catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

第三步:request、session中的参数,有的时候会影响业务逻辑执行的结果,有的时候不会,因此可以将是否影响作为配置项,在缓存策略配置文件中进行配置,那么,各个不同的请求地址的缓存键生成策略部同,可以增加缓存框架的易用性。
第四步:考虑到如果当一个请求正在执行,还没有执行完成,另一个相同请求地址、参数、session参数的请求也请求到服务器端,那么这种情况,将会导致缓存没有起到作用,两次请求都会被web系统执行,消耗了系统资源。因此增加一个同步机制,相同请求地址、参数、session参数即缓存键相同时,后到达的请求,将以线程同步的方式,等待上次执行结果完成,而并不直接调用业务逻辑,等待从缓存中获取到结果。如此,可以在系统缓存到期的情况下,有效防止由于缓存过期引起的性能下降问题。
第五步:在最先提到用户的增加、修改、删除,都会影响到查询的结果。那么还应该设置缓存击穿策略,即当用户增加的时候,击穿查询的缓存结果,当执行增加用户后,上一次的查询结果就失效了,当再次有查询请求道web服务器的时候,将不再从缓存中获取结果,而是再次执行业务逻辑,完成之后将结果缓存。同样用户修改、删除之后也会击穿用户查询的缓存。





使用方式:
1、将jar包和依赖jar包copy到classpath路径中
2、在web.xml中增加缓存过滤器
<!-- 缓存过滤器  -->
	<filter>
		<filter-name>cacheFilter</filter-name>
		<filter-class>
			com.cjnetwork.cache.filter.CacheFilter
		</filter-class>
		<init-param>
			<param-name>configFileLocation</param-name>		<!-- 缓存策略配置文件地址,默认为cache.xml  -->
			<param-value></param-value>
		</init-param>
		<init-param>
			<param-name>requestUriIncludePattern</param-name>	<!-- 缓存过滤器,需要处理的请求的地址的正则表达式  -->
			<param-value>.*?!.*?</param-value>
		</init-param>
		<init-param>
			<param-name>requestUriExcludePattern</param-name>	<!-- 缓存过滤器,需要排除的请求的地址的正则表达式  -->
			<param-value></param-value>
		</init-param>
		<init-param>
			<param-name>xmlReloadable</param-name>	<!-- 策略文件是否为重新导入模式,即当配置文件变化的时候,不需要重新启动应用程序,缓存框架会自动检测到,该功能在开发调制阶段非常有用(推荐在生产环境设置为false)  -->
			<param-value>true</param-value>  
		</init-param>
		<init-param>
			<param-name>cacheProvider</param-name>		<!-- 缓存提供者,可以自定义缓存数据存放方式(内存、其他KeyValue缓存框架等)  -->
			<param-value>com.cjnetwork.cache.provider.SimpleMemeryCacheProvider</param-value>
		</init-param>
	</filter>

3、将filter过滤配置到真正执行业务逻辑的filter之前,如struts框架中,将缓存filter配置到struts的filter之前
<filter-mapping>
		<filter-name>cacheFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

4、修改缓存策略文件cache.xml,该文件可以有filter定义中的初始化参数修改,可以是其他文件名
里面的具体配置参数,请直接查看配置文件中的注释或查看缓存策略配置说明章节。







缓存策略配置说明
通过修改该配置文件,可以调整缓存框架的性能,默认文件为cache.xml文件。
1、修改注解监控的包
<annotationPackage>		<!-- 注解所在的包 -->
		<package uriPrefix="" uriSeperator="!" uriSuffix=".action">com.cjnetwork.gis.action</package>
	</annotationPackage>

annotationPackage节点定义系统中需要扫描的包,在这里设置之后,可以通过注解@Cache完成缓存的配置。节点内的package节点可以定义多个,监听多个包中的注解。
package节点中:
uriPrefix:uri的前缀
uriSeperator:类与方法的分隔符
uriSuffix:uri的后缀

2、配置默认的缓存策略
<defaultCache cacheable="true" cacheTime="180">	<!-- cacheable:默认是否缓存true/false 	cacheTime:默认缓存时间(秒)-->
		<keyFromRequestIncludePattern></keyFromRequestIncludePattern>	<!-- 可存在多个,request的请求参数中,需要包含在缓存主键生成中,不配置表示请求中所有参数都要包含 -->
		<keyFromRequestExcludePattern></keyFromRequestExcludePattern>	<!-- 可存在多个,request的请求参数中,需要从缓存主键生成中排除,不配置表示请求中所有参数都不排除(包含) -->
		<keyValuePairFromRequestExclude>page=1</keyValuePairFromRequestExclude>	<!-- 可存在多个,request的请求参数中,需要从缓存主键生成中排除的特殊键值对,例如在请求某个查询的时候,有page=1的参数和不带该参数的查询,其结果应该是一样的,不配置表示请求中所有参数都要包含 -->
		<keyValuePairFromRequestExclude>pageSize=10</keyValuePairFromRequestExclude>	<!-- 可存在多个,request的请求参数中,需要从缓存主键生成中排除的特殊键值对,例如在请求某个查询的时候,有page=1的参数和不带该参数的查询,其结果应该是一样的,不配置表示请求中所有参数都要包含 -->
		<keyFromSessionIncludePattern></keyFromSessionIncludePattern>	<!-- 可存在多个,session的参数中,需要包含在缓存主键生成中,不配置表示请求中所有参数都要包含 -->
		<keyFromSessionExcludePattern></keyFromSessionExcludePattern>	<!-- 可存在多个,session的参数中,需要从缓存主键生成中排除,不配置表示请求中所有参数都不排除(包含) -->
		<keyValuePairFromSessionExclude></keyValuePairFromSessionExclude>	<!-- 可存在多个,request的请求参数中,需要从缓存主键生成中排除的特殊键值对,例如在请求某个查询的时候,有page=1的参数和不带该参数的查询,其结果应该是一样的,不配置表示请求中所有参数都要包含 -->
	</defaultCache>


3、修改特殊请求uri的缓存策略
<cache uri="testAction!test.action" cacheable="true" cacheTime="180">	<!-- cacheable:是否缓存true/false 	cacheTime:缓存时间(秒)-->
		<keyFromRequestIncludePattern></keyFromRequestIncludePattern>	<!-- 可存在多个,request的请求参数中,需要包含在缓存主键生成中,不配置表示请求中所有参数都要包含 -->
		<keyFromRequestExcludePattern></keyFromRequestExcludePattern>	<!-- 可存在多个,request的请求参数中,需要从缓存主键生成中排除,不配置表示请求中所有参数都不排除(不包含) -->
		<keyValuePairFromRequestExclude>page=1</keyValuePairFromRequestExclude>	<!-- 可存在多个,request的请求参数中,需要从缓存主键生成中排除的特殊键值对,例如在请求某个查询的时候,有page=1的参数和不带该参数的查询,其结果应该是一样的,不配置表示请求中所有参数都要包含 -->
		<keyValuePairFromRequestExclude>pageSize=10</keyValuePairFromRequestExclude>	<!-- 可存在多个,request的请求参数中,需要从缓存主键生成中排除的特殊键值对,例如在请求某个查询的时候,有page=1的参数和不带该参数的查询,其结果应该是一样的,不配置表示请求中所有参数都要包含 -->
		<keyFromSessionIncludePattern></keyFromSessionIncludePattern>	<!-- 可存在多个,session的参数中,需要包含在缓存主键生成中,不配置表示请求中所有参数都要包含 -->
		<keyFromSessionExcludePattern></keyFromSessionExcludePattern>	<!-- 可存在多个,session的参数中,需要从缓存主键生成中排除,不配置表示请求中所有参数都不排除(不包含) -->
		<keyValuePairFromSessionExclude></keyValuePairFromSessionExclude>	<!-- 可存在多个,session的请求参数中,需要从缓存主键生成中排除的特殊键值对,例如在请求某个查询的时候,有page=1的参数和不带该参数的查询,其结果应该是一样的,不配置表示请求中所有参数都要包含 -->
		<effects>
			<effect uri="testAction!test1.action" />	<!-- 可存在多个,缓存击穿地址,表示当目前uri地址testAction!test.action如果真正执行,将击穿uri="testAction!test1.action在系统中的缓存 -->
			<effectBy uri="testAction!test2.action" />	<!-- 可存在多个,缓存击穿地址,表示当testAction!tes2t.action如果真正执行,将击穿目前uri地址testAction!test.action在系统中的缓存 -->
		<effects>
	</cache>


4、注解配置方式(可选)
如果需要使用注解配置,则需要完成配置1中的配置,设置好相关的属性
@com.cjnetwork.cache.annotation.Cache具有如下属性
uri:请求的地址
cacheable:是否缓存true/false
cacheTime:缓存时间
keyFromRequestIncludePattern:request的请求参数中,需要包含在缓存主键生成中,不配置表示请求中所有参数都要包含
keyFromRequestExcludePattern:request的请求参数中,需要从缓存主键生成中排除,不配置表示请求中所有参数都不排除(不包含)
keyValuePairFromRequestExclude:request的请求参数中,需要从缓存主键生成中排除的特殊键值对,例如在请求某个查询的时候,有page=1的参数和不带该参数的查询,其结果应该是一样的,不配置表示请求中所有参数都要包含
keyFromSessionIncludePattern:session的参数中,需要包含在缓存主键生成中,不配置表示请求中所有参数都要包含
keyFromSessionExcludePattern:session的参数中,需要从缓存主键生成中排除,不配置表示请求中所有参数都不排除(不包含)
keyValuePairFromSessionExclude:可存在多个,session的请求参数中,需要从缓存主键生成中排除的特殊键值对,例如在请求某个查询的时候,有page=1的参数和不带该参数的查询,其结果应该是一样的,不配置表示请求中所有参数都要包含
effect:缓存击穿地址
effectBy:被其他uri地址击穿,其他地址将影响该地址的其他的地址









修改记录:
2012-08-10 cjnetwork
FilterCache-V1.0.1-realease.jar
1、修正相同请求地址,不同参数之间数据不同,但获取到相同结果bug
2、修正缓存测量文件中,无注解配置项是初始化异常

2012-05-17 cjnetwork
FilterCache-V1.0.0-realease.jar
1、完成第一个版本,通过配置能够完成缓存功能,正确配置缓存参数,可以提高web可访问性数倍;
2、该版本没有缓存击穿功能,下一版本将实现该功能;
  • 大小: 45.9 KB
分享到:
评论
1 楼 coldrain2014 2014-11-18  
更多html、js、php、java教程,请关注http://www.code1314.com/

相关推荐

    java自学===Filter类的应用,网站数量统计

    在本篇博客“java自学===Filter类的应用,网站数量统计”中,作者可能探讨了如何使用Filter来实现网站访问量的统计功能。 首先,Filter类位于javax.servlet包中,它是Servlet API的一部分,主要用于增强Web应用程序...

    基于SpringBoot+Layui搭建的学生管理系统,融合shiro安全框架和Ehcache缓存框架.zip

    本项目"基于SpringBoot+Layui搭建的学生管理系统",结合了Shiro安全框架和Ehcache缓存框架,为学生信息管理提供了便捷、安全的解决方案。以下是关于这些技术及如何整合的详细阐述。 首先,SpringBoot是Spring框架的...

    Java基于Redis实现附近的人Demo

    这个“Java基于Redis实现附近的人Demo”项目使用了Spring Boot框架,这是一种轻量级、易于使用的Java开发框架,能够快速构建微服务应用。Redis则是一个高性能的键值存储系统,常用于缓存和实时数据操作,对于处理...

    基于Struts 框架的BBS论坛系统

    Struts框架是一个强大的MVC(Model-View-Controller)设计模式的实现,广泛应用于Java Web应用的开发。在本项目“基于Struts框架的BBS论坛系统”中,开发者利用了Struts的强大功能来构建了一个功能完备的在线讨论...

    基于java的企业级应用开发:拦截器.ppt

    在Java企业级应用开发中,Spring MVC框架提供了一种名为拦截器(Interceptor)的功能,它与Servlet中的过滤器(Filter)类似,但有其独特的用法和功能。拦截器主要用于在用户请求到达控制器处理逻辑之前或之后进行...

    基于OSCache的页面缓存

    OSCache是开源的Java缓存框架,能够帮助开发者实现高效的页面和数据缓存,从而降低数据库的访问压力,提高应用的响应速度。 一、缓存整个页面 OSCache组件提供的`CacheFilter`是一个关键元素,它能对整个动态页面...

    ServletEx2 Java B/S应用开发技术框架 (ServletEx2 1.0)

    ServletEx2是一个基于Java的B/S(Browser/Server)应用开发技术框架,版本为1.0。这个框架专为简化Web应用程序的构建而设计,它提供了丰富的功能和工具,帮助开发者快速开发出高效、可扩展的Web服务。下面将详细阐述...

    【Java毕业设计】基于java web技术的毕业设计商城项目。.zip

    该项目是一个基于Java Web技术的毕业设计,主要涵盖了Java编程语言、Web开发框架、数据库管理和前端交互等多个方面的知识点。下面将详细解析这些关键领域的技术及其在实际应用中的作用。 1. **Java编程语言**:Java...

    基于MVC的Java Web设计与开发源代码(后面的)

    在Java Web开发中,Model-...总的来说,基于MVC的Java Web设计与开发通过分离关注点,提高了代码的可读性和可维护性,同时利用成熟的框架简化了开发流程。理解并熟练掌握这一模式,对于Java Web开发者来说至关重要。

    java dwr 框架源码

    Java DWR(Direct Web Remoting)框架是一种在Web应用程序中实现AJAX(Asynchronous JavaScript and XML)交互的技术。它允许JavaScript在客户端与服务器端的Java对象进行直接通信,从而实现页面的部分更新,提高...

    基于Java设计的网上商城系统(JSP+MYSQL)源码.zip

    《基于Java设计的网上商城系统:JSP与MYSQL的整合应用》 在互联网技术日新月异的今天,网上商城已经成为电商行业的主流形式。本文将深入探讨一个基于Java设计的网上商城系统,该系统利用了JSP(Java Server Pages)...

    基于Java的源码-java开源论坛系统 jeebbs v7.0 源码包.zip

    【基于Java的源码-java开源论坛系统 jeebbs v7.0 源码包.zip】是一款基于Java编程语言开发的开源论坛系统,专为技术爱好者和开发者提供了一个交流平台。该系统的版本号为v7.0,意味着它经过多次迭代与优化,具备了...

    java程序员之路—学习框架

    【部分内容】: 这个学习框架为java程序员提供了一个逐步深入的路线图,涵盖了从J2SE(Java标准版)的基础到J2EE(Java企业版)的高级框架应用。以下将详细介绍各个阶段的学习内容和相关项目实践。 ### 第一阶段:...

    基于JSP的java网上招标系统

    【基于JSP的Java网上招标系统】是一种利用Java技术实现的网络应用,旨在提供一个高效、安全、透明的招标流程。这种系统通常包括了招标公告发布、供应商报名、投标文件上传、在线评审、中标公示等多个功能模块,为...

    JAVA企业面试真题(框架部分)

    - Struts是一个基于MVC模式的Java Web应用框架,它简化了Web应用程序的开发过程。 - **配置与初始化**:在使用Struts时,首先需要在web.xml中配置Filter,这是Struts框架初始化的关键步骤之一。此外,还需要定义...

    Filter

    4. **Filter应用场景**:Filter可以用于日志记录、权限验证、字符编码转换、GZIP压缩、缓存控制等多种场景。 5. **源码分析**:博客可能涉及到对Filter的源码分析,例如分析`javax.servlet.Filter`接口和相关的实现...

    java SSH三层框架web开发-旅游网

    Java SSH 三层框架是Java Web开发中常用的架构模式,它由Spring、Struts和Hibernate三个开源框架组合而成,为开发者提供了高效、灵活且强大的应用程序构建工具。本项目是基于SSH框架实现的一个旅游网应用,旨在展示...

    基于Java Web+ssm+vue的线上办公管理系统.zip

    2. Spring框架:Spring是Java企业级应用的核心框架,提供依赖注入(DI)和面向切面编程(AOP)等功能,极大地简化了企业级应用的开发。SpringMVC是Spring框架的一部分,用于处理HTTP请求和响应,实现Model-View-...

    SSH框架配置-JAVA框架

    SSH框架,全称为Struts2、Spring和Hibernate的组合,是一种经典的Java Web开发框架,用于构建企业级的、模块化的、可扩展的应用程序。SSH框架的配置涉及到三个核心组件的集成,分别是Struts2作为MVC(模型-视图-控制...

Global site tag (gtag.js) - Google Analytics