我正在尝试在我通过Docker安装的Websphere Liberty配置文件中运行的非常简单的Web应用程序中使用CDI。
然而,注入失败,除非我在注入的bean上指定范围注释(例如@ApplicationScoped
),尽管根据许多在线教程(例如this),Java EE规范不要求这样做
以下是失败的代码:
HelloWorldServlet.java
package my.simple.app;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/HelloWorld")
public class HelloWorldServlet extends HttpServlet {
static String PAGE_HEADER = "<html><head /><body>";
static String PAGE_FOOTER = "</body></html>";
@Inject
HelloService helloService;
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
writer.println(PAGE_HEADER);
writer.println("<h1>" + helloService.createHelloMessage("World") + "</h1>");
writer.println(PAGE_FOOTER);
writer.close();
}
}
HelloService.java
package my.simple.app;
public class HelloService {
String createHelloMessage(String name) {
return "Hello " + name + "!";
}
}
server.xml(Docker镜像是websphere-liberty:javaee7)
<server description="default servlet engine">
<httpEndpoint id="defaultHttpEndpoint" host="*" httpPort="9080" httpsPort="9443" />
<!-- Enable features -->
<featureManager>
<feature>servlet-3.1</feature>
<feature>cdi-1.2</feature>
</featureManager>
</server>
但是我收到此错误
Error 404: javax.servlet.UnavailableException: SRVE0319E: For the [my.simple.app.HelloWorldServlet] servlet, my.simple.app.HelloWorldServlet servlet class was found, but a resource injection failure has occurred. The @Inject java.lang.reflect.Field.helloService reference of type my.simple.app.HelloService for the null component in the app.war module of the app application cannot be resolved.
但是,一旦我将@ApplicationScoped
添加到HelloService,它就会开始工作。
我做错了什么?
解决方案:
在CDI1.2(我正在使用)中,默认情况下只会发现带注释的bean。要发现所有bean,需要在beans.xml
链接:
答案 0 :(得分:5)
您可以强制CDI将servlet视为bean,并通过将bean发现模式更改为all
来执行注入。
This article提供了一些有用的背景知识和示例:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="all">
</beans>
或者,在WDT中,您可以通过右键单击项目并选择 Java EE Tools - &gt;来生成此项。生成CDI Bean部署描述符存根,并确保从下拉菜单“Bean发现模式”选择中选择all
。
缺点是应用程序需要更长的时间才能启动,但这是一个可以避免重新编译的权衡。
答案 1 :(得分:3)
虽然斯科特建议解决你的问题,但这里有关于它如何运作的全貌。
在CDI 1.2中,默认情况下所有应用程序都启用了CDI。
如果存在空beans.xml或带有bean-discovery-mode =&#34; all&#34;的beans.xml,则所有类都选择使用bean。
如果没有带bean-discovery-mode =&#34;注释&#34;的beans.xml或beans.xml,将扫描每个类的bean。只有使用bean定义注释(https://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#bean_defining_annotations)注释的类才被视为bean。
在您的第一个示例中,由于您没有beans.xml,因此执行了对bean定义注释的扫描。由于未找到定义注释的bean,因此禁用了cdi。结果,注射失败了。
要启用注射,有两种解决方案: 1.使用定义注释的bean注释类HelloService(例如,任何范围:ApplicationScoped,RequestScoped,SessionScoped,ConversationScoped,Dependent等)。这将使HelloService成为CDI bean,然后注入将成功。 2.使用beans-discovery-mode =&#34; all&#34;添加空beans.xml或beans.xml。在.war文件的WEB-INF下或.jar文件的META-INF
有关bean档案的更多信息,请参阅https://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#bean_archive。
答案 2 :(得分:0)
我对EJB不够熟悉,但您可以尝试将@Stateless或@Service注释添加到Service类
package my.simple.app;
@Stateless
//@Service
public class HelloService {
String createHelloMessage(String name) {
return "Hello " + name + "!";
}
}
修改强> 或者,如果您在使用生产者方法 http://docs.oracle.com/javaee/6/tutorial/doc/gjdid.html
之后无法修改 HelloService