Skip to content

Latest commit

 

History

History
136 lines (113 loc) · 3.94 KB

스프링 리액티브 프로그래밍(8).md

File metadata and controls

136 lines (113 loc) · 3.94 KB

토비의 봄 TV 스프링 리액티브 프로그래밍 를 보고 정리한 글


WebFlux

RestTemplate -> sync

Async
  1. AsyncRestTemplate
  2. WebClient(WebFlux)
@SpringBootApplication
@RestController
@Slf4j
@EnableAsync
public class WebfluxPrcApplication {
    static final String URL1 = "http://localhost:8081/service?req={req}";
    static final String URL2 = "http://localhost:8081/service2?req={req}";

    @Autowired MyService myService;

    WebClient client = WebClient.create();    // AsyncRestTemplate과 유사

    @GetMapping("/rest")
    public Mono<String> rest(int idx) {
        return Mono.just("Hello");  // 이미 값이 있는걸 리턴하고 싶다 -> just
    }

    public static void main(String[] args) {
        SpringApplication.run(WebfluxPrcApplication.class, args);
    }
}
  • "Hello"가 Mono라는 타입 안에 담겨 리턴됨
  • Mono : 컨테이너라고 생각하면됨
  • List<String>처럼 컨테이너가 제공하는 기능을 사용할 수 있음



@GetMapping("/rest")
public Mono<String> rest(int idx) {
    Mono<ClientResponse> res = client.get().uri(URL1, idx).exchange();  // (1)
    return Mono.just("Hello");  // (2)
}

(1)

  • WebClient -> builder 스타일로 호출
  • URL1에 해당하는 api를 호출하고 응답값을 가져오는 역할
  • ClientResponse -> ResponseEntity 와 비슷

(2)

  • 이렇게 하면 호출 되는가?
  • Pub Sub 개념으로 subscribe 를 해야만 호출
  • res.subscribe()를 해야
  • Mono를 리턴하는 것만으로 호출되지 않음



@GetMapping("/rest")
public Mono<String> rest(int idx){
        Mono<ClientResponse> res=client.get().uri(URL1,idx).exchange();
        Mono<Mono<String>>body=res.map(clientResponse->clientResponse.bodyToMono(String.class)); // (1)
        Mono<String> body2=res.flatMap(clientResponse->clientResponse.bodyToMono(String.class)); // (2)

        return body2;
        // (리액티브 스타일 코드는)선언만 하는 것으로는 동작하지 않는다.
}

(1)

  • clientResponse 라는 타입을 받아서 String으로 리턴하는게 아니라 Mono 로 리턴 : 다시 Mono로 감쌈

(2)

  • (1)에서 이중으로 감싸졌기 때문에 flat 해준다!!
  • body만 꺼내서 Mono 타입으로 리턴해줘야함



/* 간결하게 */ 
@GetMapping("/rest")
public Mono<String> rest(int idx) {
	return client.get().uri(URL1, idx).exchange()
			.flatMap(c -> c.bodyToMono(String.class));
}



/* +2번째 API를 호출 */
@GetMapping("/rest")
public Mono<String> rest(int idx) {
	return client.get().uri(URL1, idx).exchange()   // Mono<ClientResponse>
			.flatMap(cr -> cr.bodyToMono(String.class)) // 위에서 ClientResponse를 받아서 Mono<String> 리턴
			.flatMap((String res1) -> client.get().uri(URL2, res1).exchange())  // 위에 String을 받아서 2번째 api를 호출
			.flatMap(c -> c.bodyToMono(String.class))
			.map(res2 -> myService.work(res2)); // 위 결과로 work를 실행 (1)
}

@Service
public static class MyService {
	public String work(String req) {
		return req + "/asyncwork";
	}
}

(1)

  • map? flatMap?
  • map!
  • 위가 Mono 이기 때문에 map 을 걸어서 String만 꺼내주면됨
  • Mono<String>



/* +2번째 API를 호출 */
@GetMapping("/rest")
public Mono<String> rest(int idx) {
	return client.get().uri(URL1, idx).exchange() 
			.flatMap(cr -> cr.bodyToMono(String.class)) 
			.flatMap((String res1) -> client.get().uri(URL2, res1).exchange()) 
			.flatMap(c -> c.bodyToMono(String.class))
			.flatMap(res2 -> Mono.fromCompletionStage(myService.work(res2))); // 비동기적으로 서비스 메소드 호출 1번
}

@Service
public static class MyService {
	@Async
	public CompletableFuture<String> work(String req) {
		return CompletableFuture.completedFuture(req + "/asyncwork");
	}
}