介绍
Memcached java client是官方推荐的最早的memcached java客户端。最新版本:java_memcached-release_2.6.1。
官方下载地址:/gwhalin/Memcached-Java-Client
采用阻塞式SOCKET通讯,据说目前版本进行了很多优化,性能有所提高(只看过1.5的源代码,还没来及看最新的)
提供key方式的连接池,默认连接池key为default。(老版本了)。2.6.1版本支持apache-commoms-pool作为连接池。
支持权重配置。
后期的版本提增加了cas支持和getMutl功能
官方示例代码
Java代码 importcom.danga.MemCached.MemCachedClient;importcom.danga.MemCached.SockIOPool;importcom.schooner.MemCached.MemcachedItem;publicclassMemcachedForJavaExample{//createastaticclientasmostinstallsonlyneed//asingleinstanceprotectedstaticMemCachedClientmcc=newMemCachedClient();//setupconnectionpoolonceatclassloadstatic{//serverlistandweightsString[]servers={"localhost:11211","localhost:11212","localhost:11213"};Integer[]weights={3,3,2};//grabaninstanceofourconnectionpoolSockIOPoolpool=SockIOPool.getInstance();//settheserversandtheweightspool.setServers(servers);pool.setWeights(weights);pool.setHashingAlg(SockIOPool.CONSISTENT_HASH);//setsomebasicpoolsettings//5initial,5min,and250maxconns//andsetthemaxidletimeforaconn//to6hourspool.setInitConn(5);pool.setMinConn(5);pool.setMaxConn(250);pool.setMaxIdle(1000*60*60*6);//setthesleepforthemaintthread//itwillwakeupeveryxsecondsand//maintainthepoolsizepool.setMaintSleep(30);//setsomeTCPsettings//disablenagle//setthereadtimeoutto3secs//anddon'tsetaconnecttimeoutpool.setNagle(false);pool.setSocketTO(3000);pool.setSocketConnectTO(0);//initializetheconnectionpoolpool.initialize();}publicstaticvoidmain(String[]args){System.out.println("SET:"+mcc.set("key1","value1"));System.out.println("SET:"+mcc.set("key2","value2"));System.out.println("SET:"+mcc.set("key3","value3"));System.out.println("GET:"+mcc.get("key1"));MemcachedItemitem=mcc.gets("key1");System.out.println("GETS:value="+item.getValue()+",CasUnique:"+item.getCasUnique());System.out.println("SET:"+mcc.set("key1","value1_1"));System.out.println("CAS:"+mcc.cas("key1","value1_2",item.getCasUnique()));//必须FALSESystem.out.println("getMulti:"+mcc.getMulti(newString[]{"key1","key2","key3"}));}}import com.danga.MemCached.MemCachedClient;import com.danga.MemCached.SockIOPool;import com.schooner.MemCached.MemcachedItem;public class MemcachedForJavaExample {// create a static client as most installs only need// a single instanceprotected static MemCachedClient mcc = new MemCachedClient();// set up connection pool once at class loadstatic {// server list and weightsString[] servers = { "localhost:11211", "localhost:11212", "localhost:11213" };Integer[] weights = { 3, 3, 2 };// grab an instance of our connection poolSockIOPool pool = SockIOPool.getInstance();// set the servers and the weightspool.setServers(servers);pool.setWeights(weights);pool.setHashingAlg(SockIOPool.CONSISTENT_HASH);// set some basic pool settings// 5 initial, 5 min, and 250 max conns// and set the max idle time for a conn// to 6 hourspool.setInitConn(5);pool.setMinConn(5);pool.setMaxConn(250);pool.setMaxIdle(1000 * 60 * 60 * 6);// set the sleep for the maint thread// it will wake up every x seconds and// maintain the pool sizepool.setMaintSleep(30);// set some TCP settings// disable nagle// set the read timeout to 3 secs// and don't set a connect timeoutpool.setNagle(false);pool.setSocketTO(3000);pool.setSocketConnectTO(0);// initialize the connection poolpool.initialize();}public static void main(String[] args) {System.out.println("SET: " + mcc.set("key1", "value1"));System.out.println("SET: " + mcc.set("key2", "value2"));System.out.println("SET: " + mcc.set("key3", "value3"));System.out.println("GET: " + mcc.get("key1"));MemcachedItem item = mcc.gets("key1");System.out.println("GETS: value=" + item.getValue() + ",CasUnique:"+item.getCasUnique());System.out.println("SET: " + mcc.set("key1", "value1_1"));System.out.println("CAS: " + mcc.cas("key1", "value1_2", item.getCasUnique())); //必须FALSESystem.out.println("getMulti:" + mcc.getMulti(new String[]{"key1","key2","key3"}));}}
我的代码
这个标题不好取,因为是我自己的想法,还需要大家多提意见,一起讨论。想叫“建议代码”或者“推荐代码”,觉得不合适,还是先叫“我的代码”吧,呵呵。
我的思路
1. 在原始客户端上层,根据业务需求封装MemcachedService(或叫MemcachedClient),负责缓存功能的包装。如:你的业务只需要add,set,get,gets,cas,delete业务,那就只封装这几个功能。这样做的好处是,屏蔽了各种客户端的API差异,让你的业务系统与客户端实现解耦合,如果你以后需要换客户端实现,对你的业务系统不会照成影响。
2. 一般不要直接采用new的方式在你的代码中显示使用memcached客户端实现,应该采用单例的方式使用memcached客户端实现,或者使用Spring的singleton方式配置。Memcached客户端实现是线程安全的。
3. memcached客户端一般都需要大量的配置,考虑扩展和配置修改,应该把参数设置设计为可配置的,可以写到propertis配置文件中或是使用Spring进行配置。
我的实现
业务层封装接口
Java代码 /***Memcached常用功能接口定义,用于业务层直接使用,屏蔽各种客户端实现的API差异,实现解耦客户端与业务系统的目的*无过期时间和flags支持,无append,prepend,replace,incr,decr等操作**@authorzhangpu**/publicinterfaceMemcachedClientService{Stringget(Stringkey);CacheItemgets(Stringkey);booleanadd(Stringkey,Stringvalue);booleanset(Stringkey,Stringvalue);booleancas(Stringkey,Stringvalue,longunique);booleandelete(Stringkey)booleanflushAll();}/*** Memcached 常用功能接口定义,用于业务层直接使用,屏蔽各种客户端实现的API差异,实现解耦客户端与业务系统的目的* 无过期时间和flags支持,无append,prepend,replace,incr,decr等操作* * @author zhangpu* */public interface MemcachedClientService {String get(String key);CacheItem gets(String key);boolean add(String key, String value);boolean set(String key, String value);boolean cas(String key, String value, long unique);boolean delete(String key)boolean flushAll();}
Java代码 publicclassCacheItem{privateStringkey;privateStringvalue;privatelongunique;publicCacheItem(){super();}publicCacheItem(Stringkey,Stringvalue,longunique){super();this.key=key;this.value=value;this.unique=unique;}publicStringgetKey(){returnkey;}publicvoidsetKey(Stringkey){this.key=key;}publicStringgetValue(){returnvalue;}publicvoidsetValue(Stringvalue){this.value=value;}publiclonggetUnique(){returnunique;}publicvoidsetUnique(longunique){this.unique=unique;}}
public class CacheItem {private String key;private String value;private long unique;public CacheItem() {super();}public CacheItem(String key, String value, long unique) {super();this.key = key;this.value = value;this.unique = unique;}public String getKey() {return key;}public void setKey(String key) {this.key = key;}public String getValue() {return value;}public void setValue(String value) {this.value = value;}public long getUnique() {return unique;}public void setUnique(long unique) {this.unique = unique;}}
客户端缓存服务实现
Java代码 /***Memcachedforjava客户端缓存服务实现*@authorzhangpu**/publicclassMemcachedClientJavaimplementsMemcachedClientService{MemCachedClientmmc=MemcachedClientFactory.getInstance();publicbooleanadd(Stringkey,Stringvalue){returnmmc.add(key,value);}publicbooleancas(Stringkey,Stringvalue,longunique){returnmmc.cas(key,value,unique);}publicStringget(Stringkey){return(String)mmc.get(key);}publicCacheItemgets(Stringkey){MemcachedItemitem=mmc.gets(key);returnnewCacheItem(key,(String)item.getValue(),item.getCasUnique());}publicbooleanset(Stringkey,Stringvalue){returnmmc.set(key,value);}publicbooleandelete(Stringkey){returnmmc.delete(key);}publicbooleanflushAll(){returnmmc.flushAll();}}/*** Memcached for java客户端缓存服务实现* @author zhangpu**/public class MemcachedClientJava implements MemcachedClientService {MemCachedClient mmc = MemcachedClientFactory.getInstance();public boolean add(String key, String value) {return mmc.add(key, value);}public boolean cas(String key, String value, long unique) {return mmc.cas(key, value, unique);}public String get(String key) {return (String) mmc.get(key);}public CacheItem gets(String key) {MemcachedItem item = mmc.gets(key);return new CacheItem(key, (String) item.getValue(), item.getCasUnique());}public boolean set(String key, String value) {return mmc.set(key, value);}public boolean delete(String key) {return mmc.delete(key);}public boolean flushAll() {return mmc.flushAll();}}
获取客户端实例
Java代码 /***MemcachedClient单例(JDK1.5以上)*@authorzhangpu**/publicclassMemcachedClientFactoryextendsConfigurableConstants{privatestaticvolatileMemCachedClientmmc;static{init("memcached-client.properties");//{"localhost:11211","localhost:11212","localhost:11213"};String[]servers=getProperty("memcached-servers","").split(",");Integer[]weights=null;StringweightsCfg=getProperty("memcached-weights","");if(weightsCfg!=null){String[]wcfg=weightsCfg.split(",");weights=newInteger[wcfg.length];for(inti=0;i<weights.length;i++){weights[i]=Integer.valueOf(wcfg[i]);}}else{weights=newInteger[servers.length];for(inti=0;i<weights.length;i++){weights[i]=1;}}SockIOPoolpool=SockIOPool.getInstance();pool.setServers(servers);pool.setWeights(weights);pool.setHashingAlg(SockIOPool.CONSISTENT_HASH);pool.setInitConn(getProperty("memcached-initConn",5));pool.setMinConn(getProperty("memcached-minConn",5));pool.setMaxConn(getProperty("memcached-maxConn",250));pool.setMaxIdle(1000*60*60*6);pool.setMaintSleep(30);pool.setNagle(false);pool.setSocketTO(3000);pool.setSocketConnectTO(0);pool.initialize();}privateMemcachedClientFactory(){}publicstaticMemCachedClientgetInstance(){if(mmc==null){synchronized(MemCachedClient.class){if(mmc==null){mmc=newMemCachedClient();}}}returnmmc;}}/*** MemcachedClient 单例(JDK1.5以上)* @author zhangpu**/public class MemcachedClientFactory extends ConfigurableConstants{private static volatile MemCachedClient mmc;static {init("memcached-client.properties");//{ "localhost:11211", "localhost:11212", "localhost:11213" };String[] servers = getProperty("memcached-servers","").split(",");Integer[] weights = null;String weightsCfg = getProperty("memcached-weights","");if(weightsCfg != null){String[] wcfg = weightsCfg.split(",");weights = new Integer[wcfg.length];for (int i = 0; i < weights.length; i++) {weights[i] = Integer.valueOf(wcfg[i]);}}else{weights = new Integer[servers.length];for (int i = 0; i < weights.length; i++) {weights[i] = 1;}}SockIOPool pool = SockIOPool.getInstance();pool.setServers(servers);pool.setWeights(weights);pool.setHashingAlg(SockIOPool.CONSISTENT_HASH);pool.setInitConn(getProperty("memcached-initConn",5));pool.setMinConn(getProperty("memcached-minConn",5));pool.setMaxConn(getProperty("memcached-maxConn",250));pool.setMaxIdle(1000 * 60 * 60 * 6);pool.setMaintSleep(30);pool.setNagle(false);pool.setSocketTO(3000);pool.setSocketConnectTO(0);pool.initialize();}private MemcachedClientFactory() {}public static MemCachedClient getInstance() {if (mmc == null) {synchronized (MemCachedClient.class) {if (mmc == null) {mmc = new MemCachedClient();}}}return mmc;}}
参数配置
Java代码 /***通过properties文件配置设置常量基类负责加载和读取properties属性文件并提供访问的静态工具方法**@authorzhangpu**/publicclassConfigurableConstants{protectedstaticLoglogger=LogFactory.getLog(ConfigurableConstants.class);protectedstaticPropertiesp=newProperties();protectedstaticvoidinit(StringpropertyFileName){InputStreamin=null;try{in=ConfigurableConstants.class.getClassLoader().getResourceAsStream(propertyFileName);if(in!=null)p.load(in);}catch(IOExceptione){logger.error("load"+propertyFileName+"intoConstantserror!");}finally{if(in!=null){try{in.close();}catch(IOExceptione){logger.error("close"+propertyFileName+"error!");}}}}protectedstaticStringgetProperty(Stringkey,StringdefaultValue){returnp.getProperty(key,defaultValue);}protectedstaticintgetProperty(Stringkey,intdefaultValue){try{returnInteger.parseInt(getProperty(key,""));}catch(Exceptione){returndefaultValue;}}}/*** 通过 properties 文件配置设置常量基类 负责加载和读取 properties 属性文件并提供访问的静态工具方法** @author zhangpu**/public class ConfigurableConstants {protected static Log logger = LogFactory.getLog(ConfigurableConstants.class);protected static Properties p = new Properties();protected static void init(String propertyFileName) {InputStream in = null;try {in = ConfigurableConstants.class.getClassLoader().getResourceAsStream(propertyFileName);if (in != null)p.load(in);} catch (IOException e) {logger.error("load " + propertyFileName + " into Constants error!");} finally {if (in != null) {try {in.close();} catch (IOException e) {logger.error("close " + propertyFileName + " error!");}}}}protected static String getProperty(String key, String defaultValue) {return p.getProperty(key, defaultValue);}protected static int getProperty(String key, int defaultValue) {try {return Integer.parseInt(getProperty(key, ""));} catch (Exception e) {return defaultValue;}}}
配置文件
memcached-client.properties
Properties代码 memcached-client.propertiesmemcached-servers=localhost:11211,localhost:11212,localhost:11213memcached-weights=3,3,2memcached-initConn=5memcached-minConn=5memcached-maxConn=250
memcached-client.propertiesmemcached-servers=localhost:11211,localhost:11212,localhost:11213memcached-weights=3,3,2memcached-initConn=5memcached-minConn=5memcached-maxConn=250
后续提供性能测试,spring整合,版本差异测试,及其它客户端对比。