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

Jakarta ee 从CDI扩展访问servlet上下文参数,jakarta-ee,servlets,cdi,Jakarta Ee,Servlets,Cdi,我正在尝试编写一个CDI扩展,它需要通过访问web.xml中定义的上下文参数。我认为有两种方法可以做到这一点: 以某种方式获取ServletContext并调用getInitParameter() 手动解析web.xml 不幸的是,对于这两种解决方案,我都需要ServletContext,而获得它似乎是不可能的。这里的问题是,一些容器在创建ServletContext之前启动CDI。即使ServletContext在CDI启动之前可用,似乎也无法从CDI扩展访问它。我尝试了一个Servlet

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

  • 以某种方式获取
    ServletContext
    并调用
    getInitParameter()
  • 手动解析
    web.xml
不幸的是,对于这两种解决方案,我都需要
ServletContext
,而获得它似乎是不可能的。这里的问题是,一些容器在创建
ServletContext
之前启动CDI。即使
ServletContext
在CDI启动之前可用,似乎也无法从CDI扩展访问它。我尝试了一个
ServletContextListener
,它将
ServletContext
存储在一个静态
ThreadLocal
中。这似乎工作正常,但会造成内存泄漏,因为我无法可靠地清理
ThreadLocal

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

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

谢谢!:)

不确定您使用的是什么容器,但它在JBoss中看起来像,至少您可以使用注释。这对您不起作用,还是我没有正确理解您的CDI扩展的性质


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

,正如您自己和Femi所注意到的那样,如果ServletContext不可用,则无法从中获取任何信息(如init参数)。
读取web.xml文件是可能的,但肯定是疯狂的,而且不可移植,但您可以在特定的部署中尝试这样做,您可以从web-INF中获得读取smth的示例。

我尝试在JBoss 7.1上与CDIBeans共享上下文。虽然它对我不起作用,但我不确定是否是JBoss7.1的当前状态导致了这些问题,所以也许它对您起作用

我所做的是在启动时让一些东西可以访问
ServletContext
(在我的例子中是一个JAX-RS
应用程序,但可能是一个侦听器或servlet)访问应用程序范围的bean,并在其中设置
ServletContext

为了连接到CDI世界,我使用以下URI中的配方来创建bean实例:

相关代码类似于:

@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;
}
使用类似以下代码段:

getBean(AppContext.class).setServletContext(servletContext);
在启动代码中。然后,您应该能够将上下文注入到您想要的任何CDI构造中。。。假设它是在servlet初始化之后运行的

例如:

@Inject
private AppContext appContext;

我想知道这在其他情况下是否有效…

在CDI实现启动期间执行扩展。所以不幸的是,这种注入在这种早期状态下无法工作,因为引导过程尚未完成。不,对不起!事件在CDI启动过程的早期阶段不起作用。我是否理解正确:您想在创建
ServletContext
之前访问
ServletContext
参数?无法等待事件触发?CDI扩展仅在CDI容器启动期间执行。因此,等待是没有选择的。问题是一些容器(例如JBoss)在创建ServletContext之前引导CDI。在其他容器(例如Tomcat)中,可能会在CDI引导之前执行自定义ServletContextLister,但我看不到将ServletContext“存储”在某个地方的选项,我可以从扩展访问它。你看,情况很棘手!:)谢谢你的评论。我认为您是对的,手动解析web.xml是唯一的选择。但是,我认为如果没有ServletContext,很难为web.xml获取InputStream。你知道怎么做吗?
@Inject
private AppContext appContext;