【SSH网上商城项目实战15】线程、定时器同步首页数据(类似于CSDN博客定期更新排名)

转自:http://blog.csdn.net/eson_15/article/details/51387378

上一节我们做完了首页UI界面,但是有个问题:如果我在后台添加了一个商品,那么我必须重启一下服务器才能重新同步后台数据,然后刷新首页才能同步数据。这明显不是我们想要的效果,一般这种网上商城首页肯定不是人为手动同步数据的,那么如何解决呢?我们需要用到线程和定时器来定时自动同步首页数据。

1. Timer和TimerTask

        我们需要用到Timer和TimerTask两个类。先来介绍下这两个类。

        Timer是一种工具类,在Java.util包中,线程用其安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。它有个构造函数:

  1. Timer(boolean isDaemon)  
  2. //创建一个新计时器,可以指定其相关的线程作为守护程序运行。  
Timer(boolean isDaemon)
//创建一个新计时器,可以指定其相关的线程作为守护程序运行。
        守护线程即主线程结束后,该线程也结束,非守护线程即主线程结束后,该线程仍然继续执行。isDaemon为true时为守护线程。Timer类有个schedule方法可以创建一个任务,如下:

  1. void  schedule(TimerTask task, Date firstTime, long period)   
  2. //安排指定的任务在指定的时间开始进行重复的固定延迟执行。  
  3. //第一个参数是指定任务,即TimerTask对象;第二个参数为第一次开启任务时间;第三个参数为时间间隔,即每隔多长时间执行一次  
void  schedule(TimerTask task, Date firstTime, long period) 
//安排指定的任务在指定的时间开始进行重复的固定延迟执行。
//第一个参数是指定任务,即TimerTask对象;第二个参数为第一次开启任务时间;第三个参数为时间间隔,即每隔多长时间执行一次
        我们再来看看TimerTask,TimerTask是用来创建一个新的线程任务的,它实现了Runnable接口,如果我们要创建一个新的线程任务,只需要继承TimerTask,并重写run方法即可。

2. 创建一个新的线程任务

        下面我们来创建一个新的线程任务,用来更新后台数据:

  1. @Component //把该对象交给Spring管理  
  2. public class ProductTimerTask extends TimerTask {  
  3.       
  4.     @Resource  
  5.     private ProductService productService = null//注入productService  
  6.     @Resource  
  7.     private CategoryService categoryService = null//注入categoryService  
  8.       
  9.     private ServletContext application = null//定义一个ServletContext对象,因为我们更新了后台数据后,需要存入application域里面  
  10.       
  11.     public void setApplication(ServletContext application) {  
  12.         this.application = application; //通过监听器将这个application对象set进来,因为这里是无法拿application对象的  
  13.     }  
  14.       
  15.     @Override  
  16.      //和监听器在项目启动的时候数据初始化的逻辑一样  
  17.     public void run() {  
  18.         System.out.println("----run----");  
  19.         List<List<Product>> bigList = new ArrayList<List<Product>>(); //bigList中存放一个装有Category类的list  
  20.          // 1. 查询出热点类别  
  21.         for(Category category : categoryService.queryByHot(true)) {  
  22.             //根据热点类别id获取推荐商品信息  
  23.             List<Product> lst = productService.querByCategoryId(category.getId());  
  24.             bigList.add(lst); //将装有category的list放到bigList中  
  25.         }  
  26.          // 2. 把查询的bigList交给application内置对象  
  27.          application.setAttribute("bigList", bigList); //假设我们已经拿到了application对象  
  28.     }  
  29.   
  30. }  
@Component //把该对象交给Spring管理
public class ProductTimerTask extends TimerTask {
	
	@Resource
	private ProductService productService = null; //注入productService
	@Resource
	private CategoryService categoryService = null; //注入categoryService
	
	private ServletContext application = null; //定义一个ServletContext对象,因为我们更新了后台数据后,需要存入application域里面
	
	public void setApplication(ServletContext application) {
		this.application = application; //通过监听器将这个application对象set进来,因为这里是无法拿application对象的
	}
	
