EJB+memcache
首先我们通过下图 了解到memcache在系统中处于大概什么的位置
然后我们了解下Memcached简介
1.1. 什么是Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。
它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提供动态、数据库驱动网站的速度。
Memcached基于一个存储键/值对的HashMap,它并不提供冗余(复制其HashMap条目),当某个服务器停止运行或崩溃了,所有存放在服务器上的键/值对都将丢失。
但目前Memcached的客户端和代理程序可以提供多服务器的并联方式,可以提供一定的处理能力。
1.2. Memcached与其他分布式缓存的区别 Memcached与其它常用的分布式缓存(例如EhCache、OSCache、JBoss Cache)最主要的区别在于Memcached采用集中式缓存方式(即一台或多台缓存服务器为所有应用系统提供缓存能力),自身不提供集群能力,不提供缓存复制功能;而其他分布式缓存系统采用分布式缓存方式,各个应用系统内部提供数据缓存的能力,
多个缓存间采用组播或点对点的方式进行缓存同步。
在性能上来看,Memcached比其它分布式缓存系统低一半以上(未考虑大量数据在其它缓存系统进行复制的影响);但从管理方面来看,Memcached的缓存采用集中管理的模式,应用系统可以水平扩展,
而其它分布式缓存在水平扩展的同时,必须同时调整缓存复制策略,一旦应用服务器节点大量扩展,对于缓存服务器间的数据复制将成几何数增加。
然后我们从官网http://memcached.org/下载 适合自身系统的memcache安装包
下载好之后解压
因为我是windows 操作
所以解压后 直接CMD到改目录
到memcached根目录
1、安装
memcached.exe –d install
2、启动
memcached.exe -d start
现在来试试是否可以连接:
使用方法为“telnet ip 端口号”,登录后使用“stats”命令
cmd下
telnet 192.168.1.135 11211(注意:这里只能用IP 不能用 localhost 或127.0.0.1 11211端口默认的)
然后使用:stats命令可以看到memcached的使用情况如下:
time: 1255537291 服务器当前的unix时间戳
total_items: 54 从服务器启动以后存储的items总数量
connection_structures: 19 服务器分配的连接构造数
version: 1.2.6 memcache版本
limit_maxbytes: 67108864 分配给memcache的内存大小(字节)
cmd_get: 1645 get命令(获取)总请求次数
evictions: 0 为获取空闲内存而删除的items数(分配给memcache的空间用满后需 要删除旧的items来得到空间分配给新的items)
total_connections: 19 从服务器启动以后曾经打开过的连接数
bytes: 248723 当前服务器存储items占用的字节数
threads: 1 当前线程数
get_misses: 82 总未命中次数
pointer_size: 32 当前操作系统的指针大小(32位系统一般是32bit)
bytes_read: 490982 总读取字节数(请求字节数)
uptime: 161 服务器已经运行的秒数
curr_connections: 18 当前打开着的连接数
pid: 2816 memcache服务器的进程ID
bytes_written: 16517259 总发送字节数(结果字节数)
get_hits: 1563 总命中次数
cmd_set: 54 set命令(保存)总请求次数
curr_items: 28 服务器当前存储的items数量
3.一些常用命令
-p 监听的端口
-l 连接的IP地址, 默认是本机
-d start 启动memcached服务
-d restart 重起memcached服务
-d stop|shutdown 关闭正在运行的memcached服务
-d install 安装memcached服务
-d uninstall 卸载memcached服务
-u 以的身份运行 (仅在以root运行的时候有效)
-m 最大内存使用,单位MB。默认64MB
-M 内存耗尽时返回错误,而不是删除项
-c 最大同时连接数,默认是1024
-f 块大小增长因子,默认是1.25
-n 最小分配空间,key+value+flags默认是48
-h 显示帮助
到此整个的memcache安装结束
那么该怎么样集成到EJB呢?
客户端调用有两种
一种是java_memcached-release_2.6.3依赖于此包
二种是alisoft-xplatform-asf-cache-2.5.1依赖于此包
我选择的是第二种原因是阿里软件的架构师岑文初进行封装的。里面的注释都是中文的,比较好详情http://www.infoq.com/cn/articles/memcached-java
重点我就讲这种结合EJB的使用
首先对xxxEJB引入alisoft-xplatform-asf-cache-2.5.1.jar
然后配置memcache.xml文件 记住一定要放在classpath下否则找不到
<memcached>
<!--memcached Client的配置,也就是一个IMemcachedCache的配置。Name必须填,表示Cache的名称,socketpool必须填,
表示使用的远程通信连接池是哪一个,参看后面对于socketpool的定义。后面都是可选的,第三个参数表示传输的时候是否压缩,第四个参数表示默认的编码方式 -->
<client name="mclient1" socketpool="pool1" compressEnable="true" defaultEncoding="UTF-8" >
<!--errorHandler></errorHandler可定义错误处理类,一般不需要定义 -->
</client>
<client name="mclient2" socketpool="pool2" compressEnable="true" defaultEncoding="UTF-8" >
</client>
<!--socketpool是通信连接池定义,每一个memcached Client要和服务端交互都必须有通信连接池作为底层数据通信的支持,name必填,表示名字,
同时也是memcached client指定socketpool的依据,failover表示对于服务器出现问题时的自动修复。
initConn初始的时候连接数,minConn表示最小闲置连接数,maxConn最大连接数,maintSleep表示是否需要延时结束(最好设置为0,如果设置延时的话那么就不能够立刻回收所有的资源,
如果此时从新启动同样的资源分配,就会出现问题),nagle是TCP对于socket创建的算法,socketTO是socket连接超时时间,aliveCheck表示心跳检查,确定服务器的状态。
Servers是memcached服务端开的地址和ip列表字符串,weights是上面服务器的权重,必须数量一致,否则权重无效 -->
<socketpool name="pool1" failover="true" initConn="10" minConn="5" maxConn="250" maintSleep="0"
nagle="false" socketTO="3000" aliveCheck="true">
<servers>192.168.1.137:11211</servers>
<weights>5</weights>
</socketpool>
<socketpool name="pool2" failover="true" initConn="10" minConn="5" maxConn="250" maintSleep="0"
nagle="false" socketTO="3000" aliveCheck="true">
<servers>192.168.0.53:11211</servers>
<weights>5</weights>
</socketpool>
<!--虚拟集群设置,这里将几个client的cache设置为一个虚拟集群,当对这些IMemcachedCache作集群操作的时候,就会自动地对集群中所有的Cache作插入,寻找以及删除的操作,做一个虚拟交互备份 -->
<cluster name="cluster1">
<memCachedClients>mclient1,mclient2</memCachedClients>
</cluster>
</memcached>
然后创建一个类进行对象初始化
//缓存管理器变量
private ICacheManager manager;
//缓存变量
private IMemcachedCache cache;
//缓存名称
/********************************单例模式(饿汉式) begin***********************************************/
private static CacheHandler cacheHandler=new CacheHandler();
/**
* 私有构造函数
*/
private CacheHandler(){
System.out.println("---------------创建单例 begin--------------");
initCache();
System.out.println("---------------创建单例 end--------------");
}
public static CacheHandler getInstance(){
return cacheHandler;
}
/********************************单例模式(饿汉式) end***********************************************/
/**
* @MethodName : initCache
* @Description : 初始化缓存
*/
private void initCache(){
//1.创建cachemanager
manager=CacheUtil.getCacheManager(IMemcachedCache.class,MemcachedCacheManager.class.getName());;
//如果cache是空,則手動創建
if(cache==null){
manager.start();
cache = (IMemcachedCache) manager.getCache("mclient1");
}
}
/**
* @MethodName : getCache
* @Description : 外部通过get方法拿到cache后,可清空cache
* @return
*/
public IMemcachedCache getCache() {
return cache;
}
/**
* @MethodName : clearCache
* @Description : 清理缓存
*/
public void clearCache(){
if(cache!=null){
cache.clear();
}
}
因为我是测试 所以利用EJB的拦截器
首先创建一个类对查询的方法进行缓存
@AroundInvoke
public Object processCache(InvocationContext context) throws Exception{
String targetName = context.getTarget().getClass().getName();
String methodName = context.getMethod().getName();
Object[] arguments =context.getParameters();
Object result;
//获取缓存对象
IMemcachedCache cache = CacheHandler.getInstance().getCache();
//如果方法名以find、query、或get开头则执行缓存策略
if(methodName.startsWith("find") || methodName.startsWith("get") || methodName.startsWith("query")){
String cacheKey = getCacheKey(targetName, methodName, arguments);
Object element = cache.get(cacheKey);
if (element == null) {
result = context.proceed(); // 执行目标方法,并保存目标方法执行后的返回值
cache.put(cacheKey, result);
element=result;
System.out.println("==========================createCache-->" + cacheKey);
} else {
System.out.println("==========================hit Cache-->" + cacheKey);
}
return element;
}
//否则直接执行目标方法
return context.proceed();
}
/**
* @MethodName : getCacheKey
* @Description : 获得cache key的方法,cache key是Cache中一个Element的唯一标识 cache key包括
* 包名+类名+方法名+各个参数的具体指,如com.jiwu.service.UserServiceImpl.getAllUser
* @param targetName 类名
* @param methodName 方法名
* @param arguments 方法实参数组
* @return cachekey
*/
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++) {
if(arguments[i] instanceof String[]){
String[] strArray = (String[])arguments[i];
sb.append(".");
for(String str : strArray){
sb.append(str);
}
}else{
sb.append(".").append(arguments[i]);
}
}
}
return sb.toString();
}
然后manager引用的时候 只要在类上引用即可 例如以下
@Interceptors(CacheInterceptor.class)
public class AdminManagerImpl implements IAdminManager
这样的话就会对该类中所有的find,get,query 开始的方法进行拦截 缓存
由此整个EJB和memcache已关联,部署的时候还需要在deploy 同等目录的LIB下放入引用alisoft-xplatform-asf-cache-2.5.1.jar
OK启动你的JBOSS 打上你的断点看是否已经成功