Spring4 整合EhCache实现页面缓存 零配置
2017-02-22 13:28
555 查看
前言
本文通过spring4 以java配置类方式 整合EhCache来实现页面整体缓存及页面局部缓存。同时提供源码。因为使用了零配置,所以要求tomcat7以上的版本。原理是添加拦截器,在请求从用户浏览器到controller之间拦截直接返回数据,减轻服务器的压力,也加快了访问。
页面缓存介绍
缓存中的元素是被压缩过的,如果客户浏览器支持压缩的话,filter会直接返回压缩过的流,这样节省了带宽,把解压的工作交给了客户浏览器,如果客户的浏览器不支持gzip ,那么filter 会把缓存的元素拿出来解压后再返回给客户浏览器。ehcache-web这个包中给我们提供了一些filter来处理页面缓存。如下图:
在这里介绍SimplePageCachingFilter和SimplePageFragmentCachingFilter。分别对应页面整体缓存和页面局部缓存,这两个类都继承CachingFilter,并且各自实现了CachingFilter中calculateKey()方法。该方法就是用来计算保存在缓存中的key。这两个类计算key的方式基本都是获取请求时的URI及后面的查询字符串作为key,不过SimplePageCachingFilter多了一个请求方法,所以不依赖于主机名和端口号。以下是SimplePageCachingFilter的calculateKey()方法
protected String calculateKey(HttpServletRequest httpRequest) { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(httpRequest.getMethod()).append(httpRequest.getRequestURI()).append(httpRequest.getQueryString()); String key = stringBuffer.toString(); return key; }
SimplePageFragmentCachingFilter的calculateKey()方法如下:
protected String calculateKey(HttpServletRequest httpRequest) { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(httpRequest.getRequestURI()).append(httpRequest.getQueryString()); String key = stringBuffer.toString(); return key; }
有必要的话,可以自己实现calculateKey()方法来计算key。比如ajax访问的时候有些会在后面的参数添加时间戳,这样会导致计算的key每次都不一样,所以缓存也就没有意义了。不过本文直接使用SimplePageCachingFilter和SimplePageFragmentCachingFilter。
maven 配置
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.test</groupId> <artifactId>ehcache-web</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <properties> <!-- spring版本号 --> <spring.version>4.3.5.RELEASE</spring.version> <junit.version>4.12</junit.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!-- tomcat jstl --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.3</version> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> <!-- ehcache 相关依赖 --> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.7.5</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache-web</artifactId> <version>2.0.4</version> </dependency> <!-- 日志文件管理包 --> <!--ehcache依赖slf4j--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.18</version> </dependency> <!--ehcache依赖slf4j--> <!--slf4j需要log4j--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.18</version> </dependency> <!--slf4j需要log4j--> <!--log4j--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.5</version> </dependency> <!--log4j--> </dependencies> </project>
ehcache.xml 配置
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="false" monitoring="autodetect" dynamicConfig="true"> <!-- diskStore :指定数据存储位置,可指定磁盘中的文件夹位置 <diskStore path="E:/cachetmpdir"/> defaultCache : 默认的管理策略 以下属性是必须的: name: Cache的名称,必须是唯一的(ehcache会把这个cache放到HashMap里)。maxElementsInMemory:在内存中缓存的element的最大数目。 maxElementsOnDisk:在磁盘上缓存的element的最大数目,默认值为0,表示不限制。 eternal:设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断。 overflowToDisk: 如果内存中数据超过内存限制,是否要缓存到磁盘上。 以下属性是可选的: timeToIdleSeconds: 对象空闲时间,指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直可以访问。 timeToLiveSeconds: 对象存活时间,指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值0,表示一直可以访问。 diskPersistent: 是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false。 diskExpiryThreadIntervalSeconds: 对象检测线程运行时间间隔。标识对象状态的线程多长时间运行一次。 diskSpoolBufferSizeMB: DiskStore使用的磁盘大小,默认值30MB。每个cache使用各自的DiskStore。 memoryStoreEvictionPolicy: 如果内存中数据超过内存限制,向磁盘缓存时的策略。默认值LRU,可选FIFO、LFU。 缓存的3 种清空策略 : FIFO ,first in first out (先进先出). LFU , Less Frequently Used (最少使用).意思是一直以来最少被使用的。缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存。 LRU ,Least Recently Used(最近最少使用). (ehcache 默认值).缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。 --> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="10000" eternal="true" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> <cache name="baseCache" maxElementsInMemory="10000" maxElementsOnDisk="1000" eternal="false" overflowToDisk="true" diskSpoolBufferSizeMB="20" timeToIdleSeconds="300" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LFU" /> <!-- 页面全部缓存 --> <cache name="SimplePageCachingFilter" maxElementsInMemory="10000" maxElementsOnDisk="1000" eternal="false" overflowToDisk="true" diskSpoolBufferSizeMB="20" timeToIdleSeconds="2" timeToLiveSeconds="4" memoryStoreEvictionPolicy="LFU" /> <!-- 页面局部缓存 --> <cache name="SimplePageFragmentCachingFilter" maxElementsInMemory="10000" maxElementsOnDisk="1000" eternal="false" overflowToDisk="false" timeToIdleSeconds="6" timeToLiveSeconds="12" memoryStoreEvictionPolicy="LFU"> </cache> </ehcache>
spring 搭建
1.用于替代web.xml的WebProjectConfigInitializerpackage com.test.config; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class WebProjectConfigInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { /** * 加载驱动应用后端的中间层和数据层组件 */ @Override protected Class<?>[] getRootConfigClasses() { return new Class[]{RootConfig.class}; } /** 指定配置类 * 加载包含web组件的bean,如控制机器、视图解析器以及映射处理器 */ @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{WebConfig.class}; } //将DispatcherServlet 映射到“/” @Override protected String[] getServletMappings() { return new String[] { "/" }; } }
2.RootConfig代码:
package com.test.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @Configuration @ComponentScan(basePackages={"com.test"},excludeFilters={@Filter(type=FilterType.ANNOTATION,value=EnableWebMvc.class)}) public class RootConfig { }
3.WebConfig代码
package com.test.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.JstlView; @Configuration @EnableWebMvc @ComponentScan("com.test.controller") public class WebConfig extends WebMvcConfigurerAdapter { //配置jsp视图解析器 @Bean public ViewResolver viewResolver(){ InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/jsp/"); resolver.setSuffix(".jsp"); resolver.setExposeContextBeansAsAttributes(true); resolver.setViewClass(JstlView.class); return resolver; } }
4.controller代码
package com.test.controller; import org.apache.log4j.Logger; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/user") public class UserController { private final static Logger log = Logger.getLogger(UserController.class); @RequestMapping("/index.html") public String index(Model model){ log.info("进入方法"); model.addAttribute("date",System.currentTimeMillis()); return "index"; } }
配置整体页面缓存
在应用中添加filter:package com.test.config; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; import javax.servlet.DispatcherType; import javax.servlet.FilterRegistration; import javax.servlet.ServletContext; import javax.servlet.ServletException; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.filter.CharacterEncodingFilter; public class MyServletInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { //配置页面整体缓存 FilterRegistration.Dynamic pageCachingFilter = servletContext.addFilter("pageCachingFilter",net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter.class); pageCachingFilter.addMappingForUrlPatterns(null, true, "/*"); FilterRegistration.Dynamic characterEncoding=servletContext.addFilter("characterEncoding", CharacterEncodingFilter.class); characterEncoding.setInitParameter("forceEncoding", "true"); characterEncoding.setInitParameter("encoding", "UTF-8"); characterEncoding.addMappingForUrlPatterns(null, true, "/*"); } }
可以看到并没有指定ehcache.xml中的缓存,因为在ehcache.xml中的名字是SimplePageCachingFilter,此时在filter中是可以不指定cacheName的,ehcache默认会使用SimplePageCachingFilter。
编写index.jsp页面:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <h1>缓存测试</h1> <h2>时间:${date }</h2> <%-- <jsp:include page="/jsp/include/index-include.jsp" /> --%> </body> </html>
运行结果如图:
控制台打印:
[INFO ] 2017-02-22 12:58:30,827 method:com.test.controller.UserController.index(UserController.java:16) 进入方法 [DEBUG] 2017-02-22 12:58:30,829 method:org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1251) Rendering view [org.springframework.web.servlet.view.JstlView: name 'index'; URL [/jsp/index.jsp]] in DispatcherServlet with name 'dispatcher' [DEBUG] 2017-02-22 12:58:30,829 method:org.springframework.web.servlet.view.AbstractView.exposeModelAsRequestAttributes(AbstractView.java:432) Added model object 'date' of type [java.lang.Long] to request in view with name 'index' [DEBUG] 2017-02-22 12:58:30,830 method:org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:166) Forwarding to resource [/jsp/index.jsp] in InternalResourceView 'index' [DEBUG] 2017-02-22 12:58:30,833 method:org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1000) Successfully completed request [DEBUG] 2017-02-22 12:58:30,835 method:net.sf.ehcache.constructs.web.filter.CachingFilter.buildPageInfo(CachingFilter.java:250) PageInfo ok. Adding to cache SimplePageCachingFilter with key GET/ehcache-web/user/index.htmlnull [DEBUG] 2017-02-22 12:58:30,835 method:net.sf.ehcache.store.disk.Segment.put(Segment.java:432) put added 0 on heap [DEBUG] 2017-02-22 12:58:30,836 method:net.sf.ehcache.constructs.web.filter.Filter.logRequestHeaders(Filter.java:288) Request Headers: host -> localhost:8080: connection -> keep-alive: cache-control -> max-age=0: upgrade-insecure-requests -> 1: user-agent -> Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36: accept -> text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8: accept-encoding -> gzip, deflate, sdch: accept-language -> zh-CN,zh;q=0.8: cookie -> JSESSIONID=F8D4E5ADD89B56C6005F7F594E9A4A68 [DEBUG] 2017-02-22 12:58:30,837 method:net.sf.ehcache.constructs.web.filter.Filter.logRequestHeaders(Filter.java:288) Request Headers: host -> localhost:8080: connection -> keep-alive: cache-control -> max-age=0: upgrade-insecure-requests -> 1: user-agent -> Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36: accept -> text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8: accept-encoding -> gzip, deflate, sdch: accept-language -> zh-CN,zh;q=0.8: cookie -> JSESSIONID=F8D4E5ADD89B56C6005F7F594E9A4A68
因为上面配置过:
<!-- 页面全部缓存 --> <cache name="SimplePageCachingFilter" maxElementsInMemory="10000" maxElementsOnDisk="1000" eternal="false" overflowToDisk="true" diskSpoolBufferSizeMB="20" timeToIdleSeconds="2" timeToLiveSeconds="4" memoryStoreEvictionPolicy="LFU" />
测试时一直刷新4秒的话之后才时间会变,2秒内不访问,再刷新,时间也会变。第二次访问的时候控制台会报Thread http-apr-8080-exec-6 has been marked as visited.。
局部页面缓存
配置SimplePageFragmentCachingFilter//配置局部页面整体缓存 FilterRegistration.Dynamic pageFragmentCachingFilter = servletContext.addFilter("pageFragmentCachingFilter",net.sf.ehcache.constructs.web.filter.SimplePageFragmentCachingFilter.class); pageFragmentCachingFilter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.INCLUDE), true, "/jsp/include/*"); // Map<String, String> initParameters = new HashMap<String, String>(); // initParameters.put("cacheName", "SimplePageFragmentCachingFilter"); // pageFragmentCachingFilter.setInitParameters(initParameters);
上面配置中的注释部分在自己指定filter时使用,如果想自己指定filter可以将fiter换成自己的,并且要指定cacheName.要注意的是,局部页面缓存需要设置DispatcherType.INCLUDE的属性,否则无效果。
被包含的页面:
index-include.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'index-include.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <h3>这是被包含的页面</h3> <h4>包含的时间:${date }</h4> </body> </html>
把上面index.jsp中包含页面的部分的注释打开
测试运行项目第一次结果为:
第二次访问:
执行结果分析:
从ehcache.xml文件中可以看到,局部页面的缓存时间比整体页面的缓存时间长。所以即使整体页面的时间变了,局部页面的时间还是没有变。
注意:上面ehcache.xml中的缓存时间都比较短,是为了本项目测试,真实项目中请根据实际情况决定缓存时间。
源代码:http://download.csdn.net/detail/poorcoder_/9760607
转载请标明出处:http://blog.csdn.net/poorcoder_/article/details/56483954
相关文章推荐
- Ehcache 整合Spring 使用页面、对象缓存
- Ehcache 整合Spring 使用页面、对象缓存
- Ehcache 整合Spring 使用页面、对象缓存
- Ehcache 整合Spring 使用页面、对象缓存
- Ehcache 整合Spring 使用页面、对象缓存
- Spirng3基于注解(annotation)整合ehcache 使用页面缓存、对象缓存
- Ehcache 整合Spring 使用页面、对象缓存
- Ehcache 整合Spring 使用页面、对象缓存(转载)
- Ehcache 整合Spring 使用页面、对象缓存
- Ehcache 整合Spring 使用页面、对象缓存
- Ehcache 整合Spring 使用页面、对象缓存
- 使用EhCache实现页面缓存
- Ehcache 整合Spring 使用页面、对象缓存
- Ehcache 整合Spring 使用页面、对象缓存
- Ehcache 整合Spring 使用页面、对象缓存
- Ehcache 整合Spring 使用页面、对象缓存
- Ehcache 整合Spring 使用对象缓存、页面缓存
- Spirng3基于注解(annotation)整合ehcache 使用页面缓存、对象缓存
- Ehcache 整合Spring 使用页面、对象缓存
- Ehcache 整合Spring 使用页面、对象缓存