2010-07-09 25 views
19

我想知道是否有人可以提出建議:我有一個Quartz運行的計劃作業每小時更新一個對象的數組列表的方案。如何在Java servlet上下文中獲取和設置全局對象

但是我需要這個對象的數組列表對於由Tomcat創建的所有會話都是可見的。所以我在想,我在Quartz作業每小時的某個地方寫這個對象,以便每個會話都可以訪問它。

誰能說如何實現最佳效果?我想知道從Quartz作業寫入servlet上下文的對象?另一種方法是讓每個會話從數據庫表中填充對象的數組列表。

謝謝

摩根先生。

+0

在這篇SOF文章中還有一篇有關這個挑戰的討論:http://stackoverflow.com/questions/10276041/retrieve-servletcontext-reference-in-quartz-scheduler – Steve 2012-05-21 16:15:33

+0

全局應用程序上下文就像Spring ? – PSyLoCKe 2017-04-10 21:01:43

回答

12

是的,我會將該列表作爲應用程序範圍的屬性存儲在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"); 
    //... 
    } 
} 
+0

所以你說的是我有一個監聽器,它有一個方法來填充對象;此偵聽器在上下文初始化並填充對象時運行。當Quartz作業每小時運行一次時,可以通過偵聽器訪問該對象? – 2010-07-09 20:00:29

+1

查看來自另一個答案的評論,它看起來像你已經有一個ServletContextListener啓動Quartz任務?你可以做的是在偵聽器中創建列表,然後將該列表作爲屬性添加到ServletContext中,然後將該列表傳遞給任務。然後,您可以通過調用'ServletContext#getAttribute()'來訪問Web應用程序中任何位置的列表。例如,在一個servlet中,你可以調用'(ArrayList)getServletContext()。getAttribute(「list」)'。確保你正確地同步你的列表,這樣你就不會同時讀/寫它。 – Michael 2010-07-09 21:01:59

+0

這聽起來不錯,但有一個例外。我不確定是否可以通過Quartz的ScheduleController提交作業,然後將相同的列表傳遞給任務。 – 2010-07-09 21:18:04

0

那麼,如果你使用靜態字段,它們將對同一個類加載器加載的所有類都可見。我認爲至少一個應用程序的servlet最終應該排位賽。但是,這確實很髒。

定義並保證是(更)全局的對象是ServletContext。這是構成一個應用程序的一部分的所有servlet之間共享的,即從相同的web.xml加載。有調用ServletContext的putget,它們允許你將它視爲一個Map。

除此之外,您需要找到一個Tomcat服務器內所有Web應用程序通用的類。 Tomcat在裝載機方面做了很多工作,我認爲不同的Web應用程序將有不同的裝載機。你可以通過編寫你自己的課程並將該課程放在Tomcat的commonshared目錄中來解決這個問題。如果我正確理解this description,那麼這些類將一次提供給所有Web應用程序。最後,除了單個Tomcat服務器的限制之外,您還需要一些基於TCP/IP的機制來在JVM之間進行通信。但正如我理解你的問題,這不應該是必要的。

+0

但是你可以訪問一個servlet之外的ServletContext嗎?我提到的石英工作是暗示他們的接口。儘管我準備使用靜態類。 – 2010-07-09 19:53:29

+0

嗯。這個Quartz作業是否作爲Tomcat中的servlet或過濾器運行?如果是這樣,是的。如果它在外部JVM中被啓動,它將無法查看Tomcat的大腦。看看[這個Quartz文檔](http://www.quartz-scheduler.org/docs/cookbook/ServletInitScheduler.html),它看起來像Quartz將會在你的應用程序中,並且一切都會好的。 – 2010-07-09 19:59:00

+0

至少Quartz可以訪問您的ServletContext(在所描述的兩種場景中)。我希望Quartz能夠讓API用戶也能夠訪問該上下文。 – 2010-07-09 20:02:01

1

你可以嘗試一些緩存解決方案,像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>,當你安排工作,你實例化的具體監聽器,並將其添加到作業。

+0

不知道我明白你來自哪裏。你能澄清嗎?你是說我的Quartz作業應該有一個JobListener或ServletContextCacheJobListener的列表?如果後者,大概我會一次列出一個元素列表? – 2010-07-09 22:14:08

+0

閱讀有關觀察者(聽衆)模式。而'ServletContextCacheJobListener'是一個'JobListener'因爲它實現了它。所以沒有區別 – Bozho 2010-07-10 05:08:34

相關問題