본문 바로가기
토비의봄

6. 비동기 RestTemplate, 비동기 MVC/Servlet

by 이석준석이 2021. 3. 6.

Callable

  • 리턴값이 있음
  • 예외를 던질 수 있음

 

Runnable

  • 리턴값이 없음
  • 예외를 던질 수 없음

1. RestTemplate

 

가정

  • localhost:8081 쪽의 작업은 오래걸린다.
  • 나에게 많은 요청이 온다.

아래의 코드는 block 방식이므로 

  • 작업시간 * 요청수 만큼의 시간이 걸림
@RestController
public static class MyController {
    RestTemplate rt = new RestTemplate();

    @GetMapping("/rest")
    public String rest(int idx) {
        String res = rt.getForObject("http://localhost:8081/service?req={req}", String.class, "hello " + idx);
        return "rest " + idx;
    }
}

2. AsyncRestTemplate

 

위의 시간이 많이걸리는 점을 AsyncRestTemplate 으로 해결

  • ListenableFuture 로 리턴하면 스프링은 알아서
    • 서블릿 쓰레드를 반환
    • 결과값에 대한 콜백에 대한 처리를 MVC 가 처리
@RestController
public static class MyController {
    AsyncRestTemplate rt = new AsyncRestTemplate();

    @GetMapping("/rest")
    public ListenableFuture<ResponseEntity<String>> rest(int idx) {
        // 스프링은
        // 비동기적으로 처리하니까 2초동안 대기하지 않음
        // 결과값 처리에 대한 콜백은 스프링 MVC 가 알아서 해줌
        return rt.getForEntity("http://localhost:8081/service?req={req}", String.class, "hello " + idx);
    }
}

추가작업

  • 추가적인 작업에 대해서는
    • ListenableFuture 에 콜백을 추가
    • 결과값을 DeferredResult 로 반환하며, 콜백 내에서 DeferredResult 의 결과값을 세팅하는 방식으로 추가 작업 진행
@RestController
public static class MyController {
    AsyncRestTemplate rt = new AsyncRestTemplate(new Netty4ClientHttpRequestFactory(new NioEventLoopGroup(1)));

    @GetMapping("/rest")
    public DeferredResult<String> rest(int idx) {
        DeferredResult<String> dr = new DeferredResult<>();
        // 스프링은
        // 비동기적으로 처리하니까 2초동안 대기하지 않음
        // 결과값 처리에 대한 콜백은 스프링 MVC 가 알아서 해줌
        ListenableFuture<ResponseEntity<String>> f1 = rt.getForEntity("http://localhost:8081/service?req={req}", String.class, "hello " + idx);
        f1.addCallback(
        s -> {
            dr.setResult(s.getBody() + "/work");
        },
        e -> {
            dr.setErrorResult(e.getMessage());
        });

        return dr;
    }
}

중첩작업

  • ListenableFuture 중첩하여 작업
@RestController
public static class MyController {
    @Autowired
    MyService myService;

    AsyncRestTemplate rt = new AsyncRestTemplate(new Netty4ClientHttpRequestFactory(new NioEventLoopGroup(1)));

    @GetMapping("/rest")
    public DeferredResult<String> rest(int idx) {
        DeferredResult<String> dr = new DeferredResult<>();
        // 스프링은
        // 비동기적으로 처리하니까 2초동안 대기하지 않음
        // 결과값 처리에 대한 콜백은 스프링 MVC 가 알아서 해줌
        ListenableFuture<ResponseEntity<String>> f1 = rt.getForEntity("http://localhost:8081/service?req={req}", String.class, "hello " + idx);
        f1.addCallback(
                s -> {
                    ListenableFuture<ResponseEntity<String>> f2 = rt.getForEntity("http://localhost:8081/service2?req={req}", String.class, s.getBody());
                    f2.addCallback(s2 -> {
                        ListenableFuture<String> f3 = myService.work(s2.getBody());
                        f3.addCallback(s3 -> {
                            dr.setResult(s3);
                        }, e3 -> {
                            dr.setErrorResult(e3.getMessage());
                        });
                    }, e2 -> {
                        dr.setErrorResult(e2.getMessage());
                    });
                },
                e -> {
                    dr.setErrorResult(e.getMessage());
                });

        return dr;
    }
}

@Service
public static class MyService {
    @Async
    public ListenableFuture<String> work(String req) {
        return new AsyncResult<>(req + "/asyncwork");
    }
}

'토비의봄' 카테고리의 다른 글

8. CompletableFuture  (2) 2021.03.09
7. AsyncTemplate 의 콜백헬, 중복작업 문제  (0) 2021.03.08
5. 자바와 스프링의 비동기 개발기술  (0) 2021.03.05
4.3. Reactive Streams  (0) 2021.03.03
4.2. Reactive Streams  (0) 2021.02.28