Accessing servlet context parameters from a CDI extension
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 callgetInitParameter()
- 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! :)
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...
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
.
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
精彩评论