我正在使用JAX-RS为资源实现CRUD操作。在我的第一个用例期间,它是一个阻塞(同步)请求,即在单线程执行中客户端获得响应。
使用案例1:
@Path("/resourceService")
public class CRUDService {
@GET
@Path("/{param}")
public Response getResource(@PathParam("param") String id) {
Resource res = SomeBean().getResource(id);
return Response.status(200).entity(res).build();
}
}
用例2:
现在我必须实现相同的请求,但它是一个非阻塞(异步)请求,这样一旦请求到达服务器,我就必须将响应返回给服务器 ACKNOWLEDGMENT 即具有Response
状态代码的ACCEPTED (202)
对象,然后恢复初始请求处理(在这种情况下通过id获取资源)。
此请求的响应(检索到的资源)通过发送新的POST
请求发送到客户端,该请求的内容是检索到的资源,然后客户端将返回此POST
请求的响应成功状态代码。
(注意:这里客户端不是bean浏览器,客户端和服务器都是调用REST Api的机器)。
@Path("/resourceService")
public class CRUDService {
@GET
@Path("/{param}")
public Response getResource(@PathParam("param") String id) {
// ACKNOWLEDGEMENT response built and sent back to clinet
return Response.status(202).build();
// Do the request handling i.e resource retrieval
Resource res = SomeBean().getResource(id);
Resonse response = Response.status(200).entity(res).build();
// Create a HTTP POST Request and set the body as response object
HttpClient client = HttpClientBuilder.create().build();
HttpPost post = new HttpPost(url);
post.setEntity(response);
HttpResponse response = client.execute(post);
}
}
我了解了Asynchronous JAX-RS
和java.util.concurrent
包。
如果我以异步方式执行此操作,例如启动新线程来执行请求处理,那么如何发送第一次 ACK的响应。例如:
@POST
@Consumes("application/json")
@Produces("application/json")
public void getResource(@PathParam("param") String id,
final @Suspended AsyncResponse response) {
new Thread() {
public void run() {
Resource res = SomeBean().getResource(id);
response.resume(resource);
}
}.start();
}
}
如何使用JAX-RS实现此调用流程?
修改 我在你的回答中提到过,但是我得到了一个例外:
服务器日志:
2016 - 07 - 25 12: 22: 01, 521 ERROR[io.undertow.request](
default task - 1) UT005023: Exception handling request to / resourceService: org.jboss.resteasy.spi.UnhandledException: java.lang.NoSuchMethodError: my.ow.dummy.package.CRUDService$1. < init > (Lmy / own / dummy / package / CRUDService;) V
at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java: 76)[resteasy - jaxrs - 3.0 .6.Final.jar: ]
at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java: 212)[resteasy - jaxrs - 3.0 .6.Final.jar: ]
at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java: 149)[resteasy - jaxrs - 3.0 .6.Final.jar: ]
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java: 372)[resteasy - jaxrs - 3.0 .6.Final.jar: ]
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java: 179)[resteasy - jaxrs - 3.0 .6.Final.jar: ]
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java: 220)[resteasy - jaxrs - 3.0 .6.Final.jar: ]
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java: 56)[resteasy - jaxrs - 3.0 .6.Final.jar: ]
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java: 51)[resteasy - jaxrs - 3.0 .6.Final.jar: ]
at javax.servlet.http.HttpServlet.service(HttpServlet.java: 790)[jboss - servlet - api_3 .1 _spec - 1.0 .0.Final.jar: 1.0 .0.Final]
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java: 85)[undertow - servlet - 1.0 .0.Final.jar: 1.0 .0.Final]
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java: 61)[undertow - servlet - 1.0 .0.Final.jar: 1.0 .0.Final]
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java: 36)[undertow - servlet - 1.0 .0.Final.jar: 1.0 .0.Final]
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java: 78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java: 25)[undertow - core - 1.0 .0.Final.jar: 1.0 .0.Final]
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java: 113)[undertow - servlet - 1.0 .0.Final.jar: 1.0 .0.Final]
at io.undertow.security.handlers.AuthenticationCallHandler.handleRequest(AuthenticationCallHandler.java: 52)[undertow - core - 1.0 .0.Final.jar: 1.0 .0.Final]
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java: 45)[undertow - core - 1.0 .0.Final.jar: 1.0 .0.Final]
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java: 61)[undertow - servlet - 1.0 .0.Final.jar: 1.0 .0.Final]
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java: 70)[undertow - servlet - 1.0 .0.Final.jar: 1.0 .0.Final]
at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java: 76)[undertow - core - 1.0 .0.Final.jar: 1.0 .0.Final]
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java: 25)[undertow - core - 1.0 .0.Final.jar: 1.0 .0.Final]
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java: 61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java: 25)[undertow - core - 1.0 .0.Final.jar: 1.0 .0.Final]
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java: 25)[undertow - core - 1.0 .0.Final.jar: 1.0 .0.Final]
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java: 240)[undertow - servlet - 1.0 .0.Final.jar: 1.0 .0.Final]
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java: 227)[undertow - servlet - 1.0 .0.Final.jar: 1.0 .0.Final]
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java: 73)[undertow - servlet - 1.0 .0.Final.jar: 1.0 .0.Final]
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java: 146)[undertow - servlet - 1.0 .0.Final.jar: 1.0 .0.Final]
at io.undertow.server.Connectors.executeRootHandler(Connectors.java: 168)[undertow - core - 1.0 .0.Final.jar: 1.0 .0.Final]
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java: 687)[undertow - core - 1.0 .0.Final.jar: 1.0 .0.Final]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java: 1145)[rt.jar: 1.7 .0 _40]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java: 615)[rt.jar: 1.7 .0 _40]
at java.lang.Thread.run(Thread.java: 724)[rt.jar: 1.7 .0 _40]
Caused by: java.lang.NoSuchMethodError: my.ow.dummy.package.CRUDService$1. < init > (Lmy / own / dummy / package / CRUDService;) V at my.ow.dummy.package.CRUDService.handlePutRequest(CRUDService.java: 78)[classes: ]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)[rt.jar: 1.7 .0 _40]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java: 57)[rt.jar: 1.7 .0 _40]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java: 43)[rt.jar: 1.7 .0 _40]
at java.lang.reflect.Method.invoke(Method.java: 606)[rt.jar: 1.7 .0 _40]
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java: 137)[resteasy - jaxrs - 3.0 .6.Final.jar: ]
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java: 280)[resteasy - jaxrs - 3.0 .6.Final.jar: ]
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java: 234)[resteasy - jaxrs - 3.0 .6.Final.jar: ]
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java: 221)[resteasy - jaxrs - 3.0 .6.Final.jar: ]
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java: 356)[resteasy - jaxrs - 3.0 .6.Final.jar: ]
...29 more
此异常未提前,它是在我添加新的Thread()部分后开始的。有什么想法吗?
答案 0 :(得分:1)
如果您想将ACK返回给客户端,然后想要进一步处理您的请求,则以下代码段应该可以正常工作。
public static void main(String args[]) {
Runnable thread = () -> {
// you code goes here
// which you want to execute in a new thread
};
// return response code / ACK
}
这里,新创建的线程将开始执行,main函数将继续执行而不等待线程完成执行。
您可以在JAX-RS实现中使用类似的实现。
答案 1 :(得分:1)
在客户端和服务器实际上都是服务器的情况下,您可以使用一些参数创建一个资源方法,该参数将使uri发送Resource
,例如通过@HeaderParam,如果初始请求需要是GET
:
@GET
@Path("/{param}")
public Response getResource(@PathParam("param") String id, @HeaderParam(
"SendBackUri") String uri) {
new Thread() {
public void run() {
Resource res = SomeBean().getResource(id);
ClientBuilder.newClient().target(uri).request().buildPost(Entity.entity(res, MediaType.WILDCARD_TYPE)).invoke();
}
}.start();
return Response.status(202).build();
}
编辑:您可以使用ExecutorService:
@GET
@Path("/{param}")
public Response getResource(@PathParam("param") String id, @HeaderParam(
"SendBackUri") String uri) {
executorService.execute(new Runnable() {
public void run() {
Resource res = SomeBean().getResource(id);
Response response = ClientBuilder.newClient().target(uri).request().buildPost(Entity.entity(res, MediaType.WILDCARD_TYPE)).invoke();
//deal with response
}
});
return Response.status(202).build();
}
run
或Runnable
的{{1}}方法中的任何内容都在单独的线程中执行。当然,在这个线程中,您可以处理来自POST请求的Thread
,如果需要,您可以根据返回的状态代码以某种方式做出反应。
您可以使用两台服务器相互通信,但这种情况并不常见。如果客户端只是客户端,则可以执行异步客户端请求,例如:
Response
对于服务器端,您可以使用异步方法
Future<Response> f = ClientBuilder.newClient().target(uri).request().async().get();
//do some client specific stuff which you probably do when receive 202;
Response r = f.get(); //wait for response
//do whatever you would do with the resource
就像你拥有它一样。