Ehcache頁面緩存

通過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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章