javaEE 使用ServletContext实现服务器端简单定时更新缓存
来源:互联网 发布:清华大学软件专业课程 编辑:程序博客网 时间:2024/05/22 23:12
我在做一个门户系统的时候遇到webService的性能问题,当时由于设计中webService传递的数据是非结构化的,因此需要建立大量的链接获取数据。后期测试时webService访问很慢,大概要7秒钟才能完成一个页面的数据。当时不想再更改webService服务器以及客户端代码了,就想着实现一个缓存,用户访问门户页面的时候,不是直接访问webService来获取数据,而是直接从缓存中查找,然后每5分钟调用webService更新一下门户系统的缓存,这样来优化页面的响应时间。
首先要注册一个ServletContextListener,这个监听器有两个方法(contextInitialized,contextDestroyed)分别是web应用启动和销毁的时候调用的。
在web应用启动的时候,调用webService,获取初始数据,放在ServletConetxt中
- package com.leec.yetsoon.listener;
- import java.util.Date;
- import java.util.Map;
- import javax.servlet.ServletContext;
- import javax.servlet.ServletContextEvent;
- import javax.servlet.ServletContextListener;
- public class CacheListenter implements ServletContextListener{
- public void contextDestroyed(ServletContextEvent event) {
- System.out.println("contextDestroyed");
- }
- public void contextInitialized(ServletContextEvent event) {
- //查询数据库获得所要共享的信息,获取需要缓存的信息,以map形式保存
- Map<String, Object> cacheMap=CacheMapFactory.getCacheMap();
- //获得ServletContext实例
- ServletContext context = event.getServletContext();
- //将查询到的共享信息保存到ServletContext中 context.setAttribute();
- context.setAttribute("cacheMap", cacheMap);
- //将更新时间加入,以便实现定时刷新
- context.setAttribute("preDate", new Date());
- context.setAttribute("isRefreshing", false);
- }
- }
- package com.leec.yetsoon.listener;
- import java.util.Date;
- import java.util.Map;
- import javax.servlet.ServletContext;
- import javax.servlet.ServletRequestEvent;
- import javax.servlet.ServletRequestListener;
- public class TimeCountListener implements ServletRequestListener {
- private final static float CACHE_MAX_AGE = 5 * 60 * 1000;//定时5分钟
- public void requestDestroyed(ServletRequestEvent arg0) {
- }
- public void requestInitialized(ServletRequestEvent event) {
- ServletContext context = event.getServletContext();
- if(!(Boolean)context.getAttribute("isRefreshing")
- && ((new Date()).getTime() - ((Date)context.getAttribute("preDate")).getTime()) > CACHE_MAX_AGE){
- context.setAttribute("isRefreshing", true);
- //在这里再次查询数据库,并将ServletContext中的信息更新
- Map<String, Object> cacheMap=CacheMapFactory.getCacheMap();
- <span style="white-space:pre"> </span>context.setAttribute("cacheMap", cacheMap);
- context.setAttribute("preDate", new Date());//每次更新缓存的同时也更新时间
- context.setAttribute("isRefreshing", false);
- }
- }
- }
这样就不用每次都消耗大量资源访问webService了~
这个缓存还存在一些问题,就是某个用户请求页面的时候,监听器接收到请求,并且满足
- !(Boolean)context.getAttribute("isRefreshing")
- && ((new Date()).getTime() - ((Date)context.getAttribute("preDate")).getTime()) > CACHE_MAX_AGE
条件时,进行缓存更新,这个过程是同步的,只有等待更新完毕,页面才能显示出来,这样对某些运气不好的个别客户端来讲,这个页面响应的时间是不可忍受的。
因此可以把更新缓存的动作改成异步的。以下代码没有进行过测试:
- package com.leec.yetsoon.listener;
- import java.util.Date;
- import java.util.Map;
- import javax.servlet.ServletContext;
- import javax.servlet.ServletRequestEvent;
- import javax.servlet.ServletRequestListener;
- public class TimeCountListener implements ServletRequestListener {
- private final static float CACHE_MAX_AGE = 5 * 60 * 1000;//定时5分钟
- public void requestDestroyed(ServletRequestEvent arg0) {
- }
- public void requestInitialized(ServletRequestEvent event) {
- final ServletContext context = event.getServletContext();
- if(!(Boolean)context.getAttribute("isRefreshing")
- && ((new Date()).getTime() - ((Date)context.getAttribute("preDate")).getTime()) > CACHE_MAX_AGE){
- context.setAttribute("isRefreshing", true);
- //在这里再次查询数据库,并将ServletContext中的信息更新
- Thread t = new Thread(new Runnable(){
- public void run(){
- Map<String, Object> cacheMap=CacheMapFactory.getCacheMap();
- context.setAttribute("cacheMap", cacheMap);
- }
- });
- t.start();
- context.setAttribute("preDate", new Date());
- context.setAttribute("isRefreshing", false);
- }
- }
- }
另外一个问题,我在context中保存了一个状态--isRefreshing,每次在更新前
- context.setAttribute("isRefreshing", true);
把状态设为正在更新,更新完毕之后,把状态再修改回去
context.setAttribute("isRefreshing", false);
每次更新的时候是要检查这个状态的,如果是正在更新,就不会再次更新,但是setAttribute的操作不是原子的,因此也可能有多个用户进入到更新缓存的状态,这个进入的会不会经常发生也没有在生产条件下测试过,因此上面的这个缓存并发性很弱,能不能应用到生产环境很难保证~
- javaEE 使用ServletContext实现服务器端简单定时更新缓存
- javaEE 使用ServletContext实现服务器端简单定时更新缓存
- 基于服务器端缓存redis的简单实现
- javaEE 导航栏使用redis缓存实现
- JavaEE篇-不定时更新
- 一种自动定时更新缓存值的缓存实现
- JavaEE 使用Servlet实现简单登录页面
- 使用google guava 实现定时缓存功能
- 使用google guava 实现定时缓存功能
- 使用google guava 实现定时缓存功能
- 使用Google Guava实现定时缓存功能
- 使用Service+BroadcastReceiver实现定时更新天气
- 在服务器端实现定时任务
- Tomcat中通过JavaEE实现的WebSocket程序获取ServletContext
- Spring--简单使用quartz实现定时作业
- Spring--简单使用quartz实现定时作业
- Spring--简单使用quartz实现定时作业
- Spring--简单使用quartz实现定时作业
- 常用的OpenCV函数速查
- 装饰者模式
- 二:4.phpmyadmin 安装
- 弹出框
- 清华大学留学班2014年招生--美加英澳名校直通车
- javaEE 使用ServletContext实现服务器端简单定时更新缓存
- 中国移动互联网用户行为统计报告2014H1(完整版)
- [除錯]引動過程的目標傳回例外狀況
- 杭电3732 Ahui Writes Word (多重背包问题)
- (原创)底层最基本的也是用的最多的条件查询方法实现,有点多!(已经更新)
- jquery easyui datagrid基本功能
- JFinal框架操作oracle数据库
- Oracle中几个关于日期方面的SQL实例
- 清华大学留学班2014年招生--美加英澳名校直通车