Memcached 客戶端選擇
上一篇文章 從零開始學 Java - Spring 集成 Memcached 緩存配置(一)中我們講到這篇要談客戶端的選擇,在 Java 中一般常用的有三個:
- Memcached Client for Java
- SpyMemcached
- XMemcached
他們的對比與性能我這里不討論,想了解自己搜索查看,我這里使用的是 XMemcached ,據說它的並發效果更好一些。
地址:https://github.com/killme2008/xmemcached
一些基礎的准備
首先,你要下載一個 memcached 服務端安裝一下,這是他的網址:https://github.com/memcached/memcached/wiki/ReleaseNotes,如果是 Windows 系統,自己去找安裝包安裝一下即可。啟動服務。
然后,你需要一個 xmemcached.jar 包,你可以直接通過我GitHub上的示例項目直接獲取到,我貼一個地址:https://github.com/mafly/SpringDemo/blob/master/WebContent/WEB-INF/lib/xmemcached-1.3.8.jar
開試寫代碼吧
一、在src
目錄下建立memcached.properties
配置文件
這個文件是用來存 memcached 服務器的地址、端口和權重的信息的
memcached.connectionPoolSize=10
memcached.failureMode=true
#server1
server1.memcached.host=127.0.0.1
server1.memcached.port=11211
server1.memcached.weight=4
#server2
server2.memcached.host=127.0.0.1
server2.memcached.port=11212
server2.memcached.weight=6
我這里是配置兩台服務器用以測試,不同的權重。具體文件請訪問 https://github.com/mafly/SpringDemo/blob/memcached/src/memcached.properties 查看。
二、在applicationContext.xml
文件中配置
打開applicationContext.xml
文件,在下面加入 memcached 的配置:
<!-- Memcached 配置 -->
<bean id="memcachedClientBuilder" class="net.rubyeye.xmemcached.XMemcachedClientBuilder"
p:connectionPoolSize="${memcached.connectionPoolSize}" p:failureMode="${memcached.failureMode}">
<!-- XMemcachedClientBuilder have two arguments.First is server list,and second is weights array. -->
<constructor-arg>
<list>
<bean class="java.net.InetSocketAddress">
<constructor-arg>
<value>${server1.memcached.host}</value>
</constructor-arg>
<constructor-arg>
<value>${server1.memcached.port}</value>
</constructor-arg>
</bean>
<bean class="java.net.InetSocketAddress">
<constructor-arg>
<value>${server2.memcached.host}</value>
</constructor-arg>
<constructor-arg>
<value>${server2.memcached.port}</value>
</constructor-arg>
</bean>
</list>
</constructor-arg>
<constructor-arg>
<list>
<value>${server1.memcached.weight}</value>
<value>${server2.memcached.weight}</value>
</list>
</constructor-arg>
<property name="commandFactory">
<bean class="net.rubyeye.xmemcached.command.TextCommandFactory" />
</property>
<property name="sessionLocator">
<bean class="net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator" />
</property>
<property name="transcoder">
<bean class="net.rubyeye.xmemcached.transcoders.SerializingTranscoder" />
</property>
</bean>
<!-- Use factory bean to build memcached client -->
<bean id="memcachedClient" factory-bean="memcachedClientBuilder"
factory-method="build" destroy-method="shutdown" />
這里的地址及端口就是讀取剛剛的memcached.properties
配置文件。當然,你不能忘了把配置文件讀取到 Spring 容器中管理。
三、建立cn.mayongfa.cache
包,並新增MemcachedBasis.java
基礎類
1.新建cn.mayongfa.cache
包我就說了,大家都會的,重要的是建完包之后要在applicationContext.xml
文件中配置掃描包,完成 Bean 的注入 。就是下面:
<context:component-scan base-package="cn.mayongfa.cache" />
2.新建MemcachedBasis.java
類。
@Component
public class MemcachedBasis {
@Autowired
protected MemcachedClient memcachedClient;
/**
* 失效時間(秒)3600*24 一天
*/
protected int Exptime = 3600 * 24;
/**
* 基礎數據失效時間(秒)3600*24*7 一周
*/
protected int DataExptime = this.Exptime * 7;
protected String Prefix = "SPRINGDEMO:";
}
都是我們需要用的基本信息,就是一個基類的概念,主要用於其他緩存類繼承它,就不需要重復定義這些變量了。
四、新增UserBasisCache.java
緩存類,繼承於MemcachedBasis.java
類
@Component
public class UserBasisCache extends MemcachedBasis {
private Logger log = Logger.getLogger(UserBasisCache.class);
@Autowired
private UserBasisDao userBasisDao;
/**
* 設置緩存
*
* @param model
* 用戶model
* @return
*/
public Boolean set(UserBasis model) {
Boolean result = false;
try {
result = memcachedClient.set(getCacheKey(model.getId()), super.Exptime, model);
} catch (TimeoutException | InterruptedException | MemcachedException e) {
log.error("", e);
}
return result;
}
/**
* 獲取緩存
*
* @param id
* 用戶ID
* @return
*/
public UserBasis get(long id) {
UserBasis entity = new UserBasis();
try {
entity = memcachedClient.get(getCacheKey(id));
if (entity == null || entity.getId() <= 0) {
entity = userBasisDao.getEntity(id);
this.set(entity);
}
} catch (TimeoutException | InterruptedException | MemcachedException e) {
log.error("", e);
entity = userBasisDao.getEntity(id);
}
return entity;
}
/**
* 刪除緩存
*
* @param id
* 用戶ID
* @return
*/
public Boolean delete(long id) {
try {
return memcachedClient.delete(getCacheKey(id));
} catch (TimeoutException | InterruptedException | MemcachedException e) {
log.error("", e);
}
return false;
}
/**
* 獲取緩存 Key
*
* @param id
* 用戶ID
* @return
*/
private String getCacheKey(long id) {
return super.Prefix + "UserBasis:" + id;
}
}
這個就是具體的業務邏輯的緩存的獲取、增加、修改和刪除的處理了,這里是以每個用戶來添加到緩存,只是用來演示的,具體的情況你們自己處理。
還記不記得上篇文章說:我們怎么做到緩存對代碼的侵入性,以及我們怎么更方便或者說不需要改代碼就實現緩存。 其實這個時候,我們會發現我們項目架構是分層的,分層的意義不就是為了分配職責、減小耦合和定義標准嘛。那這個時候我們如果都在實現層(Service.Imp)來實現緩存的增刪改查,那是不是 Controller 層的調用就不需要任何改動了,也不需要考慮緩存怎么實現的了,不需要去執行緩存的增刪改查了,還是像原來那樣直接調用實現層的方法就行了。
五、修改UserBasisServiceImp.java
類,實現緩存的增刪改查
最開始這個類其中的方法是這樣的:
@Override
public long Save(UserBasis entity) {
return UserBasisdao.Save(entity);
}
@Override
public Boolean Delete(long ID) {
return UserBasisdao.Delete(ID);
}
@Override
public UserBasis getEntity(long ID) {
return UserBasisdao.getEntity(ID);
}
我們改成了這樣的:
@Autowired
private UserBasisCache UserBasiscache;
@Override
public long Save(UserBasis entity) {
long id = UserBasisdao.Save(entity);
if (id > 0) {
UserBasiscache.set(entity);
}
return id;
}
@Override
public Boolean Delete(long ID) {
boolean result = UserBasisdao.Delete(ID);
if (result) {
UserBasiscache.delete(ID);
}
return result;
}
@Override
public UserBasis getEntity(long ID) {
return UserBasiscache.get(ID);
}
看出來區別了吧,就是我們在實現層處理了緩存的操作,並不需要去最外層的調用處處理了。
總結一下
上一篇文章我講了整個選擇緩存的心路歷程,雖然沒有干貨,但都是值得思考的東西,這篇文章就有了干貨,可以讓你用「最原始版」方式來靈活在項目中實現緩存。希望我的分享對你有所幫助吧,所有這些配置及代碼都可以在我的 GitHub 上關於 Spring 的示例項目看到:https://github.com/mafly/SpringDemo/tree/memcached。
又寫到凌晨一點,我睡了。