XMemcached与spring的集成实例

来源:互联网 发布:linux文件夹 编辑:程序博客网 时间:2024/06/08 03:06

1.Memcached Client简要介绍
Memcached Client目前有3种: 

1.Memcached Client for Java  2.SpyMemcached   3.XMemcached

这三种Client一直存在各种争议:

Memcached Client for Java 比 SpyMemcached更稳定、更早、更广泛;SpyMemcached 比 Memcached Client for Java更高效;XMemcached 比 SpyMemcache并发效果更好。

具体可以参考官方性能对比: 

Memcached Client for Java: https://github.com/gwhalin/Memcached-Java-Client/wiki/PERFORMANCE 
XMemcached: http://xmemcached.googlecode.com/svn/trunk/benchmark/benchmark.html 

2.XMemcached特性 

高性能;支持完整的memcached文本协议,二进制协议;支持JMX,可以通过MBean调整性能参数、动态添加/移除server、查看统计等;支持客户端统计;支持memcached节点的动态增减;支持memcached分布:余数分布和一致性哈希分布;更多的性能调整选项。

3.XMemcached简单实现

MemcachedClientBuilder是MemcachedClient核心接口,用来控制Client的构建(build()方法)和关闭(shutdown()方法)。 通过build()方法获得 MemcachedClient 

然后就可以通过Memcached进行set、get、replace、delete等Memcached操作了! 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import static junit.framework.Assert.*;
 
import java.io.IOException;
import java.util.concurrent.TimeoutException;
 
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.command.BinaryCommandFactory;
import net.rubyeye.xmemcached.exception.MemcachedException;
import net.rubyeye.xmemcached.utils.AddrUtil;
 
import org.junit.Test;
 
