我想知道是否有人可以提出建議:我有一個Quartz運行的計劃作業每小時更新一個對象的數組列表的方案。如何在Java servlet上下文中獲取和設置全局對象
但是我需要這個對象的數組列表對於由Tomcat創建的所有會話都是可見的。所以我在想,我在Quartz作業每小時的某個地方寫這個對象,以便每個會話都可以訪問它。
誰能說如何實現最佳效果?我想知道從Quartz作業寫入servlet上下文的對象?另一種方法是讓每個會話從數據庫表中填充對象的數組列表。
謝謝
摩根先生。
我想知道是否有人可以提出建議:我有一個Quartz運行的計劃作業每小時更新一個對象的數組列表的方案。如何在Java servlet上下文中獲取和設置全局對象
但是我需要這個對象的數組列表對於由Tomcat創建的所有會話都是可見的。所以我在想,我在Quartz作業每小時的某個地方寫這個對象,以便每個會話都可以訪問它。
誰能說如何實現最佳效果?我想知道從Quartz作業寫入servlet上下文的對象?另一種方法是讓每個會話從數據庫表中填充對象的數組列表。
謝謝
摩根先生。
是的,我會將該列表作爲應用程序範圍的屬性存儲在ServletContext
中。從數據庫中提取數據可能效率較低,因爲您只是每小時更新列表。創建ServletContextListener
可能是必要的,以便爲Quartz任務提供對ServletContext
對象的引用。 ServletContext
只能從JavaEE相關的類(如Servlets和Listener)中檢索。
編輯: 在ServletContextListener中,當您創建作業時,可以通過將作業添加到JobDataMap中來將作業傳遞給作業。
public class MyServletContextListener implements ServletContextListener{
public void contextInitialized(ServletContextEvent event){
ArrayList list = new ArrayList();
//add to ServletContext
event.getServletContext().setAttribute("list", list);
JobDataMap map = new JobDataMap();
map.put("list", list);
JobDetail job = new JobDetail(..., MyJob.class);
job.setJobDataMap(map);
//execute job
}
public void contextDestroyed(ServletContextEvent event){}
}
//Quartz job
public class MyJob implements Job{
public void execute(JobExecutionContext context){
ArrayList list = (ArrayList)context.getMergedJobDataMap().get("list");
//...
}
}
所以你說的是我有一個監聽器,它有一個方法來填充對象;此偵聽器在上下文初始化並填充對象時運行。當Quartz作業每小時運行一次時,可以通過偵聽器訪問該對象? – 2010-07-09 20:00:29
查看來自另一個答案的評論,它看起來像你已經有一個ServletContextListener啓動Quartz任務?你可以做的是在偵聽器中創建列表,然後將該列表作爲屬性添加到ServletContext中,然後將該列表傳遞給任務。然後,您可以通過調用'ServletContext#getAttribute()'來訪問Web應用程序中任何位置的列表。例如,在一個servlet中,你可以調用'(ArrayList)getServletContext()。getAttribute(「list」)'。確保你正確地同步你的列表,這樣你就不會同時讀/寫它。 – Michael 2010-07-09 21:01:59
這聽起來不錯,但有一個例外。我不確定是否可以通過Quartz的ScheduleController提交作業,然後將相同的列表傳遞給任務。 – 2010-07-09 21:18:04
那麼,如果你使用靜態字段,它們將對同一個類加載器加載的所有類都可見。我認爲至少一個應用程序的servlet最終應該排位賽。但是,這確實很髒。
定義並保證是(更)全局的對象是ServletContext。這是構成一個應用程序的一部分的所有servlet之間共享的,即從相同的web.xml
加載。有調用ServletContext的put
和get
,它們允許你將它視爲一個Map。
除此之外,您需要找到一個Tomcat服務器內所有Web應用程序通用的類。 Tomcat在裝載機方面做了很多工作,我認爲不同的Web應用程序將有不同的裝載機。你可以通過編寫你自己的課程並將該課程放在Tomcat的common
或shared
目錄中來解決這個問題。如果我正確理解this description,那麼這些類將一次提供給所有Web應用程序。最後,除了單個Tomcat服務器的限制之外,您還需要一些基於TCP/IP的機制來在JVM之間進行通信。但正如我理解你的問題,這不應該是必要的。
但是你可以訪問一個servlet之外的ServletContext嗎?我提到的石英工作是暗示他們的接口。儘管我準備使用靜態類。 – 2010-07-09 19:53:29
嗯。這個Quartz作業是否作爲Tomcat中的servlet或過濾器運行?如果是這樣,是的。如果它在外部JVM中被啓動,它將無法查看Tomcat的大腦。看看[這個Quartz文檔](http://www.quartz-scheduler.org/docs/cookbook/ServletInitScheduler.html),它看起來像Quartz將會在你的應用程序中,並且一切都會好的。 – 2010-07-09 19:59:00
至少Quartz可以訪問您的ServletContext(在所描述的兩種場景中)。我希望Quartz能夠讓API用戶也能夠訪問該上下文。 – 2010-07-09 20:02:01
你可以嘗試一些緩存解決方案,像EhCache你存儲的值,並更新他們每隔一小時。它將處理併發問題。緩存對象本身可以存儲在從Quartz作業寫入ServletContext
的好方法是將偵聽器註冊到您的作業中,該作業會通知有關更改後的值。因此,例如:
public class JobListener {
public void updateValue(Object newValue);
}
public class ServletContextCacheJobListener implements JobListener {
private ServletContext ctx;
public ServletContextJobListener(ServletContext ctx) {
this.ctx = ctx;
}
public void updateValue(Object newValue) {
Cache cache = (Cache) ctx.getAttribute("cache");
cache.update("yourKey", newValue);
}
}
你的工作將有一個List<JobListener>
,當你安排工作,你實例化的具體監聽器,並將其添加到作業。
不知道我明白你來自哪裏。你能澄清嗎?你是說我的Quartz作業應該有一個JobListener或ServletContextCacheJobListener的列表?如果後者,大概我會一次列出一個元素列表? – 2010-07-09 22:14:08
閱讀有關觀察者(聽衆)模式。而'ServletContextCacheJobListener'是一個'JobListener'因爲它實現了它。所以沒有區別 – Bozho 2010-07-10 05:08:34
在這篇SOF文章中還有一篇有關這個挑戰的討論:http://stackoverflow.com/questions/10276041/retrieve-servletcontext-reference-in-quartz-scheduler – Steve 2012-05-21 16:15:33
全局應用程序上下文就像Spring ? – PSyLoCKe 2017-04-10 21:01:43