Как использовать асинхронные обратные вызовы в Jersey 2 в tomcat 7
Как использовать асинхронные обратные вызовы джерси 2 на сервере tomcat.
Я нашел несколько примеров в руководстве Джерси: https://jersey.java.net/documentation/latest/user-guide.html#d0e8496.
Но проблема возникает, когда я пытаюсь проверить следующий код следующим образом: https://jersey.java.net/documentation/latest/user-guide.html#d0e8615 код как упомянутых в Руководстве Джерси 2.
-------------------------------------------- -------------------------------------------------- ---------------------------------
Поскольку ручная версия была изменена, я размещаю коды здесь:
Это моя служба:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.container.CompletionCallback;
import javax.ws.rs.container.Suspended;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@Path("/resource")
public class AsyncResource {
private static int numberOfSuccessResponses = 0;
private static int numberOfFailures = 0;
private static Throwable lastException = null;
@GET
public void asyncGetWithTimeout(@Suspended final AsyncResponse asyncResponse) {
System.out.println("AsyncResource.asyncGetWithTimeout()");
asyncResponse.register(new CompletionCallback() {
@Override
public void onComplete(Throwable throwable) {
if (throwable == null) {
// no throwable - the processing ended successfully
// (response already written to the client)
numberOfSuccessResponses++;
} else {
numberOfFailures++;
lastException = throwable;
}
}
});
new Thread(new Runnable() {
@Override
public void run() {
String result = veryExpensiveOperation();
asyncResponse.resume(result);
}
private String veryExpensiveOperation() {
// ... very expensive operation
return "Hi";
}
}).start();
}
}
Это клиент:
ClientConfig clientConfig = new ClientConfig();
Client client = ClientBuilder.newClient(clientConfig);
WebTarget webTarget = client.target("http://localhost:8080/Jersey2.5Service/rest");
WebTarget target = webTarget.path("resource");
final AsyncInvoker asyncInvoker = target
.request().async();
final Future<Response> responseFuture = asyncInvoker.get();
System.out.println("Request is being processed asynchronously.");
final Response response = responseFuture.get();
// get() waits for the response to be ready
System.out.println("Response received." +response.readEntity(String.class));
web.xml
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>
org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>main.java</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Это банки, которые я использую:
asm-all-repackaged-2.2.0-b21.jar
cglib-2.2.0-b21.jar
guava-14.0.1.jar
hk2-api-2.2.0-b21.jar
hk2-locator-2.2.0-b21.jar
hk2-utils-2.2.0-b21.jar
javax.annotation-api-1.2.jar
javax.inject-2.2.0-b21.jar
javax.servlet-api-3.0.1.jar
javax.ws.rs-api-2.0.jar
jaxb-api-2.2.7.jar
jersey-client.jar
jersey-common.jar
jersey-container-servlet-core.jar
jersey-container-servlet.jar
jersey-server.jar
org.osgi.core-4.2.0.jar
osgi-resource-locator-1.0.1.jar
persistence-api-1.0.jar
servlet-api-3.0.jar
validation-api-1.1.0.Final.jar
Эти ошибки:
Jan 31, 2014 4:06:53 PM org.glassfish.jersey.servlet.internal.ResponseWriter suspend
WARNING: Attempt to put servlet request into asynchronous mode has failed. Please check your servlet configuration - all Servlet instances and Servlet filters involved in the request processing must explicitly declare support for asynchronous request processing.
java.lang.IllegalStateException: Not supported.
at org.apache.catalina.connector.Request.startAsync(Request.java:1676)
at org.apache.catalina.connector.RequestFacade.startAsync(RequestFacade.java:1031)
at org.glassfish.jersey.servlet.async.AsyncContextDelegateProviderImpl$ExtensionImpl.suspend(AsyncContextDelegateProviderImpl.java:87)
at org.glassfish.jersey.servlet.internal.ResponseWriter.suspend(ResponseWriter.java:120)
at org.glassfish.jersey.server.ServerRuntime$AsyncResponder.suspend(ServerRuntime.java:758)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:330)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:106)
at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:259)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:318)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:236)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1010)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:373)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:382)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:345)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:220)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Jan 31, 2014 4:06:53 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [HelloServlet] in context with path [/Jersey2.5Service] threw exception [javax.ws.rs.ProcessingException: Attempt to suspend a connection of an asynchronous request failed in the underlying container.] with root cause
javax.ws.rs.ProcessingException: Attempt to suspend a connection of an asynchronous request failed in the underlying container.
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:331)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:106)
at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:259)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:318)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:236)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1010)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:373)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:382)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:345)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:220)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Ответы
Ответ 1
Для меня решение заключалось в том, чтобы добавить поддержку Async в Servlet Filter. Сообщение об ошибке дало мне подсказку:
Попытка отправить запрос сервлета в асинхронный режим завершилась неудачно. Пожалуйста, проверьте конфигурацию сервлета - все экземпляры сервлета и задействованные фильтры сервлетов в обработке запроса должны явно объявить поддержку для обработки асинхронных запросов
Я использую Spring для инъекций зависимостей и использую сервлет по умолчанию Джерси. Для Spring я использую прокси-сервер делегирующего фильтра. Мне нужно было объявить, что поддержка фильтра asycn истинна.
Итак, для сервлета:
<servlet>
<servlet-name>myserlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
И добавьте поддержку async true для фильтра Spring.
<filter>
<description>Spring filter</description>
<display-name>spring-filter</display-name>
<filter-name>springFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
</filter>
Надеюсь, это поможет вам и другим.
Ответ 2
Я знаю, что этот вопрос очень старый, но для людей, которые сталкиваются с этой проблемой. Обновите Tomcat Server до последней версии 8. **. Tomcat, начиная с версии 8, поддерживает Async Processing.
Ответ 3
Для обратного вызова Async вы можете использовать Guava lib. Например:
@GET
@Produces(MediaType.APPLICATION_JSON)
@ManagedAsync
public void getBooks(@Suspended final AsyncResponse response){
ListenableFuture<Collection<Book>> bookFuture = dao.getBooksAsync();
Futures.addCallback(bookFuture, new FutureCallback<Collection<Book>>() {
public void onSuccess(Collection<Book> books){
response.resume(books);
}
public void onFailure(Throwable thrown){
response.resume(thrown);
}
});
}
И в моей книге DAO у меня есть:
BookDao(){
books = new HashMap<String,Book>();
Book b1 = new Book();
service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
}
Collection<Book> getBooks(){
return(books.values());
}
ListenableFuture<Collection<Book>> getBooksAsync(){
ListenableFuture<Collection<Book>> future =
service.submit(new Callable<Collection<Book>>() {
public Collection<Book> call() throws Exception{
return getBooks();
}
});
return(future);
}