我有一个过滤器,我在其中映射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中手动创建一个映射,那个servlet中的给定EJB正在工作。 这让我想知道我在运行时注册servlet的事实是不是将这些servlet视为托管。
如果是这样的话,将EJB注入我的servlet的正确方法是什么,而不改变它们通过过滤器进行dinamically注册的方式?
通过JNDI是注入我的EJB的唯一方法吗?
编辑1:
我尝试使用ServletContextListener
中的以下代码按照“Will”的建议实现web.xml
类:
<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() );
}
}
...
不幸的是,它不会使容器注入EJB并且空指针仍然存在。我目前正在为服务进行自定义类型安全的JNDI查找。显然,这比使用正确的注射要昂贵得多(如果我错了就纠正我,没有做过关于性能的实验)。
使用:
Java EE 6
JBoss AS 7.1
答案 0 :(得分:3)
Servlet 3.0 Spec,Sect。 4.4.3.5 强>
资源注入 [例如添加了所有组件(Servlet,过滤器和监听器)的@EJB] 以编程方式或以编程方式创建,而不是通过 采用实例的方法,只有在组件为a时才支持 托管Bean 。有关什么是Managed Bean的详细信息,请参阅 Managed Bean规范定义为Java EE 6和JSR 299的一部分。
管理Bean声明
Java EE 6托管bean带有注释@javax.annotation.ManagedBean
并且具有无参数构造函数。 JSR 299(CDI)托管bean只需要一个无参数构造函数或带注释的构造函数@javax.inject.Inject
。
<强>答案强>
要启用资源注入,您需要:
在动态添加的servlet上放置@ManagedBean
注释
或者
启用CDI&amp;包含空beans.xml
修改强>
即使您是动态创建servlet,容器也必须完成创建。不要认为ServletContext中的创建将支持注入。 Servlet doc在这里很模糊。
使用CDI尝试:
servletContext.addServlet("your servlet name", @Inject YourServletClass servlet)
答案 1 :(得分:3)
问题似乎与this reported bug有关,但尚未解决。资源解析对于JSF规范定义的Managed Beans来说效果很好,但不适用于CDI Managed Beans。简单地使用@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实现,并且在其上下文管理代码的内容中,它确定了通过注入或常规 new 实例化新组件的方法。 Afaik截止日期,您的servlet需要以某种方式进行注释才能通过注入进行处理:我在原始答案中提到了@ManagedBean,但它看起来像使用@WebServlet进行注释也适用。
答案 2 :(得分:0)
首先,在我的测试中,使用Glassfish V3版本可以正常工作。
但是,第二,你很可能违反了Servlet 3.0规范的这一条款。
自Servlet 3.0以来,ServletContext中添加了以下方法 启用servlet,过滤器和url的编程定义 他们映射到的模式。这些方法只能在调用期间调用 从contexInitialized初始化应用程序 ServletContextListener实现的方法或来自 ServletContainerInitializer实现的onStartup方法。
值得注意的是,无法从Filter.init()
方法调用这些方法。我最初在Servlet.init()
方法中尝试过此操作,init
方法失败,因为上下文已经初始化。
所以,我的实验没有完全复制你的测试 - 我没有使用Filter.init()
方法,而是将代码放在ServletContextListener
中。当我这样做时,我的@EJB
注释得到了尊重。
编辑:
听起来没有帮助,我建议这是JBoss中的一个错误。当我最初使用Filter的注入尝试原始代码时,Glassfish引发了异常,因为除了前面提到的那样,你不允许进行注射。现在也许这是JBoss的“附加功能”,但显然@EJB注入处理根本不起作用。根据规范,这应该像宣传的那样工作。