【问题标题】:Accessing servlet context parameters from a CDI extension从 CDI 扩展访问 servlet 上下文参数
【发布时间】:2011-08-26 05:52:52
【问题描述】:

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

  • 不知何故获得ServletContext 并致电getInitParameter()
  • 手动解析web.xml

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

在你回答之前还有两个 cmets:

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

谢谢! :)

【问题讨论】:

    标签: jakarta-ee servlets cdi


    【解决方案1】:

    我尝试在 JBoss 7.1 上与 CDI bean 共享上下文做类似的事情。虽然它对我不起作用,但我不确定是否是 JBoss7.1 的当前状态导致了问题,所以也许它对你有用?

    我所做的是在启动时访问ServletContext(在我的情况下为JAX-RS Application,但可能是一个侦听器或servlet)访问应用程序范围的bean并设置@ 987654324@在里面。

    为了连接到 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;
        }
    }
    

    使用类似的 sn-p:

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

    在您的启动代码中。然后,您应该能够在您想要的任何 CDI 构造中使用 @Inject 上下文... 假设它在您的 servlet init 或其他任何东西之后运行。

    例如:

    @Inject
    private AppContext appContext;
    

    我会很好奇这是否适用于其他情况......

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 在 CDI 实现启动期间执行扩展。所以不幸的是,由于引导过程尚未完成,因此这种注入在这个早期状态下不会起作用。
      • 不,对不起!在 CDI 启动过程的早期阶段,事件将不起作用。
      • 我理解正确吗:您想在创建ServletContext 之前访问ServletContext 参数?没有办法等待事件触发?
      • CDI 扩展仅在 CDI 容器启动期间执行。所以等待是没有办法的。问题是某些容器(例如 JBoss)在创建 ServletContext 之前引导 CDI。在其他容器(例如 Tomcat)中,可能有可能在 CDI 引导之前执行自定义 ServletContextLister,但我看不到在某处“存储” ServletContext 的选项,我可以从扩展中访问它。你看情况很棘手! :)
      【解决方案3】:

      正如您自己和 Femi 所评论的那样,如果 ServletContext 不可用,您将无法从中获取任何东西(例如 init 参数)。 读取 web.xml 文件是可能的,但可以肯定的是它很疯狂并且不可移植,但是您始终可以尝试在您的特定部署中执行此操作,您可以从 WEB-INF here 获得一个读取 smth 的示例

      【讨论】:

      • 感谢您的评论。我认为你是对的,手动解析 web.xml 是唯一的选择。但是我认为没有 ServletContext 很难为 web.xml 获得 InputStream。知道怎么做吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-08
      • 2016-05-02
      • 1970-01-01
      • 2019-03-20
      • 2012-07-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多