본문 바로가기

Spring & Java

spring controller async request process with executor

반응형

스프링에서 컨트롤러에서 요청에 대한 처리를 동기가 아닌 비동기 처리하는 방식을 제공 하고있다.
스프링5 의 webflux 사용한다면 해당 비동기 처리를 사용할 수 있지만 스프링 5 버전 이하의 시스템에서는
해당 처리가 필요할 것이다.

  • 스프링이 제공하는 방식

    비동기로 처리하기 위해 스프링에서 여러가지 반환 유형을 제공한다.
    요청에 대해 즉각 응답을 주는것이 아닌 요청에 대한 처리를 백그라운드로 처리하여 완료시 사용자에게 반환 함으로써 요청 처리에 대한
    병목을 없애도록 한다.

  • 스프링이 제공하는 비동기 응답

    > 다른 스레드로 생성된 비동기 결과
    > > DefferedResult  
    > > ListenableFuture  
    > > CompletionStage  
    > > CompletableFuture  
    
    > > 연산 후 생성된 결과로 비동기 계산  
    > > Callable  
    
    > > ResponseBodyEmitter  
    > > 비동기 응답을 다수의 객체로 작성 할 때 사용  
    
    > > SseEmitter  
    > > 비동기 서버-전송 이벤트를 작성 할 때 사용
    
    > > StreamingResponseBody  
    > > 비동기 OutputStream 을 작성 할 때 사용.
    
  • reference book: SpringBoot2 Receipes

- 비동기 처리를 위한 taskExecutor 설정

/**
 * TaskExecutor 에 대한 설정 파일
 */
@Configuration
public class DemoConfig implements WebMvcConfigurer {

    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
        configurer.setTaskExecutor(mvcTaskExecutor());
    }

    @Bean
    public ThreadPoolTaskExecutor mvcTaskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setThreadNamePrefix("mvc-task-");
        taskExecutor.setCorePoolSize(10);
        taskExecutor.setMaxPoolSize(50);
        taskExecutor.setQueueCapacity(100);
        return taskExecutor;
    }
}

- 비동기 컨트롤러 작성

@RestController
public class DemoController {
    public final String RESPONSE_MESSAGE = "Hello wooriworld, from spring completablefuture";
    private final TaskExecutor taskExecutor;

    public DemoController(TaskExecutor taskExecutor) {
        this.taskExecutor = taskExecutor;
    }

    @GetMapping
    public CompletableFuture<String> demoCompletableFuture(){
        //요청에 대한 응답은 딜레이 초 후 주도록 하기 위해 sleep 함.
        return CompletableFuture.supplyAsync(()-> {
            randomDelay();
            return RESPONSE_MESSAGE;
        },taskExecutor);
    }
    private void randomDelay() {
        try{
            Thread.sleep(ThreadLocalRandom.current().nextInt(5000));
        }catch(InterruptedException e){
            Thread.currentThread().interrupt();
        }
    }
}

- 비동기 컨트롤러 테스트

@RunWith(SpringRunner.class)
@WebMvcTest(DemoController.class)
public class DemoControllerTest {
    public final String RESPONSE_MESSAGE = "Hello wooriworld, from spring completablefuture";

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testDemoCompletableFuture() {
        try {
            MvcResult mvcResult = mockMvc.perform(get("/"))
                    .andExpect(request().asyncStarted())
                    .andDo(MockMvcResultHandlers.log())
                    .andReturn();

            mockMvc.perform(asyncDispatch(mvcResult))
                    .andExpect(status().isOk())
                    .andExpect(content().contentTypeCompatibleWith(TEXT_PLAIN))
                    .andExpect(content().string(RESPONSE_MESSAGE));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

github source

반응형

'Spring & Java' 카테고리의 다른 글

Java Object Stream group by multiple field and map in map to list  (0) 2020.01.05
JPA - Join  (0) 2019.12.08
Java 8 Stream range  (0) 2019.08.24
usage spring data jpa with query dsl  (0) 2019.07.14
Spring Batch (정리)  (0) 2019.04.06