我对Java很新,所以对某些人来说这似乎是显而易见的.我在ActionScript上做了很多工作,这是基于事件的,我很喜欢.我最近尝试编写了一小部分执行POST请求的Java代码,但我遇到了一个问题,即它是一个同步请求,因此代码执行会等待请求完成,超时或出现错误.
如何创建异步请求,代码继续执行,并在HTTP请求完成时调用回调?我瞥了一眼线程,但我认为这太过分了.
Java确实比ActionScript更低级别.这就像比较苹果和橘子.虽然ActionScript在"引擎盖下"透明地处理它,但在Java中,您需要自己管理异步处理(线程).
幸运的是,在Java中,有一种java.util.concurrent
API可以很好地完成这项工作.
你的问题基本上可以解决如下:
// Have one (or more) threads ready to do the async tasks. Do this during startup of your app. ExecutorService executor = Executors.newFixedThreadPool(1); // Fire a request. Futureresponse = executor.submit(new Request(new URL("http://google.com"))); // Do your other tasks here (will be processed immediately, current thread won't block). // ... // Get the response (here the current thread will block until response is returned). InputStream body = response.get().getBody(); // ... // Shutdown the threads during shutdown of your app. executor.shutdown();
其中Request
和Response
如下所示:
public class Request implements Callable{ private URL url; public Request(URL url) { this.url = url; } @Override public Response call() throws Exception { return new Response(url.openStream()); } }
和
public class Response { private InputStream body; public Response(InputStream body) { this.body = body; } public InputStream getBody() { return body; } }
课程:并发 - 一个java.util.concurrent
教程.
如果您处于JEE7环境中,那么您必须有一个不错的JAXRS实现,这将允许您使用其客户端API轻松地发出异步HTTP请求.
这看起来像这样:
public class Main { public static FuturegetAsyncHttp(final String url) { return ClientBuilder.newClient().target(url).request().async().get(); } public static void main(String ...args) throws InterruptedException, ExecutionException { Future response = getAsyncHttp("http://www.nofrag.com"); while (!response.isDone()) { System.out.println("Still waiting..."); Thread.sleep(10); } System.out.println(response.get().readEntity(String.class)); } }
当然,这只是使用期货.如果你可以使用更多的库,你可以看看RxJava,代码看起来像:
public static void main(String... args) { final String url = "http://www.nofrag.com"; rx.Observable.from(ClientBuilder.newClient().target(url).request().async().get(String.class), Schedulers .newThread()) .subscribe( next -> System.out.println(next), error -> System.err.println(error), () -> System.out.println("Stream ended.") ); System.out.println("Async proof"); }
最后但并非最不重要的是,如果你想重用你的异步调用,你可能想看看Hystrix,除了一个非常酷的其他东西之外,它还允许你写这样的东西:
例如:
public class AsyncGetCommand extends HystrixCommand{ private final String url; public AsyncGetCommand(final String url) { super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("HTTP")) .andCommandPropertiesDefaults(HystrixCommandProperties.Setter() .withExecutionIsolationThreadTimeoutInMilliseconds(5000))); this.url = url; } @Override protected String run() throws Exception { return ClientBuilder.newClient().target(url).request().get(String.class); } }
调用此命令将如下所示:
public static void main(String ...args) { new AsyncGetCommand("http://www.nofrag.com").observe().subscribe( next -> System.out.println(next), error -> System.err.println(error), () -> System.out.println("Stream ended.") ); System.out.println("Async proof"); }
PS:我知道线程已经过时了,但是在没有提到Rx/Hystrix方式的情况下,没有人提到这个问题.
您可能还想查看Async Http Client.
基于此SO线程上的Apache HTTP组件链接,我遇到了HTTP组件的Fluent外观API. 这里的一个例子展示了如何设置异步HTTP请求的队列(并获得完成/失败/取消的通知).就我而言,我不需要一个队列,一次只需要一个异步请求.
这是我结束的地方(也使用HTTP Components中的URIBuilder,例如这里).
import java.net.URI; import java.net.URISyntaxException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.apache.http.client.fluent.Async; import org.apache.http.client.fluent.Content; import org.apache.http.client.fluent.Request; import org.apache.http.client.utils.URIBuilder; import org.apache.http.concurrent.FutureCallback; //... URIBuilder builder = new URIBuilder(); builder.setScheme("http").setHost("myhost.com").setPath("/folder") .setParameter("query0", "val0") .setParameter("query1", "val1") ...; URI requestURL = null; try { requestURL = builder.build(); } catch (URISyntaxException use) {} ExecutorService threadpool = Executors.newFixedThreadPool(2); Async async = Async.newInstance().use(threadpool); final Request request = Request.Get(requestURL); Futurefuture = async.execute(request, new FutureCallback () { public void failed (final Exception e) { System.out.println(e.getMessage() +": "+ request); } public void completed (final Content content) { System.out.println("Request completed: "+ request); System.out.println("Response:\n"+ content.asString()); } public void cancelled () {} });
您可能想看一下这个问题:Java中的异步IO?
看起来你最好的选择,如果你不想自己争论线程是一个框架.上一篇文章提到了Grizzly,https://grizzly.dev.java.net/和Netty,http: //www.jboss.org/netty/ .
来自netty文档:
Netty项目旨在提供异步事件驱动的网络应用程序框架和工具,以便快速开发可维护的高性能和高可伸缩性协议服务器和客户端.