저는 Java를 처음 접하기 때문에 일부 사람들에게는 이것이 분명해 보일 수 있습니다. 저는 이벤트 기반의 액션 스크립트로 많은 작업을 해왔고 그것을 좋아합니다. 최근에 POST 요청을 수행하는 약간의 Java 코드를 작성하려고 시도했지만 동기 요청이라는 문제에 직면하여 코드 실행이 요청이 완료되거나 시간이 초과되거나 오류가 표시 될 때까지 대기합니다.
코드가 실행을 계속하고 HTTP 요청이 완료되면 콜백이 호출되는 비동기 요청을 생성하려면 어떻게해야합니까? 스레드를 훑어 봤지만 과잉이라고 생각합니다.
답변
java11은 이제 java의 CompletableFuture를 사용하여 완전히 비동기식 작업을 지원 하는 새로운 HTTP api HttpClient 를 제공합니다 .
또한 동기식 인 send 및 비동기식 sendAsync 와 같은 호출을 사용하여 동기식 버전을 지원합니다 .
비동기 요청의 예 (apidoc에서 가져옴) :
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/"))
.timeout(Duration.ofMinutes(2))
.header("Content-Type", "application/json")
.POST(BodyPublishers.ofFile(Paths.get("file.json")))
.build();
client.sendAsync(request, BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
답변
JEE7 환경에있는 경우 클라이언트 API를 사용하여 쉽게 비동기 HTTP 요청을 만들 수있는 적절한 JAXRS 구현이 있어야합니다.
이것은 다음과 같습니다.
public class Main {
public static Future<Response> getAsyncHttp(final String url) {
return ClientBuilder.newClient().target(url).request().async().get();
}
public static void main(String ...args) throws InterruptedException, ExecutionException {
Future<Response> 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를 살펴볼 수 있습니다. Hystrix는 엄청나게 멋진 다른 것 외에도 다음과 같이 작성할 수 있습니다.
예를 들면 :
public class AsyncGetCommand extends HystrixCommand<String> {
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");
}
추신 : 스레드가 오래되었다는 것을 알고 있지만 아무도 찬성 응답에서 Rx / Hystrix 방식을 언급하지 않는다는 것이 잘못되었다고 느꼈습니다.
답변
Async Http Client 를 살펴볼 수도 있습니다 .
답변
이 SO 스레드의 Apache HTTP 구성 요소 에 대한 링크를 기반으로 HTTP 구성 요소 에 대한 Fluent 파사드 API를 발견했습니다. 여기에있는 예 는 비동기 HTTP 요청의 대기열을 설정하는 방법을 보여줍니다 (그리고 완료 / 실패 / 취소에 대한 알림 받기). 제 경우에는 대기열이 필요하지 않고 한 번에 하나의 비동기 요청 만 필요했습니다.
여기에 내가 끝낸 곳이 있습니다 (또한 HTTP 구성 요소의 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);
Future<Content> future = async.execute(request, new FutureCallback<Content>() {
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 프로젝트는 유지 보수 가능한 고성능 및 높은 확장 성 프로토콜 서버 및 클라이언트의 신속한 개발을위한 비동기 이벤트 중심 네트워크 애플리케이션 프레임 워크 및 도구를 제공하기위한 노력입니다.
답변
Apache HttpComponents 에는 이제 비동기 http 클라이언트도 있습니다.
/**
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.0-beta4</version>
</dependency>
**/
import java.io.IOException;
import java.nio.CharBuffer;
import java.util.concurrent.Future;
import org.apache.http.HttpResponse;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.nio.IOControl;
import org.apache.http.nio.client.methods.AsyncCharConsumer;
import org.apache.http.nio.client.methods.HttpAsyncMethods;
import org.apache.http.protocol.HttpContext;
public class HttpTest {
public static void main(final String[] args) throws Exception {
final CloseableHttpAsyncClient httpclient = HttpAsyncClients
.createDefault();
httpclient.start();
try {
final Future<Boolean> future = httpclient.execute(
HttpAsyncMethods.createGet("http://www.google.com/"),
new MyResponseConsumer(), null);
final Boolean result = future.get();
if (result != null && result.booleanValue()) {
System.out.println("Request successfully executed");
} else {
System.out.println("Request failed");
}
System.out.println("Shutting down");
} finally {
httpclient.close();
}
System.out.println("Done");
}
static class MyResponseConsumer extends AsyncCharConsumer<Boolean> {
@Override
protected void onResponseReceived(final HttpResponse response) {
}
@Override
protected void onCharReceived(final CharBuffer buf, final IOControl ioctrl)
throws IOException {
while (buf.hasRemaining()) {
System.out.print(buf.get());
}
}
@Override
protected void releaseResources() {
}
@Override
protected Boolean buildResult(final HttpContext context) {
return Boolean.TRUE;
}
}
}
답변
HTTP 프로토콜이 동 기적이며 프로그래밍 언어와 관련이 없음을 분명히해야합니다. 클라이언트가 요청을 보내고 동기 응답을받습니다.
당신은 HTTP를 통해 비동기 행동을하려는 경우,이 구축되어야 이상 (나는 액션에 대해 아무것도 몰라하지만 난이 ActionScript를 너무 무엇이라고 생각) HTTP를. 이러한 기능을 제공 할 수있는 많은 라이브러리가 있습니다 (예 : Jersey SSE ). HTTP 위의 정확한 비표준 통신 방법에 동의해야하기 때문에 클라이언트와 서버 간의 종속성을 어떻게 든 정의합니다.
당신은 클라이언트와 서버를 모두 제어 할 수 또는 당신이 그들 사이의 종속성을 갖고 싶어하지 않을 경우, 사용하고 HTTP를 통해 비동기 (예 : 이벤트 기반) 통신을 구현하는 가장 일반적인 방법 경우 webhooks이 접근은 (확인할 수 있습니다 이 에 대한 자바에서 구현 예).
내가 도왔 으면 좋겠어!