Инъекция зависимости с Джерси 2.0

java dependency-injection jersey jersey-2.0 hk2

90170 просмотра

8 ответа

658 Репутация автора

Начиная с нуля без каких-либо предыдущих знаний о Jersey 1.x, мне трудно понять, как настроить внедрение зависимостей в моем проекте Jersey 2.0.

Я также понимаю, что HK2 доступен в Jersey 2.0, но я не могу найти документы, которые бы помогли с интеграцией в Jersey 2.0.

@ManagedBean
@Path("myresource")
public class MyResource {

    @Inject
    MyService myService;

    /**
     * Method handling HTTP GET requests. The returned object will be sent
     * to the client as "text/plain" media type.
     *
     * @return String that will be returned as a text/plain response.
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/getit")
    public String getIt() {
        return "Got it {" + myService + "}";
    }
}

@Resource
@ManagedBean
public class MyService {
    void serviceCall() {
        System.out.print("Service calls");
    }
}

pom.xml

<properties>
    <jersey.version>2.0-rc1</jersey.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey</groupId>
            <artifactId>jersey-bom</artifactId>
            <version>${jersey.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-common</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey</groupId>
        <artifactId>jax-rs-ri</artifactId>
    </dependency>
</dependencies>

Я могу заставить контейнер запускаться и обслуживать мой ресурс, но как только я добавляю @Inject в MyService, платформа выдает исключение:

SEVERE: Servlet.service() for servlet [com.noip.MyApplication] in context with path [/jaxrs] threw exception [A MultiException has 3 exceptions.  They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=MyService,parent=MyResource,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,1039471128)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.noip.MyResource errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on com.noip.MyResource
] with root cause
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=MyService,parent=MyResource,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,1039471128)
    at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74)


Мой стартовый проект доступен на GitHub: https://github.com/donaldjarmstrong/jaxrs

Автор: donnie_armstrong Источник Размещён: 25.04.2013 01:58

Ответы (8)


102 плюса

3586 Репутация автора

Решение

Вам необходимо определить AbstractBinderи зарегистрировать его в приложении JAX-RS. Связыватель определяет, как внедрение зависимостей должно создавать ваши классы.

public class MyApplicationBinder extends AbstractBinder {
    @Override
    protected void configure() {
        bind(MyService.class).to(MyService.class);
    }
}

Когда @Injectобнаруживается в параметре или поле типа, MyService.classон создается с использованием класса MyService. Чтобы использовать это связующее, его необходимо зарегистрировать в приложении JAX-RS. В вашем приложении web.xmlопределите приложение JAX-RS следующим образом:

<servlet>
  <servlet-name>MyApplication</servlet-name>
  <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
  <init-param>
    <param-name>javax.ws.rs.Application</param-name>
    <param-value>com.mypackage.MyApplication</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>MyApplication</servlet-name>
  <url-pattern>/*</url-pattern>
</servlet-mapping>

Реализуйте MyApplicationкласс (указанный выше в init-param).

public class MyApplication extends ResourceConfig {
    public MyApplication() {
        register(new MyApplicationBinder());
        packages(true, "com.mypackage.rest");
    }
}

Связующее, определяющее внедрение зависимостей, регистрируется в конструкторе класса, и мы также сообщаем приложению, где найти ресурсы REST (в вашем случае MyResource), используя packages()вызов метода.

Автор: joscarsson Размещён: 16.06.2013 11:59

2 плюса

1999 Репутация автора

Oracle рекомендует добавить аннотацию @Path ко всем типам, которые будут внедрены при объединении JAX-RS с CDI: http://docs.oracle.com/javaee/7/tutorial/jaxrs-advanced004.htm Хотя это далеко не идеально ( например, вы получите предупреждение от Джерси при запуске), я решил пойти по этому пути, что избавляет меня от необходимости поддерживать все поддерживаемые типы в подшивке.

Пример:

@Singleton
@Path("singleton-configuration-service")
public class ConfigurationService {
  .. 
}

@Path("my-path")
class MyProvider {
  @Inject ConfigurationService _configuration;

  @GET
  public Object get() {..}
}
Автор: Benjamin Mesing Размещён: 02.06.2014 01:52

0 плюса

39 Репутация автора

Если вы предпочитаете использовать Guice и не хотите объявлять все привязки, вы также можете попробовать этот адаптер:

Guice-мост-JIT-инжектор

Автор: Choi Размещён: 03.07.2014 08:18

12 плюса

2405 Репутация автора

Выбранный ответ датируется некоторое время назад. Нецелесообразно объявлять каждую привязку в пользовательском связывателе HK2. Я использую Tomcat, и мне просто нужно было добавить одну зависимость. Несмотря на то, что он был разработан для Glassfish, он отлично вписывается в другие контейнеры.

   <dependency>
        <groupId>org.glassfish.jersey.containers.glassfish</groupId>
        <artifactId>jersey-gf-cdi</artifactId>
        <version>${jersey.version}</version>
    </dependency>

Убедитесь, что ваш контейнер тоже настроен правильно ( см. Документацию ).

Автор: otonglet Размещён: 08.01.2015 07:49

49 плюса

164353 Репутация автора

Сначала просто ответить на комментарий в ответ принимает.

«Что делает связывание? Что если у меня есть интерфейс и реализация?»

Это просто читает bind( implementation ).to( contract ). Вы можете альтернативную цепочку .in( scope ). Объем по умолчанию PerLookup. Так что если вы хотите синглтон, вы можете

bind( implementation ).to( contract ).in( Singleton.class );

Там также есть в RequestScopedналичии

Кроме того, вместо bind(Class).to(Class), вы также можете bind(Instance).to(Class), который будет автоматически одиночным.


Добавление к принятому ответу

Для тех, кто пытается выяснить, как зарегистрировать вашу AbstractBinderреализацию в файле web.xml (т.е. вы не используете a ResourceConfig), кажется, что связующее не будет обнаружено при сканировании пакетов, т.е.

<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
    <param-name>jersey.config.server.provider.packages</param-name>
    <param-value>
        your.packages.to.scan
    </param-value>
</init-param>

Или это либо

<init-param>
    <param-name>jersey.config.server.provider.classnames</param-name>
    <param-value>
        com.foo.YourBinderImpl
    </param-value>
</init-param>

Чтобы заставить его работать, я должен был реализовать Feature:

import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.Provider;

@Provider
public class Hk2Feature implements Feature {

    @Override
    public boolean configure(FeatureContext context) {
        context.register(new AppBinder());
        return true;
    }
}

@ProviderАннотаций должен позволить Featureбыть подобрано сканированием пакета. Или без сканирования пакета, вы можете явно зарегистрировать Featureвweb.xml

<servlet>
    <servlet-name>Jersey Web Application</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>jersey.config.server.provider.classnames</param-name>
        <param-value>
            com.foo.Hk2Feature
        </param-value>
    </init-param>
    ...
    <load-on-startup>1</load-on-startup>
</servlet>

Смотрите также:

и для общей информации из документации Джерси


ОБНОВИТЬ

Фабрики

Помимо базовой привязки в принятом ответе, у вас также есть фабрики, на которых вы можете иметь более сложную логику создания, а также иметь доступ к информации о контексте запроса. Например

public class MyServiceFactory implements Factory<MyService> {
    @Context
    private HttpHeaders headers;

    @Override
    public MyService provide() {
        return new MyService(headers.getHeaderString("X-Header"));
    }

    @Override
    public void dispose(MyService service) { /* noop */ }
}