public class MemcachedClientTest {
    @Test
    public void test() {
        MemcachedClientBuilder builder = new XMemcachedClientBuilder(
//多个服务和权重
            AddrUtil.getAddresses("192.168.1.110:11211 192.168.1.111:11211"),new int[] {11});
        // 设置连接池大小,即客户端个数
        builder.setConnectionPoolSize(50);
        // 宕机报警
        builder.setFailureMode(true);
        // 使用二进制文件
        builder.setCommandFactory(new BinaryCommandFactory());
        // 使用一致性哈希算法(Consistent Hash Strategy)
        builder.setSessionLocator(new KetamaMemcachedSessionLocator());
        // 使用序列化传输编码
        builder.setTranscoder(new SerializingTranscoder());
        // 进行数据压缩,大于1KB时进行压缩
        builder.getTranscoder().setCompressionThreshold(1024);
        MemcachedClient memcachedClient = null;
        try {
            memcachedClient = builder.build();
            try {
                // 设置/获取
                memcachedClient.set("aa"36000"set/get");
                assertEquals("set/get", memcachedClient.get("aa"));
                // 替换
                memcachedClient.replace("aa"36000"replace");
                assertEquals("replace", memcachedClient.get("aa"));
                // 移除
                memcachedClient.delete("aa");
                assertNull(memcachedClient.get("aa"));
            catch (TimeoutException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            catch (MemcachedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        finally {
            if (memcachedClient != null) {
                try {
                    memcachedClient.shutdown();
                catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}


4.XMemcached与Spring集成 更新数据后原来对应的类模块键过期策略,对缓存键存在数据库中策略的代替

spring-xmemcached.xml注释的部分是可以配置多个memcached服务器的

复制代码
<!-- 引入Memcached客户端开始-->    <bean name="memcachedClientBuilder" class="net.rubyeye.xmemcached.XMemcachedClientBuilder">                <constructor-arg>            <list>                <bean class="java.net.InetSocketAddress">                    <constructor-arg>                        <value>192.168.100.102</value>                    </constructor-arg>                    <constructor-arg>                        <value>11211</value>                    </constructor-arg>                </bean>                <!--                 <bean class="java.net.InetSocketAddress">                    <constructor-arg>                        <value>localhost</value>                    </constructor-arg>                    <constructor-arg>                        <value>12001</value>                    </constructor-arg>                </bean>                 -->            </list>        </constructor-arg>        <constructor-arg>            <list>                                 <value>1</value>                <!--                <value>2</value>                 -->            </list>        </constructor-arg>                <property name="connectionPoolSize" value="2"></property>        <property name="commandFactory">            <bean class="net.rubyeye.xmemcached.command.TextCommandFactory"></bean>        </property>        <property name="sessionLocator">            <bean class="net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator"></bean>        </property>        <property name="transcoder">            <bean class="net.rubyeye.xmemcached.transcoders.SerializingTranscoder" />        </property>    </bean>        <bean name="memcachedClient" factory-bean="memcachedClientBuilder"        factory-method="build" destroy-method="shutdown" />        <!-- 引入Memcached客户端结束 -->   
     <!-- get cache拦截器 --><bean id="methodCacheInterceptor" class="com.jing.memcached.interceptor.XMemcachedMethodCacheInterceptor"><property name="memcachedClient"><ref local="memcachedClient" /></property></bean><bean id="methodCachePointCut"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><property name="advice"><ref local="methodCacheInterceptor" /></property><property name="patterns"><list><value>com.jing.*.getAllUser</value>            <value>com.jing.*.update.*</value>            <value>com.jing.*.add.*</value></list></property></bean>                <!--一个ProxyFactoryBean类只能指定一个代理目标。BeanNameAutoProxyCreator类自动代理,可以代理多个目标  --><bean id="myService" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"><property name="beanNames" value="*ServiceImpl"/>  <!--配置文件中可以使用@Autowired注解实例化的类  --> <property name="interceptorNames"><list><value>methodCachePointCut</value></list></property></bean> 
复制代码

拦截器配置:
package com.jing.memcached.interceptor;import java.lang.reflect.Method;import net.rubyeye.xmemcached.MemcachedClient;import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;import org.springframework.beans.factory.InitializingBean;import org.springframework.util.Assert;import com.jing.memcached.annotation.CacheAdd;import com.jing.memcached.annotation.CacheRemove;/** * @author 静国强 * @date 2015-9-11 * @desc 配置MemCachedClient拦截器 */public class XMemcachedMethodCacheInterceptor implements MethodInterceptor,InitializingBean {private MemcachedClient memcachedClient;public void setMemcachedClient(MemcachedClient memcachedClient) {this.memcachedClient = memcachedClient;}public void afterPropertiesSet() throws Exception {Assert.notNull(memcachedClient,"A cache is required. Use setCache(Cache) to provide one.");}public Object invoke(MethodInvocation invocation) throws Throwable { Method[] methods = invocation.getThis().getClass().getDeclaredMethods();   String targetName = invocation.getThis().getClass().getName();Method method = invocation.getMethod();  //这种方法不能取到它的注解String methodName = method.getName();Object[] arguments = invocation.getArguments();Object result= null;Object  object = null;//定义版本号        String prefixValue = null;                        //通过方法名获取每个方法模块的版本号        if(null != memcachedClient.get(targetName))        {            prefixValue = memcachedClient.get(targetName).toString();        }                                else        {   prefixValue = CacheVersion.getVersion();            memcachedClient.set(targetName,60*60*24*30, prefixValue);        }String cacheKey = getCacheKey(targetName, methodName, arguments) + prefixValue;System.out.println(">>>>>>>>>进入拦截:方法"+methodName+">>>>>>cacheKey:"+cacheKey);for(Method m:methods){ //循环方法,找匹配的方法进行执行  用m才能取到它的注解 System.out.println("aa循环:"+m.getName()+" "+m.isAnnotationPresent(CacheAdd.class) +m.isAnnotationPresent(CacheRemove.class)); if(m.getName().equals(methodName)){ if(m.isAnnotationPresent(CacheAdd.class)){  System.out.println(">>>>>>>>>添加缓存分支");//添加缓存synchronized (this) {object = memcachedClient.get(cacheKey);if (object == null) {// 调用实际的方法result = invocation.proceed();System.out.println(">>>>>>>>>走数据库得到结果集为:"+result);memcachedClient.add(cacheKey,60*60*24 ,result ); //单位:秒  }else{System.out.println(">>>>>>>>>走缓存_得到结果集为:"+object);}}result = memcachedClient.get(cacheKey);}else if(m.isAnnotationPresent(CacheRemove.class)){ System.out.println(">>>>>>>>>删除缓存分支");  //执行正常操作result = invocation.proceed();                            //修改后,版本号 。以前的版本号组成的cacheKey就查询不到了 慢慢过期销毁    String version =CacheVersion.getVersion();                            memcachedClient.replace(targetName,60*60*24, version);                            System.out.println("更新"+targetName+"版本号为:"+version);}else{System.out.println(">>>>>>>>>没有缓存操作分支");result = invocation.proceed();} break;//找到这个方法就退出循环 }      }return result;        }private String getCacheKey(String targetName, String methodName,Object[] arguments) {StringBuffer sb = new StringBuffer();sb.append(targetName).append(".").append(methodName);if ((arguments != null) && (arguments.length != 0)) {for (int i = 0; i < arguments.length; i++) {sb.append(".").append(arguments[i]);}}return sb.toString();}}

生成版本号

package com.jing.memcached.interceptor;import java.util.UUID;public class CacheVersion {public static String getVersion(){UUID uuid = UUID.randomUUID();return uuid.toString().toUpperCase(); }}



0 0
原创粉丝点击