2011-08-26 86 views
4

我在嘗試編寫需要通過<context-param>訪問web.xml中定義的上下文參數的CDI擴展。我覺得這樣做有兩種方式:從CDI擴展訪問servlet上下文參數

  • 以某種方式獲取ServletContext並調用getInitParameter()
  • 手動解析web.xml

不幸的是我需要的ServletContext兩種解決方案,並得到它doesn」似乎是可能的。這裏的問題是有些容器在創建ServletContext之前啓動CDI。即使在CDI啓動前ServletContext可用,似乎也無法從CDI擴展中訪問它。我試驗了一個ServletContextListener,它將ServletContext存儲在一個靜態的ThreadLocal中。這似乎工作正常,但它會造成內存泄漏,因爲我無法可靠地清理ThreadLocal

兩個更多的評論,然後回答:

  • 使用一些其他的方法來讀取配置參數(如使用JNDI)沒有選擇我,因爲我想寫一個CDI擴展與第3集黨的框架。
  • 我知道這個問題可能沒有解決方案,可以在環境/容器之間100%移植。但是如果我找到可以在大多數情況下工作的解決方案,我會很高興。

謝謝! :)

回答

0

不知道你在使用什麼容器,但它看起來像在JBoss中,至少你可以使用註釋inject the ServletContext。這不適合你嗎,還是我沒有正確理解你的CDI擴展的本質?

編輯:啊。我從來沒有使用CDI實現,但是可以創建一個ServletContextListener,它生成一個CDI事件,並將ServletContext作爲事件屬性之一。然後,您可以在您的擴展程序中監聽事件並提取ServletContext

+0

一個延伸是CDI實現的啓動過程中執行。所以不幸的是,由於自舉過程還沒有完成,這種注入在這種早期狀態下將不起作用。 – chkal

+0

不,對不起!在CDI啓動程序的這個早期階段,事件將不起作用。 – chkal

+0

我的理解是否正確:你想在創建ServletContext之前訪問'ServletContext'參數?沒有辦法等待事件發生? – Femi

0

正如你已經注意到你自己和Femi評論如果ServletContext不可用,你無法從它獲得任何東西(比如init params)。 閱讀web.xml文件是可能的,但肯定它是瘋狂的,並且不會是便攜式的,但您可以隨時嘗試在您的特定部署中做到這一點,您可以從WEB-INF讀取無題的示例here

+0

感謝您的評論。我認爲你是正確的,手動解析web.xml是唯一的選擇。但是我認爲很難在沒有ServletContext的情況下爲web.xml獲取InputStream。任何想法如何做到這一點? – chkal

4

我試圖做一些類似的事情,在JBoss 7.1上與CDI bean共享上下文。儘管它不適用於我,但我不確定是否是JBoss7.1的當前狀態導致了這些問題,因此它可能適用於您?

我所做的是對啓動的東西,有訪問ServletContext(在我的情況下,JAX-RS Application,但可能對你的監聽器或Servlet)在其訪問應用程序作用域的bean,並設置ServletContext

爲了彌補對CDI的世界裏,我用從以下URI的配方來創建bean實例: http://docs.jboss.org/weld/reference/1.1.0.Final/en-US/html/extend.html#d0e4978

相關的代碼是一樣的東西:

@SuppressWarnings("unchecked") 
public <T> T getBean(Class<T> instanceClass) throws NamingException 
{ 
    BeanManager beanManager 
     = (BeanManager) InitialContext.doLookup("java:comp/BeanManager"); 

    AnnotatedType<Object> annotatedType 
     = (AnnotatedType<Object>) beanManager.createAnnotatedType(instanceClass); 

    InjectionTarget<Object> injectionTarget 
     = beanManager.createInjectionTarget(annotatedType); 

    CreationalContext<Object> context 
     = beanManager.createCreationalContext(null); 

    Object instance = injectionTarget.produce(context); 

    injectionTarget.inject(instance, context); 
    injectionTarget.postConstruct(instance); 

    return (T) instance; 
} 

然後你可以設置成一個bean,看起來像:

package some.package; 

import javax.enterprise.context.ApplicationScoped; 
import javax.servlet.ServletContext; 

/** An application context, initialised on application startup. */ 
@ApplicationScoped 
public class AppContext 
{ 

    private ServletContext servletContext; 

    /** Return the servlet context for the current application. */ 
    public ServletContext getServletContext() 
    { 
     return servletContext; 
    } 

    public void setServletContext(ServletContext servletContext) 
    { 
     this.servletContext = servletContext; 
    } 
} 

使用網頁摘要:

getBean(AppContext.class).setServletContext(servletContext); 

在您的啓動代碼。然後,你應該只需要@Inject上下文在任何你想要的CDI構造中...... 假設它在你的servlet init之後運行或者其他什麼。

例如:

@Inject 
private AppContext appContext; 

我會好奇,如果這部作品在其他情況下...