register(new AbstractBinder() {
    @Override
    public void configure() {
        bindFactory(MyServiceFactory.class).to(MyService.class)
                .in(RequestScoped.class);
    }
});

Затем вы можете добавить MyServiceв свой класс ресурсов.

Автор: Paul Samsotha Размещён: 26.03.2015 10:07

5 плюса

51 Репутация автора

Поздно, но я надеюсь, что это кому-то поможет.

Я определил мой JAX RS следующим образом:

@Path("/examplepath")
@RequestScoped //this make the diference
public class ExampleResource {

Затем, в моем коде, наконец, я могу ввести:

@Inject
SomeManagedBean bean;

В моем случае SomeManagedBeanэто bean-компонент ApplicationScoped.

Надеюсь, это кому-нибудь поможет.

Автор: gjijon Размещён: 06.10.2016 07:51

0 плюса

1494 Репутация автора

Для меня это работает без AbstractBinderвключения следующих зависимостей в мое веб-приложение (работает на Tomcat 8.5, Jersey 2.27):

<dependency>
    <groupId>javax.ws.rs</groupId>
    <artifactId>javax.ws.rs-api</artifactId>
    <version>2.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet</artifactId>
    <version>${jersey-version}</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.ext.cdi</groupId>
    <artifactId>jersey-cdi1x</artifactId>
    <version>${jersey-version}</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.inject</groupId>
    <artifactId>jersey-hk2</artifactId>
    <version>${jersey-version}</version>
</dependency>

Он работает с CDI 1.2 / CDI 2.0 для меня (используя Weld 2/3 соответственно).

Автор: lazlev Размещён: 09.01.2019 10:26

0 плюса

271 Репутация автора

Зависимость требуется для обслуживания Джерси, а Tomcat является сервером. где $ {jersey.version} равен 2.29.1

    <dependency>
        <groupId>javax.enterprise</groupId>
        <artifactId>cdi-api</artifactId>
        <version>2.0.SP1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-server</artifactId>
        <version>${jersey.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
        <version>${jersey.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.inject</groupId>
        <artifactId>jersey-hk2</artifactId>
        <version>${jersey.version}</version>
    </dependency>

Основной код будет следующим:

@RequestScoped
@Path("test")
public class RESTEndpoint {

   @GET
   public String getMessage() {
Автор: alokj Размещён: 28.10.2019 11:16
Вопросы из категории :
32x32