沒有用過memcached,看了一些關於memcached的博客,寫的都挺好的,本身整合的時候也遇到了一些問題。javascript
java若是想要與memcached聯合使用的話,須要使用memcached的客戶端,這是網友們的叫法。其實就是jar包。這些jar包幫咱們封裝好了一些方法,避免咱們本身再去實現複雜的操做了。css
目前我看到有三個客戶端:html
jar包下載地址:http://pan.baidu.com/s/1sjLQO8ljava
我作的示例整合的是 java_memcached-release 這個版本的jquery
web.xmlweb
<?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" 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>SpringMVC-Memcached</display-name> <!-- 引入 spring --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:/applicationContext*.xml</param-value> </context-param> <!-- 引入 springMVC --> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:/spring-servlet-config.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 編碼 UTF-8 --> <filter> <filter-name>SpringMVC-Memcached-Encoding</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> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>SpringMVC-Memcached-Encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
src目錄下新建 applicationContext.xml 配置文件spring
若是你須要把mybatis整合儘可能的話,在此配置文件下增長數據源、事務管理等等express
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <!-- 引入memcached配置文件 --> <import resource="spring-memcached.xml"/> </beans>
src目錄下新建 spring-memcached.xml 配置文件,該配置文件定義memcached的各類配置。apache
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <!-- 客戶端:java_memcached-release_2.6.3 --> <bean id="memcachedPool" class="com.danga.MemCached.SockIOPool" factory-method="getInstance" init-method="initialize" lazy-init="false" destroy-method="shutDown"> <constructor-arg> <value>memcachedPool</value> </constructor-arg> <!-- 能夠設置多個memcached服務器 --> <property name="servers"> <list> <value>127.0.0.1:11211</value> </list> </property> <!-- 每一個服務器初始鏈接數 --> <property name="initConn"> <value>20</value> </property> <!-- 每一個服務器最小鏈接數 --> <property name="minConn"> <value>20</value> </property> <!-- 每一個服務器最大鏈接數 --> <property name="maxConn"> <value>1000</value> </property> <!-- 主線程睡眠時間 --> <property name="maintSleep"> <value>30000</value> </property> <!-- TCP/Socket的參數,若是是true在寫數據時不緩衝,當即發送出去參數 --> <property name="nagle"> <value>false</value> </property> <!-- 鏈接超時/阻塞讀取數據的超時間是 --> <property name="socketTO"> <value>3000</value> </property> </bean> <bean id="memcachedClient" class="com.danga.MemCached.MemCachedClient" > <constructor-arg> <value>memcachedPool</value> </constructor-arg> </bean> </beans>
src目錄下新建 spring-servlet-config.xml 配置文件,該配置文件定義spring的各類配置信息。spring-mvc
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd"> <!-- 使用@Controllers前配置 --> <mvc:annotation-driven /> <!-- 容器加載時 自動掃描全部註解 --> <context:component-scan base-package="com.test" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" /> <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" /> <context:include-filter type="annotation" expression="org.springframework.stereotype.Component" /> </context:component-scan> <!-- 配置靜態資源 --> <mvc:resources mapping="/js/**" location="/js/" /> <mvc:resources mapping="/image/**" location="/image/" /> <mvc:resources mapping="/css/**" location="/css/" /> <!-- 使用jsp做爲視圖 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass"> <value>org.springframework.web.servlet.view.JstlView</value> </property> <!-- 目標路徑返回到pages下 使用jsp做爲視圖 --> <property name="prefix" value="/pages/"></property> <property name="suffix" value=".jsp"></property> </bean> <!-- 異常處理 --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="org.apache.shiro.authz.UnauthorizedException">error/403</prop> </props> </property> </bean> </beans>
新建包 com.test.utils ,新建 MemcachedUtils.java
備註:MemcachedUtils.java是一個工具類,裏面封裝了一些memcached的方法,這些方法都是基於 java_memcached-release.jar進行包裝的, 能夠方便咱們在項目中使用。
本工具類的原做者是:http://blog.csdn.net/yin_jw/article/details/32331453,我比較臉大,直接拿過來使用了~
package com.test.utils; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.text.SimpleDateFormat; import java.util.Date; import org.apache.log4j.Logger; import com.danga.MemCached.MemCachedClient; public class MemcachedUtils { private static final Logger logger = Logger.getLogger(MemcachedUtils.class); private static MemCachedClient cachedClient; static { if (cachedClient == null) cachedClient = new MemCachedClient("memcachedPool"); } private MemcachedUtils() {} /** * 向緩存添加新的鍵值對。若是鍵已經存在,則以前的值將被替換。 * * @param key * 鍵 * @param value * 值 * @return */ public static boolean set(String key, Object value) { return setExp(key, value, null); } /** * 向緩存添加新的鍵值對。若是鍵已經存在,則以前的值將被替換。 * * @param key * 鍵 * @param value * 值 * @param expire * 過時時間 New Date(1000*10):十秒後過時 * @return */ public static boolean set(String key, Object value, Date expire) { return setExp(key, value, expire); } /** * 向緩存添加新的鍵值對。若是鍵已經存在,則以前的值將被替換。 * * @param key * 鍵 * @param value * 值 * @param expire * 過時時間 New Date(1000*10):十秒後過時 * @return */ private static boolean setExp(String key, Object value, Date expire) { boolean flag = false; try { flag = cachedClient.set(key, value, expire); } catch (Exception e) { // 記錄Memcached日誌 MemcachedLog.writeLog("Memcached set方法報錯,key值:" + key + "\r\n" + exceptionWrite(e)); } return flag; } /** * 僅當緩存中不存在鍵時,add 命令纔會向緩存中添加一個鍵值對。 * * @param key * 鍵 * @param value * 值 * @return */ public static boolean add(String key, Object value) { return addExp(key, value, null); } /** * 僅當緩存中不存在鍵時,add 命令纔會向緩存中添加一個鍵值對。 * * @param key * 鍵 * @param value * 值 * @param expire * 過時時間 New Date(1000*10):十秒後過時 * @return */ public static boolean add(String key, Object value, Date expire) { return addExp(key, value, expire); } /** * 僅當緩存中不存在鍵時,add 命令纔會向緩存中添加一個鍵值對。 * * @param key * 鍵 * @param value * 值 * @param expire * 過時時間 New Date(1000*10):十秒後過時 * @return */ private static boolean addExp(String key, Object value, Date expire) { boolean flag = false; try { flag = cachedClient.add(key, value, expire); } catch (Exception e) { // 記錄Memcached日誌 MemcachedLog.writeLog("Memcached add方法報錯,key值:" + key + "\r\n" + exceptionWrite(e)); } return flag; } /** * 僅當鍵已經存在時,replace 命令纔會替換緩存中的鍵。 * * @param key * 鍵 * @param value * 值 * @return */ public static boolean replace(String key, Object value) { return replaceExp(key, value, null); } /** * 僅當鍵已經存在時,replace 命令纔會替換緩存中的鍵。 * * @param key * 鍵 * @param value * 值 * @param expire * 過時時間 New Date(1000*10):十秒後過時 * @return */ public static boolean replace(String key, Object value, Date expire) { return replaceExp(key, value, expire); } /** * 僅當鍵已經存在時,replace 命令纔會替換緩存中的鍵。 * * @param key * 鍵 * @param value * 值 * @param expire * 過時時間 New Date(1000*10):十秒後過時 * @return */ private static boolean replaceExp(String key, Object value, Date expire) { boolean flag = false; try { flag = cachedClient.replace(key, value, expire); } catch (Exception e) { MemcachedLog.writeLog("Memcached replace方法報錯,key值:" + key + "\r\n" + exceptionWrite(e)); } return flag; } /** * get 命令用於檢索與以前添加的鍵值對相關的值。 * * @param key * 鍵 * @return */ public static Object get(String key) { Object obj = null; try { obj = cachedClient.get(key); } catch (Exception e) { MemcachedLog.writeLog("Memcached get方法報錯,key值:" + key + "\r\n" + exceptionWrite(e)); } return obj; } /** * 刪除 memcached 中的任何現有值。 * * @param key * 鍵 * @return */ public static boolean delete(String key) { return deleteExp(key, null); } /** * 刪除 memcached 中的任何現有值。 * * @param key * 鍵 * @param expire * 過時時間 New Date(1000*10):十秒後過時 * @return */ public static boolean delete(String key, Date expire) { return deleteExp(key, expire); } /** * 刪除 memcached 中的任何現有值。 * * @param key * 鍵 * @param expire * 過時時間 New Date(1000*10):十秒後過時 * @return */ private static boolean deleteExp(String key, Date expire) { boolean flag = false; try { flag = cachedClient.delete(key, expire); } catch (Exception e) { MemcachedLog.writeLog("Memcached delete方法報錯,key值:" + key + "\r\n" + exceptionWrite(e)); } return flag; } /** * 清理緩存中的全部鍵/值對 * * @return */ public static boolean flashAll() { boolean flag = false; try { flag = cachedClient.flushAll(); } catch (Exception e) { MemcachedLog.writeLog("Memcached flashAll方法報錯\r\n" + exceptionWrite(e)); } return flag; } /** * 返回異常棧信息,String類型 * * @param e * @return */ private static String exceptionWrite(Exception e) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); pw.flush(); return sw.toString(); } /** * * @ClassName: MemcachedLog * @Description: Memcached日誌記錄 * @author yinjw * @date 2014-6-18 下午5:01:37 * */ private static class MemcachedLog { private final static String MEMCACHED_LOG = "D:\\memcached.log"; private final static String LINUX_MEMCACHED_LOG = "/usr/local/logs/memcached.log"; private static FileWriter fileWriter; private static BufferedWriter logWrite; // 獲取PID,能夠找到對應的JVM進程 private final static RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); private final static String PID = runtime.getName(); /** * 初始化寫入流 */ static { try { String osName = System.getProperty("os.name"); if (osName.indexOf("Windows") == -1) { fileWriter = new FileWriter(MEMCACHED_LOG, true); } else { fileWriter = new FileWriter(LINUX_MEMCACHED_LOG, true); } logWrite = new BufferedWriter(fileWriter); } catch (IOException e) { logger.error("memcached 日誌初始化失敗", e); closeLogStream(); } } /** * 寫入日誌信息 * * @param content * 日誌內容 */ public static void writeLog(String content) { try { logWrite.write("[" + PID + "] " + "- [" + new SimpleDateFormat("yyyy年-MM月-dd日 hh時:mm分:ss秒").format(new Date().getTime()) + "]\r\n" + content); logWrite.newLine(); logWrite.flush(); } catch (IOException e) { logger.error("memcached 寫入日誌信息失敗", e); } } /** * 關閉流 */ private static void closeLogStream() { try { fileWriter.close(); logWrite.close(); } catch (IOException e) { logger.error("memcached 日誌對象關閉失敗", e); } } } }
測試部分,新建一個index.jsp、Login.java
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery/jquery-1.8.0.min.js"></script> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Insert title here</title> </head> <body> <div><font color="red" size="10px">${returnMsg}</font></div> <form action="${pageContext.request.contextPath }/loginController/login" method="post" name="loginForm" id="loginForm"> <div> 用戶名:<input class="username" type="text" id="username" name="username" value=''/> </div> <div > 密碼:<input class="password" type="password" id="password" name="password" value=""/> </div> <div><input type="button" value="submit" onclick="login()" /></div> </form> <script type="text/javascript"> function login(){ var username = $("#username").val(); var password = $("#password").val(); $("#loginForm").submit(); } document.onkeydown=function(event){ e = event ? event :(window.event ? window.event : null); if(e.keyCode==13){ login(); } } </script> </body> </html>
package com.test.web; import java.util.Date; import javax.servlet.http.HttpSession; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; import com.test.utils.MemcachedUtils; @Controller @RequestMapping("/loginController") public class Login { @RequestMapping("/login") public ModelAndView login( @RequestParam(value = "username") String userid, @RequestParam(value = "password") String passwd, HttpSession session){ ModelAndView m = new ModelAndView(); m.setViewName("../index"); MemcachedUtils.set("wasd", "12ab",new Date(1000 * 60)); Object ss = MemcachedUtils.get("wasd"); System.out.println(ss.toString()); m.addObject("returnMsg","好的!"); return m; } }
基本就是這樣了,在整合的時候遇到一個問題 [ERROR] attempting to get SockIO from uninitialized pool!
緣由是:spring-memcached.xml中的 memcachedPool 的名字要和MemcachedUtils.java中new MemCachedClient("memcachedPool"); 的名字對應起來。
具體緣由已經有人分析了:http://blog.csdn.net/maerdym/article/details/10297993,我直接引用原做者的。
Memecached JavaClient在使用前需初始化SockIOPool,該類只有一個protected的構造方法,所以外部需使用其提供的靜態方法getInstance來獲取SockIOPool實例,getInstance方法容許傳入poolname來指明SockIOPool名稱. SockIOPool自己只是做爲SchoonerSockIOPool的代理類,SchoonerSockIOPool內維護了一個鏈接池Map,其中poolname做爲key,Pool實例做爲值.所以在使用Spring整合Memcacheds時,若是在Spring配置文件中指明瞭poolname,則在初始化MemecachedClient時,須要在其構造函數中指明poolname.,若是沒有聲明poolname,則MemechachedClient則或獲取名爲default的Pool實例. 如如下配置,必須在實例化MemechacedClient時傳入poolname.不然將沒法進行數據操做或數據操做無效。 Spring配置文件,該配置文件聲明瞭SockIOPool,因爲該類的構造方法爲protected類型,沒法直接訪問,所以須要使用工廠方法getInstance()來獲取其實例,注:此處的<constructor-arg>標籤不是做爲構造函數的參數,而是做爲工廠方法getInstance()的參數,即指明poolname爲memcache <bean id="memcache" class="com.whalin.MemCached.SockIOPool" factory-method="getInstance" init-method="initialize" destroy-method="shutDown"> <constructor-arg> <value>memcache</value> </constructor-arg></span></strong></em></span> <property name="servers"> <list> <value>${memcache.server}</value> </list> </property> <property name="initConn"> <value>${memcache.initConn}</value> </property> <property name="minConn"> <value>${memcache.minConn}</value> </property> <property name="maxConn"> <value>${memcache.maxConn}</value> </property> <property name="maintSleep"> <value>${memcache.maintSleep}</value> </property> <property name="nagle"> <value>${memcache.nagle}</value> </property> <property name="socketTO"> <value>${memcache.socketTO}</value> </property> </bean> 在使用memcachedClient訪問memchached時,需指明poolname爲memcache(默認爲default,但配置文件中沒有對default進行配置) MemCachedClient memCachedClient = new MemCachedClient("memcache"); memCachedClient.set("name", "simple"); System.out.println(memCachedClient.get("name")); 此處實例化MemCachedClient時,必須傳入參數‘memcache’類指明pool實例名稱,不然在插入的時候不報錯,但讀取的值始終爲null
文中我搭建的工程放到了網盤上,須要的請移步下載哈:http://pan.baidu.com/s/1nthx0ff