zoukankan      html  css  js  c++  java
  • springMVC整合memcached,以注解形式使用

    没有用过memcached,看了一些关于memcached的博客,写的都挺好的,自己整合的时候也遇到了一些问题。

    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包帮我们封装好了一些方法,避免我们自己再去实现复杂的操作了。

    目前我看到有三个客户端:

      • java_memcached-release     --->:danga的,我也不知道这是什么组织……,但这个客户端比较老牌的了。
      • alisoft-xplatform-asf-cache  --->:阿里的
      • XMemcached                      --->:oschina上看到的,貌似是纯国产啊,应用的还是挺广泛的~

      jar包下载地址:http://pan.baidu.com/s/1sjLQO8l

    我做的示例整合的是 java_memcached-release 这个版本的

    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" 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 配置文件

    如果你需要把mybatis整合尽量的话,在此配置文件下增加数据源、事务管理等等

    <?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的各种配置。

    <?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的各种配置信息。

    <?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 + "
    " + 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 + "
    " + 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 + "
    " + 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 + "
    " + 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 + "
    " + exceptionWrite(e));  
            }  
            return flag;  
        }  
      
        /** 
         * 清理缓存中的所有键/值对 
         *  
         * @return 
         */  
        public static boolean flashAll() {  
            boolean flag = false;  
            try {  
                flag = cachedClient.flushAll();  
            } catch (Exception e) {  
                MemcachedLog.writeLog("Memcached flashAll方法报错
    " + 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()) + "]
    "  
                            + 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

  • 相关阅读:
    hdu 2222 Keywords Search
    Meet and Greet
    hdu 4673
    hdu 4768
    hdu 4747 Mex
    uva 1513 Movie collection
    uva 12299 RMQ with Shifts
    uva 11732 strcmp() Anyone?
    uva 1401
    hdu 1251 统计难题
  • 原文地址:https://www.cnblogs.com/zhengbn/p/4132391.html
Copyright © 2011-2022 走看看