通過Ehcache設置頁面緩存,緩解服務器壓力
簡單demo 結構圖
pom配置
<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>EhcacheDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<spring.version>4.3.0.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.8.5</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-web</artifactId>
<version>2.0.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.5.v20120716</version>
<configuration>
<connectors>
<connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
<port>8080</port> <!-- 訪問端口,默認8080 -->
</connector>
</connectors>
<stopPort>9966</stopPort>
<stopKey>foo</stopKey>
<scanIntervalSeconds>10</scanIntervalSeconds>
<webApp>
<!-- web項目根路徑 -->
<contextPath>/</contextPath>
</webApp>
</configuration>
</plugin>
</plugins>
</build>
</project>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>EhcacheDemo</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</context-param>
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>context</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- ehcache頁面緩存 -->
<filter>
<filter-name>simplePageCachingFilter</filter-name>
<filter-class>com.test.ehcache.filter.PageCachingFilter</filter-class>
<init-param>
<param-name>cacheName</param-name>
<!-- 定義cache的名字 -->
<param-value>webPageCache</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>simplePageCachingFilter</filter-name>
<url-pattern>/home/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
配置文件 log4j.properties
log4j.rootLogger=info, A1
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=>>> %d %5p [%t] (%F:%L) - %m%n
log4j.appender.A1.DatePattern='.'yyyy-MM-dd
log4j.appender.A1=org.apache.log4j.ConsoleAppender
applicationContext-mvc.xml
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
" default-lazy-init="true">
<context:annotation-config />
<!-- 把標記了@Controller註解的類轉換爲bean -->
<context:component-scan base-package="com.test.ehcache" />
<!-- 啓動Spring MVC的註解功能,完成請求和註解POJO的映射 -->
<!-- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> -->
<!-- 對模型視圖名稱的解析,即在模型視圖名稱添加前後綴 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/view/" p:suffix=".jsp" />
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
p:defaultEncoding="utf-8" />
<mvc:annotation-driven/>
</beans>
ehcache.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" maxBytesLocalDisk="20G">
<!-- Default Cache configuration. These settings will be applied to caches
created programmatically using CacheManager.add(String cacheName). This element
is optional, and using CacheManager.add(String cacheName) when its not present
will throw CacheException The defaultCache has an implicit name "default"
which is a reserved cache name. -->
<defaultCache maxElementsInMemory="10000" eternal="false"
timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="30"
maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU" overflowToDisk="false"
overflowToOffHeap="false">
<persistence strategy="localTempSwap" />
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
</defaultCache>
<!-- 配置自定義緩存 maxElementsInMemory:緩存中允許創建的最大對象數 eternal:緩存中對象是否爲永久的,如果是,超時設置將被忽略,對象從不過期。
timeToIdleSeconds:緩存數據的鈍化時間,也就是在一個元素消亡之前, 兩次訪問時間的最大時間間隔值,這隻能在元素不是永久駐留時有效,
如果該值是 0 就意味着元素可以停頓無窮長的時間。 timeToLiveSeconds:緩存數據的生存時間,也就是一個元素從構建到消亡的最大時間間隔值,
這隻能在元素不是永久駐留時有效,如果該值是0就意味着元素可以停頓無窮長的時間。 overflowToDisk:內存不足時,是否啓用磁盤緩存。 memoryStoreEvictionPolicy:緩存滿了之後的淘汰算法。 -->
<cache name="webPageCache" maxElementsInMemory="10000" eternal="false"
timeToIdleSeconds="900" timeToLiveSeconds="900" overflowToDisk="true"
memoryStoreEvictionPolicy="LFU" />
</ehcache>
PageCachingFilter
package com.test.ehcache.filter;
import java.util.Enumeration;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import net.sf.ehcache.constructs.blocking.LockTimeoutException;
import net.sf.ehcache.constructs.web.AlreadyCommittedException;
import net.sf.ehcache.constructs.web.AlreadyGzippedException;
import net.sf.ehcache.constructs.web.filter.FilterNonReentrantException;
import net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter;
public class PageCachingFilter extends SimplePageCachingFilter{
private static final Logger logger = Logger.getLogger(PageCachingFilter.class);
/**
* 設置緩存頁面的key
*/
@Override
protected String calculateKey(HttpServletRequest request) {
StringBuffer stringBuffer = new StringBuffer();
//請求地址
String url=request.getRequestURI();
//請求參數
String query=request.getQueryString();
stringBuffer.append(url);
stringBuffer.append("?");
stringBuffer.append(query);
return stringBuffer.toString();
}
@Override
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws AlreadyGzippedException, AlreadyCommittedException, FilterNonReentrantException,
LockTimeoutException, Exception {
String url=request.getRequestURI()+"?"+request.getQueryString();
//過濾活動相關的分組等請求,滿足則緩存頁面
if(url.contains("/home/main.do")){
logger.info("ehcache緩存頁面地址:" + url);
super.doFilter(request, response, chain);
}else{
//不滿足則不緩存
chain.doFilter(request, response);
}
}
/**
* 兼容ie6/7 gzip壓縮
*/
@Override
protected boolean acceptsGzipEncoding(HttpServletRequest request) {
boolean ie6 = headerContains(request, "User-Agent", "MSIE 6.0");
boolean ie7 = headerContains(request, "User-Agent", "MSIE 7.0");
return acceptsEncoding(request, "gzip") || ie6 || ie7;
}
private boolean headerContains(final HttpServletRequest request, final String header, final String value) {
logRequestHeaders(request);
final Enumeration<?> accepted = request.getHeaders(header);
while (accepted.hasMoreElements()) {
final String headerValue = (String) accepted.nextElement();
if (headerValue.indexOf(value) != -1) {
return true;
}
}
return false;
}
}
EhcacheUtil
package com.test.ehcache.util;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
public class EhcacheUtil {
private static final Logger LOG = LoggerFactory.getLogger(EhcacheUtil.class);
public static CacheManager manager = CacheManager.create();
/**
* Gets an element from the cache. Updates Element Statistics
*
* @param cacheName
* @param key
* @return
*/
public static Object get(String cacheName, Object key) {
Ehcache ehcache = getEhcache(cacheName);
if (ehcache != null) {
Element element = ehcache.get(key);
if (element != null) {
return element.getObjectValue();
}
}
return null;
}
/**
* Gets an element from the cache. Updates Element Statistics
*
* @param cacheName
* @param key
* @return
*/
public static List<?> getKeys(String cacheName) {
Ehcache ehcache = getEhcache(cacheName);
if (ehcache != null) {
return ehcache.getKeys();
}
return null;
}
/**
* Put an element in the cache.
*
* @param cacheName
* @param key
* @param value
*/
public static void put(String cacheName, Object key, Object value) {
Ehcache ehcache = getEhcache(cacheName);
if (ehcache != null) {
ehcache.put(new Element(key, value));
}
}
/**
* Removes an Element from the Cache
*
* @param cacheName
* @param key
* @return
*/
public static boolean remove(String cacheName, Object key) {
Ehcache ehcache = getEhcache(cacheName);
if (ehcache != null) {
return ehcache.remove(key);
}
return false;
}
/**
* Removes all cached items.
*
* @param cacheName
*/
public static void removeAll(String cacheName) {
Ehcache ehcache = getEhcache(cacheName);
if (ehcache != null) {
LOG.info("Removes ehcache all cached items.");
ehcache.removeAll();
}
}
/**
* Get ehcache object instance
* @param cacheName
* @return
*/
private static Ehcache getEhcache(String cacheName){
return manager.getEhcache(cacheName);
}
}
CacheController
package com.test.ehcache.web;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.test.ehcache.util.EhcacheUtil;
@Controller
@RequestMapping("/cache")
public class CacheController{
private static final Logger logger = Logger.getLogger(CacheController.class);
@RequestMapping(value="/clean")
@ResponseBody
public void cleanPageCache(@RequestParam String params){
logger.info("清除緩存"+params);
EhcacheUtil.remove("webPageCache", params);
}
}
HomeController
package com.test.ehcache.web;
import java.util.Date;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/home")
public class HomeController {
private static final Logger logger = Logger.getLogger(HomeController.class);
@RequestMapping(value="/main")
public String main(Model model){
//參數
String dateTime = new Date().toLocaleString();
model.addAttribute("datas", dateTime);
logger.info("測試,當前時間:" + dateTime);
return "home/main";
}
}
通過 jetty:run啓動後
訪問多次
http://localhost:8080/home/main.do
查看日誌
通過clean 就可以把ehcache清除
主要是 通過SimplePageCachingFilter來實現。
代碼目錄:http://git.oschina.net/li35619081/EhcacheDemo