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

发布于 2024-12-01 15:36:57 字数 695 浏览 0 评论 0原文

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

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

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

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

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

谢谢! :)

I'm trying to write a CDI extension that needs to access the context parameters defined in web.xml via <context-param>. I think there are two ways of doing this:

  • Somehow get the ServletContext and call getInitParameter()
  • Manually parse the web.xml

Unfortunately I need the the ServletContext for both solutions and getting it doesn't seem to be possible. The problem here is that some containers startup CDI before the ServletContext is created. And even if the ServletContext would be available before CDI starts up, there seems to be no way to access it from the CDI extension. I experimented with a ServletContextListener that stores the ServletContext in a static ThreadLocal. This seems to work fine but it would create a memory leak as I'm unable to cleanup the ThreadLocal reliably.

Two more comments before you answer:

  • Using some other approach to read configuration parameters (like using JNDI) is no option for me as I'm trying to write a CDI extension for integrating with a 3rd party framework.
  • I'm aware of the fact that there will be probably no soltion for this problem that is 100% portable between environments/containers. But I would be happy if I find a solution that works in most cases.

Thanks! :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一袭水袖舞倾城 2024-12-08 15:36:57

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

我所做的是在启动时有一些东西可以访问 ServletContext (在我的例子中是 JAX-RS Application,但可能是您的侦听器或 servlet)访问应用程序-scoped 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);

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

例如:

@Inject
private AppContext appContext;

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

I tried to do something similar with sharing the context with CDI beans in general on JBoss 7.1. Although it didn't work for me, I'm not sure if it's the current state of JBoss7.1 that caused the problems, so perhaps it'll work for you?

What I did was have something on startup that has access to the ServletContext (in my case a JAX-RS Application, but probably a listener or servlet for you) access an application-scoped bean and set the ServletContext in it.

To bridge to the world of CDI, I used the recipe from the following URI to create the bean instance:
http://docs.jboss.org/weld/reference/1.1.0.Final/en-US/html/extend.html#d0e4978

The relevant code is something like:

@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;
}

which you could then set into a bean that looks like:

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;
    }
}

using a snippet like:

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

in your startup code. You should then be able to just @Inject the context in whatever CDI construct you want it in... assuming it is run after your servlet init or whatever.

For example:

@Inject
private AppContext appContext;

I'll be curious if this works in other situations...

哭泣的笑容 2024-12-08 15:36:57

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

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

Not sure what container you're using, but it looks like in JBoss at least you can just inject the ServletContext using an annotation. Would this not work for you, or am I not properly understanding the nature of your CDI extension?

EDIT: ah. I've never used the CDI implementation, but would it be possible to create a ServletContextListener that generated a CDI event with the ServletContext as one of the event properties. You could then just listen for the event in your extension and extract the ServletContext.

南…巷孤猫 2024-12-08 15:36:57

正如您自己和 Femi 所注意到的,如果 ServletContext 不可用,您就无法从中获取任何内容(例如 init params)。
读取 web.xml 文件是可能的,但可以肯定它很疯狂并且不可移植,但您始终可以尝试在特定部署上执行此操作,您可以从 WEB-INF 此处

As you have noticed yourself and Femi commented if the ServletContext is not available there is no way you can get anything from it (like init params).
Reading web.xml file is possible but for sure it's crazy and won't be portable, but you can always try to do it on your specific deployment, you can get an example of reading smth from WEB-INF here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文