java将EJB注入到动态映射的servlet中
我有一个过滤器,在这里我以友好的方式映射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不会被注入
@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通过过滤器进行动态注册的方式的情况下,将EJB注入到我的servlet中的正确方法是什么 通过JNDI是注入EJB的唯一方法吗 编辑1:
我已尝试按照“Will”的建议,在 以及实施的相关部分: 不幸的是,它不会使容器注入EJB,空指针仍然存在。我目前正在对该服务进行自定义类型安全的JNDI查找。显然,这比使用正确的注入要昂贵得多(如果我错了,请纠正我,我还没有做过关于性能的实验) 使用: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() );
}
}
...
Java EE 6
JBossAS7.1
# 1 楼答案
这个问题似乎与this reported bug有关,但尚未解决。对于JSF规范定义的托管bean,资源解析工作得很好,但对于CDI托管bean则不行。简单地用
@javax.faces.bean.ManagedBean
注释动态servlet类就可以解决这个问题(是的,这是一个相当丑陋的解决方案):使用JEE6(ofc)和JBoss 7.1.1和7.2.0(EAP 6.1.0 Alpha)进行测试
编辑:
动态映射servlet的问题实际上在基本JBoss体系结构中非常严重。他们使用JBossWeb(Tomcat的分叉版本)作为servlet实现,在其上下文管理代码中,它决定是通过注入还是通过常规的new实例化新组件。到目前为止,您的servlet需要以某种方式进行注释,以便通过注入进行处理:我在最初的回答中提到了@ManagedBean,但它看起来像是使用@WebServlet works进行注释
# 2 楼答案
Servlet 3.0规范,第节。4.4.3.5
添加了所有组件(servlet、筛选器和侦听器)上的资源注入[例如@EJB] 以编程方式或以编程方式创建,而不是通过 仅当组件是一个实例时,才会支持使用实例的方法 托管Bean。有关什么是托管Bean的详细信息,请参阅 托管Bean规范定义为JavaEE6和JSR299的一部分
托管Bean声明
JavaEE6托管bean被注释为
@javax.annotation.ManagedBean
,并且具有无参数构造函数。JSR299(CDI)托管bean只需要一个无参数构造函数或一个带注释的@javax.inject.Inject
构造函数回答
要启用资源注入,您需要:
在动态添加的servlet上放置
@ManagedBean
注释或
启用CDI&;包括一个空的
beans.xml
编辑
即使是动态创建servlet,容器进行创建也是很重要的。不要认为ServletContext中的创建将支持注入。这一点很模糊
使用CDI尝试:
# 3 楼答案
首先,在我的测试中,使用Glassfish V3的一个版本,它工作得很好
但是,第二,您可能与Servlet3.0规范的这一条款有冲突
值得注意的是,这些方法不能从
Filter.init()
方法调用。我最初在Servlet.init()
方法中尝试了这一点,init
方法失败,因为上下文已经初始化因此,我的实验并没有完全复制您的测试,我没有为此使用
Filter.init()
方法,而是将代码放在ServletContextListener
中。当我这么做的时候,我的@EJB
注释很荣幸编辑:
虽然听起来没有帮助,但我认为这是JBoss中的一个bug。当我最初尝试从过滤器注入您的原始代码时,Glassfish抛出了一个异常,因为您不允许在我前面提到的地方进行注入。现在,这可能是JBoss的一个“新增功能”,但显然@EJB注入处理根本不起作用。根据规范,这应该是宣传的工作