【问题标题】:Java EE Dependency Injection in Websphere Liberty profileWebsphere Liberty 配置文件中的 Java EE 依赖注入
【发布时间】:2016-12-31 03:53:00
【问题描述】:

我正在尝试在通过 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中开启显式发现模式

链接:

【问题讨论】:

    标签: cdi java-ee-7 websphere-liberty


    【解决方案1】:

    虽然 Scott 的建议可以解决您的问题,但以下是有关其工作原理的全貌。

    在 CDI 1.2 中,所有应用程序都默认启用 CDI。

    如果有一个空的 beans.xml 或一个带有 bean-discovery-mode="all" 的 beans.xml,则所有类都选择了 beans。

    在缺少 beans.xml 或 beans.xml with bean-discovery-mode="annotated" 的情况下,将扫描每个类以查找 beans。只有使用 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. 在.war 文件的WEB-INF 或.jar 文件的META-INF 下添加一个空的beans.xml 或beans.xml,beans-discovery-mode="all"

    更多关于bean归档的信息,请参考https://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#bean_archive

    【讨论】:

      【解决方案2】:

      您可以强制 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 -> Generate CDI Beans Deployment Descriptor Stub 来生成它,并确保从下拉列表中选择 all -down “Bean 发现模式”选择。

      缺点是性能会受到影响,因为应用程序需要更长的时间才能启动,但这是您可以做出的权衡以避免重新编译。

      【讨论】:

      • 谢谢,就是这样!更新了我自己的解决方案评论。
      【解决方案3】:

      我对 EJB 不够熟悉,但您可以尝试在您的 Service 类中添加 @Stateless 或 @Service 注解

      package my.simple.app;
      @Stateless
      //@Service
      public class HelloService {
          String createHelloMessage(String name) {
              return "Hello " + name + "!";
          }
      }
      

      编辑: 或者,如果您无法修改 HelloService,您可以使用 Producer Method http://docs.oracle.com/javaee/6/tutorial/doc/gjdid.html

      【讨论】:

      • 问题是我不想向注入的类添加任何东西,因为在某些情况下我可能无法控制它们的源代码(例如 3rd 方库)。
      猜你喜欢
      • 2014-11-23
      • 2012-11-11
      • 1970-01-01
      • 1970-01-01
      • 2013-08-07
      • 1970-01-01
      • 1970-01-01
      • 2015-02-03
      • 1970-01-01
      相关资源
      最近更新 更多