java - 将 EJB 注入(inject)动态映射的 servlet

标签 java jakarta-ee servlets jboss ejb

我有一个过滤器,我在其中动态映射 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/

相关文章:

java - 如何在 Java Servlet Filter 中管理数据库连接?

jsf - 为什么 FacesServlet 不能有/*. 的 url-pattern?

jakarta-ee - JSF2 搜索框

java - 将表单输入值作为对象列表从 JSP 页面传递到 Servlet

java - 通过servlet获取sql中的上一条记录

java - 为了提高性能 out.print 是否应该使用?

java - Web 服务方法结果的类是什么?

java - 配对游戏中如何将花色应用到牌上?

java - java中链表的迭代和

java - doGet servlet 中的 InputStreamReader