浏览 5461 次
锁定老帖子 主题:基于拦截器的缓存实现参考
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2005-01-11
// 此处拦截所有business facade调用 IF (读方法); key = (根据方法签名计算缓存key); value = (根据key取缓存数据); IF (value == null); value = (实际调用被拦截方法); (key:value放入缓存); RETURN value ELSE IF (写方法); (清空所有缓存); RETURN (实际调用被拦截方法); ELSE RETURN (实际调用被拦截方法); 请注意,这个缓存的清空策略很简单:一旦调用写方法,便清空所有缓存。因此它适用的范围也很窄:仅仅适用于读方法的调用频率远远高于写方法的情况。我目前在做的是一个网站,大概每天只在早上更新几篇文章,一整天阅读文章则有十万次左右,因此恰好适用这个缓存策略。具体的实现参见附件。 虽然这个拦截器很简单,但是值得一提的是,它封装了一切与缓存相关的逻辑:是否需要做缓存;一个方法是读方法还是写方法,或者是与缓存无关的普通方法;使用什么缓存实现……这些都被封装在拦截器中。需要改变缓存策略时,只需要修改这一个地方,完全不会影响到client代码。并且对client代码也没有任何约束,business facade返回任何值(包括int等原生类型)都可以照单全收。 某天下午抽空一小时的作品。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2005-01-11
两个问题:
1.缓存机制放在BusinessFacade有什么好处吗?通常我的做法是放在数据访问层。 2.下载代码中是否缺少加锁的机制? |
|
返回顶楼 | |
发表时间:2005-01-11
partech 写道 两个问题:
1.缓存机制放在BusinessFacade有什么好处吗?通常我的做法是放在数据访问层。 2.下载代码中是否缺少加锁的机制? 1、实现比较简单。数据访问层那边,Hibernate可以配置一个pluggable的cache,所以我也懒得做。 2、是。目前根本没考虑。 |
|
返回顶楼 | |
发表时间:2005-01-11
这种方法有点问题吧?
会在缓存中造成数据的冗余和一致性问题。 |
|
返回顶楼 | |
发表时间:2005-01-11
很多时候需要deep clone
|
|
返回顶楼 | |
发表时间:2005-01-12
前几天看到一篇blog也是写基于Spring AOP的缓存实现。这几天自己也打算写一个,我和gigix的想法基本很像。应该不需要deepclone的,对于方法结果返回的是可序列化对象应该都适用吧?数据冗余和一致性问题也不会造成,因为生成的Key肯定是唯一的,并且在每次写方法时同时都会更新缓存中的数据。
|
|
返回顶楼 | |
发表时间:2005-01-14
这样做法我觉得可能有些问题,
假如系统中有 getUserById() getUserByName() 而按照你的算法,上面两个方法的cacheKey是不一样的,我觉得要找到一种办法,让user cache只有一个的。 同理,你expire cache的时候也最好能够唯一确定需要expire的Cache。 否则这样的Cache系统应用面实在是太窄了,基本只能是信息发布网站,如果真的如此,那就索性把信息发布成static html好了,更快咯。。。 我自己用annontation的Cache demo code这么做的。 /** * Take it easy guy, just as a proof of concept :); * @@CacheAttribute(type="demo.User",key="java.lang.Long",action="read"); * @param id * @return */ public User getUser(Long id);{ try { return new UserImpl(userDAO.getUserEntityById(id););; } catch (DAOException e); { throw new UserNotFoundException("User with id=" + id + " not found!");; } } /** * @@CacheAttribute(type="demo.User",key="java.lang.String",action="read"); * @param name * @return */ public User getUser(String name);{ try { return new UserImpl(userDAO.getUserEntityByName(name););; } catch (DAOException e); { throw new UserNotFoundException("User with name=" + name + " not found!");; } } /** * @@CacheAttribute(type="demo.User",value="demo.User",action="invalid"); * @@TransactionAttribute(type="required"); * @param user */ public void deleteUser(User user);{ userDAO.deleteUser((UserEntity);user.getEntity(););; } 这里,我在每个需要Cache Interceptor拦截的方法上都加了 @@CacheAttribute(type="demo.User",key="java.lang.String",action="read") 这样的注释,CacheInterceptor会读取这个注释,然后根据里面的Type,来从CacheManager中得到对应的Cache,根据对应的Action进行操作。 这里有2个问题: (1)一个业务方法可能有多个参数,比如getFoo(Bar bar1,Bar bar2)。那么在Read action的时候,如何确定那个bar?是被Cache的BO的key? 目前我的系统这类需要Cache的read方法只有一个参数,因为一般是通过PK或者来拿对象的。如果真的有多个参数,也可以通过在parameter上添加annontation的方法来确定,但是我担心性能上恐怕有一点点损失,而且也不确定JDK1.5的annontation是否支持。 (2)你在expire cache的时候,同样需要这个Key或者被Cache的Object本身,如何从被拦截的业务方法中获得? 我现在是通过对CacheAttribute的参数增加不同的语义来实现,但是感觉不是最优雅。 权当作抛砖引玉,希望牛人不吝赐教。 |
|
返回顶楼 | |