从CDI扩展访问servlet上下文参数

时间:2011-08-26 05:52:53

标签: java-ee servlets cdi

我正在尝试编写一个CDI扩展,需要通过<context-param>访问web.xml中定义的上下文参数。我认为有两种方法可以做到这一点:

  • 以某种方式获取ServletContext并致电getInitParameter()
  • 手动解析web.xml

不幸的是,我需要两个解决方案的ServletContext,并且似乎不可能。这里的问题是一些容器在创建ServletContext之前启动CDI。即使在CDI启动之前ServletContext可用,也似乎无法从CDI扩展中访问它。我尝试使用ServletContextListenerServletContext存储在静态ThreadLocal中。这似乎工作正常,但它会造成内存泄漏,因为我无法可靠地清理ThreadLocal

在你回答之前还有两条评论:

  • 使用其他方法来读取配置参数(比如使用JNDI)对我来说是没有选择,因为我正在尝试编写CDI扩展以与第三方框架集成。
  • 我知道在环境/容器之间100%可移植的问题可能没有解决方案。但如果我找到一个适用于大多数情况的解决方案,我会很高兴。

谢谢! :)

3 个答案:

答案 0 :(得分: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;

如果这在其他情况下有效,我会很好奇......

答案 1 :(得分:0)

不确定您正在使用哪个容器,但在JBoss中看起来至少可以使用注释inject the ServletContext。这不适合你,还是我没有正确理解你的CDI扩展的性质?

编辑:啊。我从未使用过CDI实现,但是可以创建一个ServletContextListener来生成一个CDI事件,其中ServletContext作为事件属性之一。然后,您可以在扩展程序中监听事件并提取ServletContext

答案 2 :(得分:0)

正如你已经注意到自己和Femi所评论的,如果ServletContext不可用,你就无法从中得到任何东西(比如init params)。 读取web.xml文件是可能的,但是肯定它很疯狂并且不可移植,但是你总是可以尝试在你的特定部署上执行它,你可以从WEB-INF here <获取一个读取smth的例子/ p>