标签:des style blog http java 使用
最近在做一个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添加缓存
下一篇博客将为大家讲述分布式环境下的缓存同步问题
EJB AOP + Ehcache实现EJB方法缓存,码迷,mamicode.com
标签:des style blog http java 使用
原文地址:http://blog.csdn.net/wzwenhuan/article/details/24742039