2008-11-24 144 views
16

我正在構建一個JSF + Facelets Web應用程序,其中一部分是每隔一段時間掃描一次目錄並索引任何更改的方法。此方法是處於應用程序範圍內的bean的一部分。我已經構建了TimerTask的子類來每X毫秒調用一次該方法。我的問題是讓bean初始化。我可以在頁面上引用bean,當我進入頁面時,bean被初始化,並按照指示工作;我想要的是在Web上下文初始化時初始化bean,以便它不需要頁面訪問來啓動索引方法。谷歌已經展示了一些想要這種功能的人,但除了與Spring集成之外沒有真正的解決方案,我真的不想僅僅爲了獲得這一功能。當上下文初始化時,JSF初始化應用程序bean

我試着玩過兩個帶有「加載啓動時」設置的Servlet,還有一個ServletContextListener讓事情繼續下去,並且無法獲得設置權限,要麼是因爲沒有可用的FacesContext,或者因爲我無法從JSF環境中引用bean。

有沒有什麼辦法讓Web應用程序啓動時初始化JSF bean?

回答

14

如果你的代碼調用FacesContext,它不會與JSF請求生命週期相關的線程之外工作。爲每個請求創建一個FacesContext對象,並將其放置在請求的末尾。您可以通過static call獲取它的原因是因爲它在請求開始時設置爲ThreadLocal。 FacesContext的生命週期與ServletContext的生命週期沒有關係。

也許這還不夠(聽起來你已經走下了這條路),但是你應該可以使用ServletContextListener來做你想做的事。只要確保任何對FacesContext的調用都保存在JSP的請求線程中。

的web.xml:

<listener> 
    <listener-class>appobj.MyApplicationContextListener</listener-class> 
</listener> 

實現:

public class MyApplicationContextListener implements ServletContextListener { 

    private static final String FOO = "foo"; 

    public void contextInitialized(ServletContextEvent event) { 
     MyObject myObject = new MyObject(); 
     event.getServletContext().setAttribute(FOO, myObject); 
    } 

    public void contextDestroyed(ServletContextEvent event) { 
     MyObject myObject = (MyObject) event.getServletContext().getAttribute(
       FOO); 
     try { 
      event.getServletContext().removeAttribute(FOO); 
     } finally { 
      myObject.dispose(); 
     } 
    } 

} 

您可以通過JSF應用範圍(如果沒有其他變量具有相同名稱的存在,或直接)解決這個對象:

<f:view> 
    <h:outputText value="#{applicationScope.foo.value}" /> 
    <h:outputText value="#{foo.value}" /> 
</f:view> 

如果您希望檢索JSF託管bean中的對象,您可以從ExternalContext

FacesContext.getCurrentInstance() 
      .getExternalContext().getApplicationMap().get("foo"); 
+0

這最終解決了 - 我錯過了「setAttribute」位,使它可以在JSF代碼中訪問。謝謝! – 2008-12-01 16:44:11

0

使用偵聽或時加載的啓動,試試這個:http://www.thoughtsabout.net/blog/archives/000033.html

+0

我以前使用過這個技巧,但它不適用於ServletContextListener,因爲您沒有針對 facesContext = contextFactory的請求/響應。getFacesContext(servletContext,request,response,lifecycle); 如果任何參數爲null,則失敗。 load-on-startup/init存在同樣的問題。 – 2008-11-24 19:47:31

+0

我可能是最好/更容易創建你的類在啓動和存儲它。然後,當第一次訪問jsf bean時,它將檢查該類,並使用它或將數據從一個複製到另一個。 – Loki 2008-11-25 22:45:32

0

在JSF 2+可以使用SystemEventListener來處理它。您可以將其設置爲在PostConstructApplicationEvent上對其執行初始化操作。

<system-event-listener> 
    <system-event-listener-class> 
    listeners.SystemEventListenerImpl 
    </system-event-listener-class> 
    <system-event-class> 
    javax.faces.event.PostConstructApplicationEvent 
    </system-event-class>      
</system-event-listener> 

實施看起來是這樣的:

public class SystemEventListenerImpl implements SystemEventListener { 

    @Override 
    public void processEvent(SystemEvent event) throws AbortProcessingException { 
    Application application = (Application) event.getSource(); 
    //TODO 
    } 

    @Override 
    public boolean isListenerForSource(Object source) { 
    return (source instanceof Application); 
    } 
} 

這將允許你做的不僅僅是簡單的傳值更。