XMemcached与spring的集成实例

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 [] { 1 1 });
         // 设置连接池大小,即客户端个数
         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(); 
	}
}



spring+xmemcached aop切面 需要xmemcached-1.2.5+spring-2.5.6 <bean name="factoryMemcachedClient" class="net.rubyeye.xmemcached.utils.XMemcachedClientFactoryBean" destroy-method="shutdown"> <property name="servers"> <value>${XMemcached_servers}</value> </property> <!-- server's weights --> <property name="weights"> <list> <value>1</value> <value>2</value> <value>3</value> </list> </property> <!-- nio connection pool size --> <property name="connectionPoolSize" value="${XMemcached_connectionPoolSize}"></property> <!-- Use binary protocol,default is TextCommandFactory, BinaryCommandFactory KestrelCommandFactory --> <property name="commandFactory"> <bean class="net.rubyeye.xmemcached.command.BinaryCommandFactory"></bean> </property> <!-- Distributed strategy KetamaMemcachedSessionLocator--> <property name="sessionLocator"> <bean class="net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator"></bean> </property> <!-- Serializing transcoder --> <property name="transcoder"> <bean class="net.rubyeye.xmemcached.transcoders.SerializingTranscoder" /> </property> <!-- ByteBuffer allocator --> <property name="bufferAllocator"> <bean class="net.rubyeye.xmemcached.buffer.SimpleBufferAllocator"></bean> </property> </bean> <bean id="cachingClient" class="com.dmx.cache.caching.impl.CachingXMemcachedClient" init-method="init" destroy-method="destroy"> <property name="memcachedClient" ref="factoryMemcachedClient" /> <property name="isflushAll" value="${XMemcached_isflushAll}" /> </bean> <bean id="cachingManager" class="com.dmx.cache.caching.impl.CachingManagerImpl"> <property name="cachingClient" ref="cachingClient" /> </bean> <bean id="cacheBeforeAdvice" class="com.dmx.cache.interceptor.advice.CacheBeforeAdvice"></bean> <bean id="cacheAfterAdvice" class="com.dmx.cache.interceptor.advice.CacheAfterAdvice"></bean> <bean id="cacheInterceptor" class="com.dmx.cache.interceptor.CacheInterceptor"> <property name="cachingManager" ref="cachingManager" /> <property name="cacheAttributes"> <props> <prop key="save*">update</prop> <prop key="remove*">update</prop> <prop key="add*">update</prop> <prop key="del*">update</prop> <prop key="get*">readOnly</prop> <prop key="getPlaybill">readOnly=10</prop> </props> </property> </bean> <bean id="cacheProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="interceptorNames"> <list> <value>cacheBeforeAdvice</value> <value>cacheAfterAdvice</value> <value>cacheInterceptor</value> </list> </property> </bean> <bean id="demoDao" parent="cacheProxyFactoryBean"> <property name="target" ref="demoDaotarget" /> </bean>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值