Инъекция зависимости с Джерси 2.0
начиная с нуля, без каких-либо предыдущих Джерси 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");
}
}
пом.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
6 ответов:
необходимо указать
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"); } }
связыватель, задающий инъекцию зависимостей, регистрируется в конструкторе класса, и мы также сообщаем приложению, где найти остальные ресурсы (в вашем случае,
MyResource
) С помощьюpackages()
вызов метода.
сначала просто ответить на комментарий в принимает ответ.
" что делает bind? Что если у меня есть интерфейс и реализация?"
он просто читает
bind( implementation ).to( contract )
. Вы можете альтернативная цепь.in( scope )
. Область действия по умолчаниюPerLookup
. Так что если вы хотите синглтон, вы можетеbind( implementation ).to( contract ).in( Singleton.class );
есть еще и
RequestScoped
скачатькроме того, вместо
bind(Class).to(Class)
, вы можете такжеbind(Instance).to(Class)
, который будет автоматически быть одиночка.
добавлять к принято отвечать
для тех, кто пытается выяснить, как зарегистрировать свой
AbstractBinder
реализация в веб.xml (т. е. вы не используете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; } }
The
@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>
Читайте Также:
- впрыска параметра изготовленного на заказ метода с Джерси
- как ввести объект в контекст запроса Джерси?
- Как правильно настроить EntityManager в a Джерси применения / hk2?
- запрос прицельной инъекции в синглтоны
и для общей информации из Джерси документация
обновление
фабрики
помимо основной привязки в принятом ответе, у вас также есть фабрики, где вы можете иметь более сложное создание логика, а также иметь доступ к контекстной информации запроса. Например
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
в своем классе ресурсом.
выбранный ответ датируется некоторое время назад. Это не практично, чтобы объявить все привязки в пользовательском HK2 Биндер. Я использую Tomcat, и мне просто нужно было добавить одну зависимость. Несмотря на то, что он был разработан для Glassfish, он идеально вписывается в другие контейнеры.
<dependency> <groupId>org.glassfish.jersey.containers.glassfish</groupId> <artifactId>jersey-gf-cdi</artifactId> <version>${jersey.version}</version> </dependency>
убедитесь, что ваш контейнер является правильно настроенный (см. документацию).
поздно, но я надеюсь, что это поможет кому-то.
у меня есть мой 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() {..} }