我有一个过滤器,我在其中动态映射 servlet 类:
@Override
public void init( FilterConfig filterConfig ) throws ServletException {
servletContext = filterConfig.getServletContext();
File directory = getConventionDirectory();
FileSystemInspector fileInspector = new FileSystemInspector();
Set<ActionInfoData> actions = fileInspector.getActions( directory );
for ( ActionInfoData action : actions ) {
servletContext
.addServlet( action.getServletName(), action.getClassName() )
.addMapping( action.getServletMapping() );
}
}
然后当我访问给定的映射时,EJB 不会被注入(inject)。
@EJB
private I18nManager i18nManager;
@Override
protected void doGet( HttpServletRequest request, HttpServletResponse response )
throws ServletException, IOException {
I18nManager i18n = i18nManager; //null
}
如果我在 web.xml 中手动创建一个映射,给定的 EJB 正在该 servlet 中运行。 这让我想知道我在运行时注册 servlet 的事实是否容器不认为这些 servlet 是托管的。
如果是这样的话,在不改变它们通过过滤器动态注册的方式的情况下,将 EJB 注入(inject)我的 servlet 的正确方法是什么?
通过 JNDI 是注入(inject)我的 EJB 的唯一方法吗?
编辑 1:
我已尝试按照“Will”的建议在 web.xml
中使用以下代码实现 ServletContextListener
类:
<listener>
<listener-class>com.megafone.web.filter.convention.InitServlet</listener-class>
</listener>
以及实现的相关部分:
...
@Override
public void contextInitialized( ServletContextEvent sce ) {
ServletContext servletContext = sce.getServletContext();
FileSystemInspector fileInspector = new FileSystemInspector();
Set<ActionInfoData> actions = fileInspector.getActions( getConventionDirectory() );
for ( ActionInfoData action : actions ) {
servletContext
.addServlet( action.getServletName(), action.getClassName() )
.addMapping( action.getServletMapping() );
}
}
...
不幸的是,它不会让容器注入(inject) EJB,空指针仍然存在。我目前正在对服务进行自定义类型安全 JNDI 查找。显然,这比使用正确的注入(inject)要昂贵得多(如果我错了,请纠正我,还没有做过关于性能的实验)。
使用:
Java EE 6
JBoss AS 7.1
最佳答案
问题似乎与 this reported bug 有关尚未解决。资源解析适用于 JSF 规范定义的托管 Bean,但不适用于 CDI 托管 Bean。简单地用 @javax.faces.bean.ManagedBean
注释您的动态 servlet 类应该可以解决这个问题(是的,这是一个非常丑陋的解决方案):
@ManagedBean
public class DynServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@EJB
private LoginService loginService;
public DynServlet() {
super();
}
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.getOutputStream().println(
"Request made to: " + getClass().getSimpleName());
response.getOutputStream().println("Login Service: " + loginService);
return;
}
}
@WebListener
public class DynamicServletLoadListener implements ServletContextListener {
public DynamicServletLoadListener() {
super();
}
@Override
public void contextDestroyed(final ServletContextEvent contextEvent) {
return;
}
@Override
public void contextInitialized(final ServletContextEvent contextEvent) {
contextEvent.getServletContext().addServlet("dynservlet", DynServlet.class)
.addMapping("/services/dynservlet");
}
}
已使用 JEE6 (ofc) 以及 JBoss 7.1.1 和 7.2.0 (EAP 6.1.0 Alpha) 进行测试。
编辑:
动态映射 servlet 的问题实际上在基础 JBoss 架构中相当深。他们使用 JBossWeb(Tomcat 的一个分支版本)作为 servlet 实现,并且在其上下文管理代码的内部,它决定是通过注入(inject)还是通过常规 new 来实例化新组件。 Afaik 截至目前,您的 servlet 需要以某种方式进行注释,以便通过注入(inject)对其进行处理:我在原始答案中提到了 @ManagedBean,但看起来使用 @WebServlet 进行注释也可以。
关于java - 将 EJB 注入(inject)动态映射的 servlet,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16389901/