2016-08-24 4 views
2

Я пытаюсь использовать CDI в своем очень простом веб-приложении, которое работает в профиле Websphere Liberty, установленном через Docker.Инъекция зависимостей Java EE в профиле Websphere Liberty

Однако впрыска завершается с ошибкой, если я не укажу аннотацию области (например, @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: 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 (который я использую) по умолчанию только аннотированные бобы обнаружены. Для того, чтобы все бобы быть обнаружены, и режим явного открытия должен быть включен в beans.xml

Ссылки:

ответ

4

Вы можете заставить CDI лечить сервлет в качестве компонента и выполните инъекцию, изменив режим обнаружения бобов на 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 Фасоль Descriptor развертывания Stub, и обязательно выберите all из раскрывающегося меню «Режим обнаружения боба».

Недостатком является поражение производительности, так как для запуска приложения потребуется больше времени, но это компромисс, который вы можете сделать, чтобы избежать перекомпиляции.

+0

Спасибо, это было! Обновил мой собственный комментарий для решения. –

0

Я не достаточно хорошо знаком с EJB, но вы можете попытаться добавить @Stateless или @Service аннотацию к вашему классу сервиса

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

Edit: Или, если вы не можете изменить HelloService как вы упомянули после вы можете использовать Producer методhttp://docs.oracle.com/javaee/6/tutorial/doc/gjdid.html

+0

Проблема в том, что я не хочу добавлять что-либо к введенным классам, потому что могут быть ситуации, когда я не могу контролировать исходный код для них (например, сторонние библиотеки). –

+0

Возможно, это поможет: http://stackoverflow.com/a/29807389/4060470 –

3

Хотя Скотт предлагает исправить вашу проблему, вот полная картина о том, как это работает.

В CDI 1.2 все приложения с CDI включены по умолчанию.

Если у вас есть пустой beans.xml или beans.xml с bean-discovery-mode = "all", все классы выбираются для beans.

В отсутствие beans.xml или beans.xml с bean-discovery-mode = "annotated", каждый класс будет сканироваться для beans. Только классы, аннотированные аннотациями, определяющими bean-компоненты (https://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#bean_defining_annotations), рассматриваются как бобы.

В первом примере, поскольку у вас нет beans.xml, было выполнено сканирование аннотаций, определяющих bean-составляющие. Поскольку никакой аннотации, определяющей бобы, не было найдено, cdi был отключен. Как следствие, инъекция не удалась.

Чтобы включить инъекции, есть два решения: 1. аннотировать класс HelloService с определением фасоли аннотации (например, любых областей: ApplicationScoped, RequestScoped, SessionScoped, ConversationScoped, Зависимая и т.д.). Это сделает HelloService CDI bean, а затем Injection будет успешным. 2. Добавьте пустой beans.xml или beans.xml с beans-discovery-mode = "all" в WEB-INF для .war файлов или META-INF для .jar-файлов

Для получения дополнительной информации о бин-архивах, обратитесь к https://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#bean_archive.

Смежные вопросы