Инъекционная инъекция с Джерси 2.0

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

Я также понимаю, что HK2 доступен в Джерси 2.0, но я не могу найти документы, которые помогают интеграции с Джерси 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

  2.0-rc1 UTF-8     org.glassfish.jersey jersey-bom ${jersey.version} pom import      org.glassfish.jersey.core jersey-common   org.glassfish.jersey.core jersey-server   org.glassfish.jersey jax-rs-ri   

Я могу заставить контейнер запускать и обслуживать мой ресурс, но как только я добавлю @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

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

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

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

  MyApplication org.glassfish.jersey.servlet.ServletContainer  javax.ws.rs.Application com.mypackage.MyApplication  1   MyApplication /*  

MyApplication class MyApplication (указанный выше в init-param ).

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

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

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

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

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

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

RequestScoped также RequestScoped

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


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

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

 org.glassfish.jersey.servlet.ServletContainer  jersey.config.server.provider.packages  your.packages.to.scan   

Или это либо

  jersey.config.server.provider.classnames  com.foo.YourBinderImpl   

Чтобы заставить его работать, мне пришлось реализовать 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 @Provider сканированием пакетов. Или без сканирования пакетов вы можете явно зарегистрировать Feature в web.xml

  Jersey Web Application org.glassfish.jersey.servlet.ServletContainer  jersey.config.server.provider.classnames  com.foo.Hk2Feature   ... 1  

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

  • Пользовательский метод Параметр Инъекции с Джерси
  • Как вставить объект в контекст запроса трикотажа?
  • Как правильно настроить EntityManager в приложении jersey / hk2?
  • Запросить инъекционную инъекцию в синглтоны

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

  • Индивидуальное управление инъекциями и жизненным циклом

ОБНОВИТЬ

Заводы

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

 public class MyServiceFactory implements Factory { @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 в свой class ресурсов.

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

   org.glassfish.jersey.containers.glassfish jersey-gf-cdi ${jersey.version}  

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

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

У меня JAX RS определяется следующим образом:

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

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

 @Inject SomeManagedBean bean; 

В моем случае SomeManagedBean является компонентом ApplicationScoped.

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

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() {..} } 

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

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

  • Лучшая практика аутентификации на основе токенов REST с JAX-RS и Джерси
  • Давайте будем гением компьютера.