웹 어플리케이션에서 다른 서비스에게 HTTP로 호출하는 용도.
스프링5 이전까지는 클라이언트에서 HTTP 접근을 위해 RestTemplate을 사용했다.
RestTemplate
SpringMVC 프로젝트의 일부로, HTTP 서버와의 통신을 가능하게 하고, RESTful 규칙을 이용함
SpringBoot 에서는 HTTP 동작을 수행하기 위한 다른 대안으로 Apache HttpClient가 있다.
이런 대안들은 모두 Java Servlet 기반으로, 블로킹 방식이다.
동기
WebClient
스프링5부터는 reactive WebClient를 사용할 수 있다.
논블로킹 이 가능하다.
비동기도 가능하다.
팩토리 메소드 패턴
학습배경
웹툰 동의 정보 가져오는 부분이다. 구현은 service-api 참고해서 했으나 코드 이해를 잘 못했기 때문에 간단하게라도 알아보자.
쓰인 건 armeria의 clientFactory, webClient 등이다.
val headers = RequestHeaders.of(
HttpMethod.GET, location,
HttpHeaderNames.CONTENT_TYPE, "application/json"
)
val response = Mono.fromFuture(webClient()
.execute(headers)
.aggregate())
.awaitSingle()
private fun webClient(responseTimeoutSeconds: Long = 1): WebClient {
return WebClient.builder()
.options(
ClientOptions.builder()
.responseTimeout(Duration.ofSeconds(responseTimeoutSeconds))
.factory(clientFactory)
.build()
)
.build()
}
- clientFactory에 주목!
### 팩토리 메소드 패턴?
- 객체를 만드는 부분을 서브 클래스에 위임하는 패턴
- 즉 new 키워드로 호출하는 부분을 서브 클래스에 위임함. 결국 '객체를 만들어 내는 공장'을 만든느 패턴임.
public class SwordFactory {
public static Sword getWeapon (type) {
if (type.equals("좋은검") {
return new 좋은검();
} else if (type.equals("안좋은검") {
return new 안좋은검();
} else {
return null;
}
}
}
SwordFactory factory = new SwordFactory();
Sword goodSword = factory.getWeapon("좋은검");
- 위처럼 new는 팩토리 클래스 안에서만 사용되고, 생성된 인스턴스는 static 메소드를 통해 호출한다.
### ClientFactory
> 이것도 팩토리임. 그래서 역할은 creates and manages clients!
### WebClient 만듦
private fun webClient(responseTimeoutSeconds: Long = 1): WebClient {
return WebClient.builder()
.options(
ClientOptions.builder()
.responseTimeout(Duration.ofSeconds(responseTimeoutSeconds))
.factory(clientFactory)
.build()
)
.build()
}
- options를 통해 clientOptions 를 만들고 그 안에서 팩토리로 client 만들고 응답 시간 조절해서 어떤 webClient를 만듦.
val response = Mono.fromFuture(webClient()
.execute(headers)
.aggregate())
.awaitSingle()
- 이 webClient를 통해, http 메소드 정보와 uri 정보와 헤더 정보를 담은 headers를 execute함.
- RequestHeaders of(HttpMethod method, String path, CharSequenceName, String value)
- execute : 빈 http request를 헤더와 함께 보냄.
# Mono? Future?
### 리액티브 프로그래밍
- 비동기 블로킹 프로세스로 동작하는 애플리케이션을 논블로킹 프로세스로 동작하도록 지원하는 프로그래밍.
### 기존 스프링 블로킹 방식
- 서버가 요청에 대한 응답을 보내는데 이게 오래 걸리면 오랜 시간동안 블로킹된다.
- 그래서 동시에 요청을 처리하도록 멀티 스레드를 지원한다.
- 근데 이러면 하나의 작업이 스레드에서 진행되고 다른 스레드가 다른 요청을 받아서 처리하게 되고,
- 결국 스레드가 계속 늘어나면서 이걸 할당하기 위한 리소스도 늘어나게 되어 매우 비효율적이다.
### 스프링5의 논블로킹 방식
- Spring5부터 클라이언트의 요청에 대해 별도 스레드를 생성하지 않고 buffer를 사용해서 요청을 받는다.
- 왜 블로킹 -> 논블로킹이 된걸까?
- 수천개의 스트림 데이터가 계속 업데이트되는 시스템이고 적절히 응답해줘야 할 때, 블로킹이라면 상당한 부담이 된다. 계속 멈추니까.
### Mono, Flux
- Mono : 0-1개의 결과만을 처리하기 위한 reactor 객체
- Flux : 0-N개의 결과를 처리하기 위한 reactor 객체
보통 여러 스트림을 하나의 결과로 모아줄 때 Mono 사용, '여러 값들을 하나로 만든' 각각의 Mono들을 합쳐서 여러 값을 처리할 때 Flux를 사용한다.
알아볼 내용
RestTemplate과 WebClient
웹 어플리케이션에서 다른 서비스에게 HTTP로 호출하는 용도. 스프링5 이전까지는 클라이언트에서 HTTP 접근을 위해 RestTemplate을 사용했다.
RestTemplate
WebClient
비동기도 가능하다.
팩토리 메소드 패턴
학습배경
웹툰 동의 정보 가져오는 부분이다. 구현은 service-api 참고해서 했으나 코드 이해를 잘 못했기 때문에 간단하게라도 알아보자. 쓰인 건 armeria의 clientFactory, webClient 등이다.
private fun webClient(responseTimeoutSeconds: Long = 1): WebClient { return WebClient.builder() .options( ClientOptions.builder() .responseTimeout(Duration.ofSeconds(responseTimeoutSeconds)) .factory(clientFactory) .build() ) .build() }
public class SwordFactory { public static Sword getWeapon (type) { if (type.equals("좋은검") { return new 좋은검(); } else if (type.equals("안좋은검") { return new 안좋은검(); } else { return null; } } } SwordFactory factory = new SwordFactory(); Sword goodSword = factory.getWeapon("좋은검");
private fun webClient(responseTimeoutSeconds: Long = 1): WebClient { return WebClient.builder() .options( ClientOptions.builder() .responseTimeout(Duration.ofSeconds(responseTimeoutSeconds)) .factory(clientFactory) .build() ) .build() }
val response = Mono.fromFuture(webClient() .execute(headers) .aggregate()) .awaitSingle()