javaEE 使用ServletContext实现服务器端简单定时更新缓存
2014-07-14 17:14
405 查看
我在做一个门户系统的时候遇到webService的性能问题,当时由于设计中webService传递的数据是非结构化的,因此需要建立大量的链接获取数据。后期测试时webService访问很慢,大概要7秒钟才能完成一个页面的数据。当时不想再更改webService服务器以及客户端代码了,就想着实现一个缓存,用户访问门户页面的时候,不是直接访问webService来获取数据,而是直接从缓存中查找,然后每5分钟调用webService更新一下门户系统的缓存,这样来优化页面的响应时间。
首先要注册一个ServletContextListener,这个监听器有两个方法(contextInitialized,contextDestroyed)分别是web应用启动和销毁的时候调用的。
在web应用启动的时候,调用webService,获取初始数据,放在ServletConetxt中
[java] view
plaincopy
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);
}
}
其次,还要再注册一个ServletRequestListener,监听每次客户端请求,当请求到来的时间比缓存中的上次更新时间超过5分钟的时候,调用webService,更新缓存。
[java] view
plaincopy
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了~
这个缓存还存在一些问题,就是某个用户请求页面的时候,监听器接收到请求,并且满足
[java] view
plaincopy
!(Boolean)context.getAttribute("isRefreshing")
&& ((new Date()).getTime() - ((Date)context.getAttribute("preDate")).getTime()) > CACHE_MAX_AGE
条件时,进行缓存更新,这个过程是同步的,只有等待更新完毕,页面才能显示出来,这样对某些运气不好的个别客户端来讲,这个页面响应的时间是不可忍受的。
因此可以把更新缓存的动作改成异步的。以下代码没有进行过测试:
[java] view
plaincopy
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,每次在更新前
[java] view
plaincopy
context.setAttribute("isRefreshing", true);
把状态设为正在更新,更新完毕之后,把状态再修改回去
context.setAttribute("isRefreshing", false);
每次更新的时候是要检查这个状态的,如果是正在更新,就不会再次更新,但是setAttribute的操作不是原子的,因此也可能有多个用户进入到更新缓存的状态,这个进入的会不会经常发生也没有在生产条件下测试过,因此上面的这个缓存并发性很弱,能不能应用到生产环境很难保证~
首先要注册一个ServletContextListener,这个监听器有两个方法(contextInitialized,contextDestroyed)分别是web应用启动和销毁的时候调用的。
在web应用启动的时候,调用webService,获取初始数据,放在ServletConetxt中
[java] view
plaincopy
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);
}
}
其次,还要再注册一个ServletRequestListener,监听每次客户端请求,当请求到来的时间比缓存中的上次更新时间超过5分钟的时候,调用webService,更新缓存。
[java] view
plaincopy
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了~
这个缓存还存在一些问题,就是某个用户请求页面的时候,监听器接收到请求,并且满足
[java] view
plaincopy
!(Boolean)context.getAttribute("isRefreshing")
&& ((new Date()).getTime() - ((Date)context.getAttribute("preDate")).getTime()) > CACHE_MAX_AGE
条件时,进行缓存更新,这个过程是同步的,只有等待更新完毕,页面才能显示出来,这样对某些运气不好的个别客户端来讲,这个页面响应的时间是不可忍受的。
因此可以把更新缓存的动作改成异步的。以下代码没有进行过测试:
[java] view
plaincopy
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,每次在更新前
[java] view
plaincopy
context.setAttribute("isRefreshing", true);
把状态设为正在更新,更新完毕之后,把状态再修改回去
context.setAttribute("isRefreshing", false);
每次更新的时候是要检查这个状态的,如果是正在更新,就不会再次更新,但是setAttribute的操作不是原子的,因此也可能有多个用户进入到更新缓存的状态,这个进入的会不会经常发生也没有在生产条件下测试过,因此上面的这个缓存并发性很弱,能不能应用到生产环境很难保证~
相关文章推荐
- javaEE 使用ServletContext实现服务器端简单定时更新缓存
- 使用Hashtable实现简单缓存功能
- Spring--简单使用quartz实现定时作业
- Demo之JavaEE的使用Ajax简单实现Google的Suggestion
- android AppWidget的使用以及利用TimerTask实现widget的定时更新
- 使用WeakReference 与 ReferenceQueue 简单实现弱引用缓存
- Spring--简单使用quartz实现定时作业
- java中读写锁的实现及使用读写锁简单实现缓存系统的实例
- 使用google guava 实现定时缓存功能
- 使用NSURLProtocol实现UIWebView的离线缓存的简单实现
- Spring -- 简单使用quartz实现定时作业
- Asp.net使用异步缓存方法实现页面及时更新
- asp.net 使用驻留在页面中的Cache缓存常用可定时更新的数据
- 一种自动定时更新缓存值的缓存实现
- Spring--简单使用quartz实现定时作业
- Spring--简单使用quartz实现定时作业
- asp.net 使用驻留在页面中的Cache缓存常用可定时更新的数据
- asp.net 使用驻留在页面中的Cache缓存常用可定时更新的数据[转]
- 使用EF6和MVC5实现一个简单的选课系统--使用EF6更新相关数据(8/12)
- Java中读写锁的实现及使用读写锁简单实现缓存系统的实例