	@Override
	 //和监听器在项目启动的时候数据初始化的逻辑一样
	public void run() {
		System.out.println("----run----");
		List<List<Product>> bigList = new ArrayList<List<Product>>(); //bigList中存放一个装有Category类的list
		 // 1. 查询出热点类别
		for(Category category : categoryService.queryByHot(true)) {
			//根据热点类别id获取推荐商品信息
			List<Product> lst = productService.querByCategoryId(category.getId());
 			bigList.add(lst); //将装有category的list放到bigList中
		}
		 // 2. 把查询的bigList交给application内置对象
		 application.setAttribute("bigList", bigList); //假设我们已经拿到了application对象
	}

}
        接下来,我们修改项目启动时监听器里面的内容,原本上面的这个查询操作是放在监听器中,当项目启动时,监听器开始执行,获取后台数据,存到application域中,然后前台通过jstl标签从application域中拿到数据。现在我们把这些事情交给我们定义的ProductTimerTask去做,那么监听器中只要设置一下定时器,让ProductTimerTask定时去更新一下后台数据即可。看看监听器中修改后的代码:

3. 在监听器中启动定时器

  1. //@Component //监听器是web层的组件,它是tomcat实例化的,不是Spring实例化的。不能放到Spring中  
  2. public class InitDataListener implements ServletContextListener {  
  3.       
  4.     private ProductTimerTask productTimerTask = null//定义一个ProductTimerTask对象  
  5.     private ApplicationContext context = null;  
  6.       
  7.     @Override  
  8.     public void contextDestroyed(ServletContextEvent event) {  
  9.         // TODO Auto-generated method stub  
  10.   
  11.     }  
  12.   
  13.     @Override  
  14.     public void contextInitialized(ServletContextEvent event) {  
  15.   
  16.         context = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());                 
  17.         productTimerTask = (ProductTimerTask) context.getBean("productTimerTask");//从配置文件中获取ProductTimerTask对象  
  18.   
  19.         //把内置对象交给productTimerTask,因为productTimerTask里面是拿不到application的,只能通过监听器set给它  
  20.         productTimerTask.setApplication(event.getServletContext());  
  21.   
  22.         //通过设置定时器,让首页的数据每个一小时同步一次(配置为守护线程)  
  23.         new Timer(true).schedule(productTimerTask, 01000*60*60);//每个一小时执行一次productTimerTask任务,即更新一下后台数据  
  24.     }  
  25.   
  26. }  
//@Component //监听器是web层的组件,它是tomcat实例化的,不是Spring实例化的。不能放到Spring中
public class InitDataListener implements ServletContextListener {
	
	private ProductTimerTask productTimerTask = null; //定义一个ProductTimerTask对象
	private ApplicationContext context = null;
	
	@Override
	public void contextDestroyed(ServletContextEvent event) {
		// TODO Auto-generated method stub

	}

	@Override
	public void contextInitialized(ServletContextEvent event) {

		context = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());				
		productTimerTask = (ProductTimerTask) context.getBean("productTimerTask");//从配置文件中获取ProductTimerTask对象

		//把内置对象交给productTimerTask,因为productTimerTask里面是拿不到application的,只能通过监听器set给它
		productTimerTask.setApplication(event.getServletContext());

		//通过设置定时器,让首页的数据每个一小时同步一次(配置为守护线程)
		new Timer(true).schedule(productTimerTask, 0, 1000*60*60);//每个一小时执行一次productTimerTask任务,即更新一下后台数据
	}

}
        关于InitDataListener监听器中原来的操作代码,可以对比上一节中的内容,其实就是ProductTimerTask中的更新后台数据,只不过现在放到TimerTask中去做了而已。这样我们就完成了使用线程和定时器定期同步首页数据,这个时间间隔可以自己设定。

        其实CSDN博客里的部分首页数据也不是实时更新的,每天晚上会有个时间更新一次,例如左侧栏目中的博客排名,阅读排行后的显示的阅读量等,这些都是每天晚上更新一次,应该就是在后台设置了每天更新一次,原理跟这里应该是一样的。这样也减轻了服务器的压力。


        相关阅读:http://blog.csdn.net/column/details/str2hiberspring.html

        整个项目的源码下载地址:http://blog.csdn.net/eson_15/article/details/51479994

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值