您的位置:首页 > 运维架构

EJB AOP + Ehcache实现EJB方法缓存

2014-04-29 22:43 393 查看
最近在做一个J2EE的分布式项目,多个子系统之间需要通过Web
Service进行通信,项目中使用EJB发布WebService。

 
为了提高系统的响应效率决定给所有的Web Service查询方法返回值添加缓存。要给所有的查询方法统一添加缓存,首先就会想到使用AOP,然后会想到Spring
AOP。但是发布成Web Service的EJB是不受Spring管理的,于是想到了EJB中的AOP策略:Interceptor
 
实现思路如下:
给EJB的实现类添加拦截器
拦截器判断查询方法的返回值是否已在缓存中,如果在则直接返回,否则调用EJB的方法,并将返回值放到缓存中,然后将结果返回
 
 
项目中使用的缓存产品是Ehcache,使用时需要引用以下jar包
ehcache-core.jar
slf4j-api.jar
slf4j-log4j.jar
 
首先封装一个缓存处理类,功能如下
获取缓存对象
根据名称获取缓存对象
清空缓存对象
根据名称清空缓存对象
添加缓存对象

public class CacheHandler {
//缓存管理器变量
private CacheManager manager;
//缓存变量
private Cache cache;

//缓存名称
private final String cacheName="EJB_METHOD_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
URL url=getClass().getResource("/ehcache.xml");
manager=CacheManager.create(url);
cache=manager.getCache(cacheName);
//如果cache是空,則手動創建
// 当启动hibernate二级缓存时,cache为空
if(cache==null){
cache=new Cache("EJB_METHOD_CACHE", 10000, true, false, 600000, 300000);
manager.addCache(cache);
}
}

/**
* @MethodName	: getCache
* @Description	: 外部通过get方法拿到cache后,可清空cache
* @return
*/
public Cache getCache() {
return cache;
}

/**
* @MethodName	: getCacheByName
* @Description	: 根据缓存名称获取缓存
* @param cacheName	缓存名称
* @return	缓存名称对应的缓存对象
*/
public Cache getCacheByName(String cacheName){
return manager.getCache(cacheName);
}

/**
* @MethodName	: clearCache
* @Description	: 清理缓存
*/
public void clearCache(){
if(cache!=null){
cache.removeAll();
}
}

/**
* @MethodName	: clearCacheByName
* @Description	: 根据缓存名称删除缓存
* @param cacheName	缓存名称
*/
public void clearCacheByName(String cacheName){
getCacheByName(cacheName).removeAll();
}

/**
* @MethodName	: addCache
* @Description	: 用户自定义缓存
* @param cacheName	自定义缓存的名称
* @return	自定义的缓存
*/
public Cache addCache(String cacheName){
Cache customCache = manager.getCache(cacheName);
if(customCache==null){
customCache =new Cache(cacheName, 10000, false, false, 600000, 300000);
manager.addCache(customCache);
}
return customCache;
}

}


为查询方法添加缓存

 
应用于查询方法的拦截器

public class CacheInterceptor {
@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;

//获取缓存对象
Cache cache = CacheHandler.getInstance().getCache();

//如果方法名以find、query、或get开头则执行缓存策略
if(methodName.startsWith("find") || methodName.startsWith("get") || methodName.startsWith("query")){
String cacheKey = getCacheKey(targetName, methodName, arguments);
Element element = cache.get(cacheKey);
if (element == null) {
result = context.proceed(); // 执行目标方法,并保存目标方法执行后的返回值
element = new Element(cacheKey, (Serializable) result);
cache.put(element);
System.out.println("createCache-->" + cacheKey);
} else {
System.out.println("hit Cache-->" + cacheKey);
}
return element.getObjectValue();
}

//否则直接执行目标方法
return context.proceed();
}

/**
* @MethodName	: getCacheKey
* @Description	: 获得cache key的方法,cache key是Cache中一个Element的唯一标识 cache key包括
* 包名+类名+方法名+各个参数的具体指,如com.co.cache.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();
}

}


将此拦截器应用到需要添加缓存的EJB实现类上即可
其实就是一行注解:@Interceptors(CacheInterceptor.class),如下所示
@Stateless
@Remote( IJcCommonBean.class)
@TransactionManagement(TransactionManagementType.CONTAINER)
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@WebService(endpointInterface = "mgr.jc.webservice.common.IJcCommonBean",serviceName = "JcCommonService",targetNamespace = "http://common.webservice.jc.mgr/")
@Interceptors(CacheInterceptor.class)
public class JcCommonBeanImpl extends BaseMgr implements IJcCommonBean {
//此处是EJB业务逻辑方法

}

清除缓存

 
当EJB执行了增删改方法后,缓存中的数据就变成了脏数据,需要清空缓存
同样是用一个拦截器来解决,不同的是,这个拦截器是添加在EJB增删改方法上的
 
拦截器代码如下

public class CacheClearInterceptor {

@AroundInvoke
public Object clearCache(InvocationContext context) throws Exception{

//执行目标方法
Object returnObj =context.proceed();

/**************************清空本地缓存  begin**************************************/
System.out.println("清空前的缓存数:"+CacheHandler.getInstance().getCache().getSize());
//清空本地缓存
CacheHandler.getInstance().clearCache();
System.out.println("清空后的缓存数:"+CacheHandler.getInstance().getCache().getSize());
/**************************清空本地缓存  end**************************************/

return returnObj;
}

}


将此拦截器应用到增删改方法上
@Interceptors(CacheClearSyncInterceptor.class)
public void addAgency(Agency agency) {

commonEao.save(agency);

}

这样就实现了为WebService添加缓存
 
下一篇博客将为大家讲述分布式环境下的缓存同步问题
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: