ehcache使用_Spring4 整合EhCache实现页面缓存 零配置

前言

本文通过spring4 以java配置类方式 整合EhCache来实现页面整体缓存及页面局部缓存。同时提供源码。因为使用了零配置,所以要求tomcat7以上的版本。 
原理是添加拦截器,在请求从用户浏览器到controller之间拦截直接返回数据,减轻服务器的压力,也加快了访问。

页面缓存介绍

缓存中的元素是被压缩过的,如果客户浏览器支持压缩的话,filter会直接返回压缩过的流,这样节省了带宽,把解压的工作交给了客户浏览器,如果客户的浏览器不支持gzip ,那么filter 会把缓存的元素拿出来解压后再返回给客户浏览器。 
ehcache-web这个包中给我们提供了一些filter来处理页面缓存。如下图: 35d673e97df3a8c76bb2e236b3b78031.png 
在这里介绍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.0modelVersion>
<groupId>com.testgroupId>
<artifactId>ehcache-webartifactId>
<version>0.0.1-SNAPSHOTversion>
<packaging>warpackaging>

<properties>

<spring.version>4.3.5.RELEASEspring.version>
<junit.version>4.12junit.version>
properties>

<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>${junit.version}version>
<scope>testscope>
dependency>

<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-context-supportartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>


<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>

<dependency>
<groupId>commons-logginggroupId>
<artifactId>commons-loggingartifactId>
<version>1.1.3version>
dependency>

<dependency>
<groupId>commons-langgroupId>
<artifactId>commons-langartifactId>
<version>2.6version>
dependency>


<dependency>
<groupId>net.sf.ehcachegroupId>
<artifactId>ehcacheartifactId>
<version>2.7.5version>
<type>jartype>
<scope>compilescope>
dependency>
<dependency>
<groupId>net.sf.ehcachegroupId>
<artifactId>ehcache-webartifactId>
<version>2.0.4version>
dependency>



<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.18version>
dependency>



<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<version>1.7.18version>
dependency>



<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-coreartifactId>
<version>2.5version>
dependency>



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 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的WebProjectConfigInitializer

package 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页面:

"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+"/";
%>

<html><head><base href=""><title>My JSP 'index.jsp' starting pagetitle><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">head><body><h1>缓存测试h1><h2>时间:${date }h2>"/jsp/include/index-include.jsp" /> --%>
body>
html>

运行结果如图: 013891f5dfd469ea0fb69b52f2415d3d.png

控制台打印:

[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 initParameters = new HashMap();
// initParameters.put("cacheName", "SimplePageFragmentCachingFilter");
// pageFragmentCachingFilter.setInitParameters(initParameters);

上面配置中的注释部分在自己指定filter时使用,如果想自己指定filter可以将fiter换成自己的,并且要指定cacheName.要注意的是,局部页面缓存需要设置DispatcherType.INCLUDE的属性,否则无效果。

被包含的页面: 
index-include.jsp

"java" import="java.util.*" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>

<html><head><title>My JSP 'index-include.jsp' starting pagetitle><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">head><body><h3>这是被包含的页面h3><h4>包含的时间:${date }h4>body>html>

把上面index.jsp中包含页面的部分的注释打开

测试运行项目第一次结果为: 6d2c5eb0e6f4bf92258e32219cc4bc93.png 
第二次访问: c69caf58c42d990d219fe7608c56043f.png 
执行结果分析: 
从ehcache.xml文件中可以看到,局部页面的缓存时间比整体页面的缓存时间长。所以即使整体页面的时间变了,局部页面的时间还是没有变。

程序员,你下班的 时候关电脑了吗?

15天的性能优化工作,5方面的调优经验

Java NIO?看这一篇就够了!

Redis 5.0.4-搭建3主3从3哨兵,实现高可用性与故障转移

BAT一线互联网企业Java工程师超硬核面试题总结

e92ed875418e4c03798a9547482dac95.png

一定要关注公众号,资料随时更新,自助领取

点亮 df696a5b97fa5185132179fba7a409a2.png,告诉大家你也在看e8e9faa39a3023dafdeafce5185c890d.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值