springMVC整合memcached,以註解形式使用

沒有用過memcached,看了一些關於memcached的博客,寫的都挺好的,本身整合的時候也遇到了一些問題。javascript

 

  1. 下載win的安裝包,貌似沒有64位的安裝包,反正我是沒找到。下載地址:http://pan.baidu.com/s/1kTC99kj
  2. 首先定位到安裝文件的解壓目錄,win7按住shift選擇打開此處cmd也能夠。
  3. 輸入安裝命令  memcached -d install  瞬間完成安裝……
  4. 而後啓動它:
    •   手動啓動:winKey+R鍵,輸入services.msc,找到memcached啓動它。
    •   或者命令行啓動:memcached -d start
    •   中止服務:memcached -d stop
    •   telnet 127.0.0.1 11211(默認的端口) ,輸入stats,出現信息則表示ok!

java若是想要與memcached聯合使用的話,須要使用memcached的客戶端,這是網友們的叫法。其實就是jar包。這些jar包幫咱們封裝好了一些方法,避免咱們本身再去實現複雜的操做了。css

目前我看到有三個客戶端:html

    • java_memcached-release     --->:danga的,我也不知道這是什麼組織……,但這個客戶端比較老牌的了。
    • alisoft-xplatform-asf-cache  --->:阿里的
    • XMemcached                      --->:oschina上看到的,貌似是純國產啊,應用的仍是挺普遍的~

  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>
View Code

 

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>
View Code


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>
View Code

 

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>
View Code

 

新建包 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);  
            }  
        }  
    }  
}
View Code


測試部分,新建一個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>
View Code
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;
    }
    
}
View Code

基本就是這樣了,在整合的時候遇到一個問題  [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
View Code

 

文中我搭建的工程放到了網盤上,須要的請移步下載哈:http://pan.baidu.com/s/1nthx0ff

相關文章
相關標籤/搜索