Джерси Hk2 впрыскивает аннотированные классы @Service
На всю жизнь я не могу заставить Джерси с hk2 автоматически обнаруживать аннотированные классы @Service и вводить их. Я пытался следовать всем советам по переполнению стека, документации по джерси и hk2 и все еще не повезло. Я пытаюсь внедрить простой эхо-сервис в ресурс Джерси. Скелет создан из простого веб-приложения maven для Джерси, которое я попытался расширить. Это то, что я до сих пор:
pom.xml
<build>
<finalName>sandbox</finalName>
<plugins>
<plugin>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2-inhabitant-generator</artifactId>
<version>2.3.0</version>
<executions>
<execution>
<configuration>
<verbose>true</verbose>
</configuration>
<goals>
<goal>generate-inhabitants</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
<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.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2</artifactId>
<version>2.3.0</version>
</dependency>
</dependencies>
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.packages</param-name>
<param-value>my.package.jerseytest</param-value>
</init-param>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>my.package.jerseytest.application.Application</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
my.package.jerseytest.application.Application
public class Application extends ResourceConfig {
public Application() {
ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
}
}
my.package.jerseytest.service.EchoService
@Service
public class EchoService {
public String generateResponse(String echo) {
return echo;
}
}
my.package.jerseytest.resource.MyResource
@Path("myresource")
public class MyResource {
@Inject
EchoService echoService;
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getIt() {
return echoService.generateResponse("Got it!");
}
}
Я проверил, что генератор ингибиторов действительно работает и выдает свои результаты, но при запуске сервера Tomcat GETting http://localhost:8080/sandbox/webapi/myresource
я получил
SEVERE: Servlet.service() for servlet [Jersey Web Application] in context with path [/sandbox] threw exception [A MultiException has 3 exceptions. They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=EchoService,parent=MyResource,qualifiers={},position=-1,optional=false,self=false,unqualified=null,932014249)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of my.package.jerseytest.resource.MyResource errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on my.package.jerseytest.resource.MyResource
] with root cause
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=EchoService,parent=MyResource,qualifiers={},position=-1,optional=false,self=false,unqualified=null,932014249)
Есть идеи, что мне не хватает? Буду признателен за любую помощь:(
NB! Я знаю о
- Как ServiceLocator автоматически находит @Service и @Contact в HK2?
- Аннотации HK2 не обрабатываются
- https://hk2.java.net/inhabitant-generator.html
- https://hk2.java.net/2.2.0-b25/getting-started.html
- https://java.net/jira/browse/HK2-165
но они не помогли мне...
5 ответов
Я объединяю понимание, которое я получил от этих двух вопросов:
- Как ServiceLocator автоматически находит @Service и @Contact в HK2?
- Джерси + Гризли + HK2: внедрение зависимости, но не в ресурс
Во-первых, используйте генератор метаданных HK2 (или Inhabitant Generator) в своей цепочке сборки (как вы уже сделали). Это отсканирует ваш источник и создаст META-INF/hk2-locator/default
,
Во-вторых, создать новый ServiceLocator
, заполненный сервисами из метаданных:
ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
Теперь передайте это Grizzly
, Цитирование Paul Samsotha:
На Джерси есть собственный ServiceLocator, и получить ссылку на него нелегко. Мы могли бы дать Джерси наш ServiceLocator, но в конечном итоге Джерси все еще создает свой собственный локатор и заполнит его нашим локатором.
ResourceConfig config = new MyApplicationConfig();
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(
URI.create(BASE_URI),
config,
serviceLocator
);
Я решил свою проблему почти так же, как этот, используя класс, который расширяет AbstractBinder, создавая его и регистрируя в приложении.
resourceConfig.register(new DependencyBinder());
Также,
/**
* dependency injection bindings.
* Jersey requires that service implementations are bound to their contracts this way.
*/
public final class DependencyBinder extends AbstractBinder {
@Override
protected final void configure() {
bind(StatusServiceImpl.class).to(StatusService.class);
}
}
Попробуйте добавить @Stateless
@Path("myresource")
@Stateless
public class MyResource {
@Inject
EchoService echoService;
...
}
Использование packages(true, "my.package.jerseytest");
И использовать org.glassfish.jersey.spi.Contract
не org.jvnet.hk2.annotations.Contract
аннотаций. И используйте простые интерфейсы без обобщений.
Попробуйте добавить пакеты, которые необходимо отсканировать, в конструкторе приложений. Параметр "true" для пакетов означает рекурсивное сканирование пакета:
public class Application extends ResourceConfig {
public Application() {
packages(true, "my.package.jerseytest");
ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
}
}