SSH框架網(wǎng)上商城項(xiàng)目第15戰(zhàn)之線程、定時(shí)器同步首頁(yè)數(shù)據(jù)
上一節(jié)我們做完了首頁(yè)UI界面,但是有個(gè)問(wèn)題:如果我在后臺(tái)添加了一個(gè)商品,那么我必須重啟一下服務(wù)器才能重新同步后臺(tái)數(shù)據(jù),然后刷新首頁(yè)才能同步數(shù)據(jù)。這明顯不是我們想要的效果,一般這種網(wǎng)上商城首頁(yè)肯定不是人為手動(dòng)同步數(shù)據(jù)的,那么如何解決呢?我們需要用到線程和定時(shí)器來(lái)定時(shí)自動(dòng)同步首頁(yè)數(shù)據(jù)。
1. Timer和TimerTask
我們需要用到Timer和TimerTask兩個(gè)類。先來(lái)介紹下這兩個(gè)類。
Timer是一種工具類,在java.util包中,線程用其安排以后在后臺(tái)線程中執(zhí)行的任務(wù)??砂才湃蝿?wù)執(zhí)行一次,或者定期重復(fù)執(zhí)行。它有個(gè)構(gòu)造函數(shù):
Timer(boolean isDaemon) //創(chuàng)建一個(gè)新計(jì)時(shí)器,可以指定其相關(guān)的線程作為守護(hù)程序運(yùn)行。
守護(hù)線程即主線程結(jié)束后,該線程也結(jié)束,非守護(hù)線程即主線程結(jié)束后,該線程仍然繼續(xù)執(zhí)行。isDaemon為true時(shí)為守護(hù)線程。Timer類有個(gè)schedule方法可以創(chuàng)建一個(gè)任務(wù),如下:
void schedule(TimerTask task, Date firstTime, long period) //安排指定的任務(wù)在指定的時(shí)間開(kāi)始進(jìn)行重復(fù)的固定延遲執(zhí)行。 //第一個(gè)參數(shù)是指定任務(wù),即TimerTask對(duì)象;第二個(gè)參數(shù)為第一次開(kāi)啟任務(wù)時(shí)間; 第三個(gè)參數(shù)為時(shí)間間隔,即每隔多長(zhǎng)時(shí)間執(zhí)行一次
我們?cè)賮?lái)看看TimerTask,TimerTask是用來(lái)創(chuàng)建一個(gè)新的線程任務(wù)的,它實(shí)現(xiàn)了Runnable接口,如果我們要?jiǎng)?chuàng)建一個(gè)新的線程任務(wù),只需要繼承TimerTask,并重寫(xiě)run方法即可。
2. 創(chuàng)建一個(gè)新的線程任務(wù)
下面我們來(lái)創(chuàng)建一個(gè)新的線程任務(wù),用來(lái)更新后臺(tái)數(shù)據(jù):
@Component //把該對(duì)象交給Spring管理 public class ProductTimerTask extends TimerTask { @Resource private ProductService productService = null; //注入productService @Resource private CategoryService categoryService = null; //注入categoryService private ServletContext application = null; //定義一個(gè)ServletContext對(duì)象,因?yàn)槲覀兏铝撕笈_(tái)數(shù)據(jù)后,需要存入application域里面 public void setApplication(ServletContext application) { this.application = application; //通過(guò)監(jiān)聽(tīng)器將這個(gè)application對(duì)象set進(jìn)來(lái),因?yàn)檫@里是無(wú)法拿application對(duì)象的 } @Override //和監(jiān)聽(tīng)器在項(xiàng)目啟動(dòng)的時(shí)候數(shù)據(jù)初始化的邏輯一樣 public void run() { System.out.println("----run----"); List<List<Product>> bigList = new ArrayList<List<Product>>(); //bigList中存放一個(gè)裝有Category類的list // 1. 查詢出熱點(diǎn)類別 for(Category category : categoryService.queryByHot(true)) { //根據(jù)熱點(diǎn)類別id獲取推薦商品信息 List<Product> lst = productService.querByCategoryId(category.getId()); bigList.add(lst); //將裝有category的list放到bigList中 } // 2. 把查詢的bigList交給application內(nèi)置對(duì)象 application.setAttribute("bigList", bigList); //假設(shè)我們已經(jīng)拿到了application對(duì)象 } }
接下來(lái),我們修改項(xiàng)目啟動(dòng)時(shí)監(jiān)聽(tīng)器里面的內(nèi)容,原本上面的這個(gè)查詢操作是放在監(jiān)聽(tīng)器中,當(dāng)項(xiàng)目啟動(dòng)時(shí),監(jiān)聽(tīng)器開(kāi)始執(zhí)行,獲取后臺(tái)數(shù)據(jù),存到application域中,然后前臺(tái)通過(guò)jstl標(biāo)簽從application域中拿到數(shù)據(jù)。現(xiàn)在我們把這些事情交給我們定義的ProductTimerTask去做,那么監(jiān)聽(tīng)器中只要設(shè)置一下定時(shí)器,讓ProductTimerTask定時(shí)去更新一下后臺(tái)數(shù)據(jù)即可??纯幢O(jiān)聽(tīng)器中修改后的代碼:
3. 在監(jiān)聽(tīng)器中啟動(dòng)定時(shí)器
//@Component //監(jiān)聽(tīng)器是web層的組件,它是tomcat實(shí)例化的,不是Spring實(shí)例化的。不能放到Spring中 public class InitDataListener implements ServletContextListener { private ProductTimerTask productTimerTask = null; //定義一個(gè)ProductTimerTask對(duì)象 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對(duì)象 //把內(nèi)置對(duì)象交給productTimerTask,因?yàn)閜roductTimerTask里面是拿不到application的,只能通過(guò)監(jiān)聽(tīng)器set給它 productTimerTask.setApplication(event.getServletContext()); //通過(guò)設(shè)置定時(shí)器,讓首頁(yè)的數(shù)據(jù)每個(gè)一小時(shí)同步一次(配置為守護(hù)線程) new Timer(true).schedule(productTimerTask, 0, 1000*60*60);//每個(gè)一小時(shí)執(zhí)行一次productTimerTask任務(wù),即更新一下后臺(tái)數(shù)據(jù) } }
關(guān)于InitDataListener監(jiān)聽(tīng)器中原來(lái)的操作代碼,可以對(duì)比上一節(jié)中的內(nèi)容,其實(shí)就是ProductTimerTask中的更新后臺(tái)數(shù)據(jù),只不過(guò)現(xiàn)在放到TimerTask中去做了而已。這樣我們就完成了使用線程和定時(shí)器定期同步首頁(yè)數(shù)據(jù),這個(gè)時(shí)間間隔可以自己設(shè)定。
其實(shí)CSDN博客里的部分首頁(yè)數(shù)據(jù)也不是實(shí)時(shí)更新的,每天晚上會(huì)有個(gè)時(shí)間更新一次,例如左側(cè)欄目中的博客排名,閱讀排行后的顯示的閱讀量等,這些都是每天晚上更新一次,應(yīng)該就是在后臺(tái)設(shè)置了每天更新一次,原理跟這里應(yīng)該是一樣的。這樣也減輕了服務(wù)器的壓力。
本文鏈接:http://blog.csdn.net/eson_15/article/details/51387378
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java郵件發(fā)送程序(可以同時(shí)發(fā)給多個(gè)地址、可以帶附件)
- java 發(fā)送郵件的實(shí)例代碼(可移植)
- java發(fā)送郵件的具體實(shí)現(xiàn)
- java mail使用qq郵箱發(fā)郵件的配置方法
- Java Mail與Apache Mail發(fā)送郵件示例
- java中javamail發(fā)送帶附件的郵件實(shí)現(xiàn)方法
- Java讀取郵件的方法
- SSH框架網(wǎng)上商城項(xiàng)目第12戰(zhàn)之添加和更新商品功能
- SSH框架網(wǎng)上商城項(xiàng)目第17戰(zhàn)之購(gòu)物車基本功能
- SSH框架網(wǎng)上商城項(xiàng)目第25戰(zhàn)之使用java email給用戶發(fā)送郵件
相關(guān)文章
Java實(shí)現(xiàn)優(yōu)雅停止線程的有效方法詳解
這篇文章主要為大家詳細(xì)如何安全有效停止 Java 線程的,確保多線程應(yīng)用程序平穩(wěn)運(yùn)行并實(shí)現(xiàn)最佳資源管理,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12Spring?Security如何實(shí)現(xiàn)升級(jí)密碼加密方式詳解
這篇文章主要為大家介紹了Spring?Security實(shí)現(xiàn)升級(jí)密碼加密方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01Javabean基于xstream包實(shí)現(xiàn)轉(zhuǎn)XML文檔的方法
這篇文章主要介紹了Javabean基于xstream包實(shí)現(xiàn)轉(zhuǎn)XML文檔的方法,結(jié)合具體實(shí)例形式分析了xstream包用于轉(zhuǎn)換xml文件的具體使用技巧,需要的朋友可以參考下2017-05-05整理總結(jié)Java多線程程序編寫(xiě)的要點(diǎn)
這篇文章主要介紹了Java多線程程序編寫(xiě)的要點(diǎn),包括線程的狀態(tài)控制和優(yōu)先級(jí)以及線程的通信問(wèn)題等方面,非常之全面!需要的朋友可以參考下2016-01-01javaweb判斷當(dāng)前請(qǐng)求是否為移動(dòng)設(shè)備訪問(wèn)的方法
這篇文章主要為大家詳細(xì)介紹了javaweb判斷當(dāng)前請(qǐng)求是否為移動(dòng)設(shè)備訪問(wèn)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05解決SpringMVC @RequestMapping不設(shè)置value出現(xiàn)的問(wèn)題
這篇文章主要介紹了解決SpringMVC @RequestMapping不設(shè)置value出現(xiàn)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08在Spring Boot中使用Spring-data-jpa實(shí)現(xiàn)分頁(yè)查詢
如何使用jpa進(jìn)行多條件查詢以及查詢列表分頁(yè)呢?下面我將介紹兩種多條件查詢方式。具體實(shí)例代碼大家參考下本文吧2017-07-07