Spring에서 비동기

Panda·2022년 6월 21일
0

Spring

목록 보기
25/45

자바에서 비동기를 사용하려면 쓰레드를 이용을 하였습니다

static ExecutorService executorService = Executors.newFixedThreadPool(5);

public void asyncMethod(final String message) throws Exception {
	executorService.submit(new Runnable() {
   		@Override
    	public void run() {
    	// do something
    	}            
    });
}	

Excutors를 사용해 ThreadPool 생성을 하고

비동기로 작동할 기능을 등록시켜 작동하면 됐습니다.
submit 말고 다양하게 실행시킬 수 있습니다.

코틀린의 코루틴 이나 자바스크립트의 async, await
비동기를 동기적으로 작성할 수 있다는것이 너무나도 부러웠습니다.

그래서 이것저것 찾아보다가
@Async 을 발견했습니다.

Async 어노테이션

사용법

@EnableAsync
@SpringBootApplication
public class SpringBootApplication {
}

Async 어노테이션을 사용하려면 Application Class에
@EnableAsync 를 적용시켜야 합니다.

@Async
public void asyncMethod(int i) {
	try {
    	Thread.sleep(500);
        System.out.println(i + "번째 작동");
    } catch(InterruptedException e) {
    	e.printStackTrace();
    }
}

비동기로 작동하고 싶은 메소드에 @Async를 붙여주시면 됩니다.

@Async의 기본 설정은 SimpleAsyncTaskExecutor를 사용하게 됩니다.
만약 원하는 설정을 하고싶으면 AsyncConfigurerSupport 를 상속받아서 원하는대로 설정하시면 될것같습니다.

Custom Async

@Configuration
@EnableAsync
public class AsyncConfig extends AsyncConfigurerSupport {
    
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);	// Poolsize
        executor.setMaxPoolSize(30);	// max Pool 
        executor.setQueueCapacity(50);	// queue 용량
        executor.setThreadNamePrefix("DDAJA-ASYNC-");
        executor.initialize();
        return executor;
    }
}
  • CorePoolSize : 기본 실행 대기하는 Thread의 수
  • MaxPoolSize : 동시 동작하는 최대 Thread의 수
  • QueueCapacity : MaxPoolSize 초과 요청에서 Thread 생성 요청시,
    해당 요청을 Queue에 저장하는데 이때 최대 수용 가능한 Queue의 수,
    Queue에 저장되어있다가 Thread에 자리가 생기면 하나씩 빠져나가 동작

이렇게 Async 환경설정을 해주면 똑같이 @Async 를 적용만 시켜주면 해당 환경들이 적용이 됩니다.

주의사항

  1. private method는 사용 불가, public method만 사용 가능

  2. self-invocation(자가 호출) 불가, 즉 inner method는 사용 불가

  3. QueueCapacity 초과 요청에 대한 비동기 method 호출시 방어 코드 작성

그 이유는
@Async의 동작은 AOP가 적용되어 Spring Context에서 등록된 Bean Object의 method가 호출 될 시에,
Spring이 확인할 수 있고 @Async가 적용된 method의 경우 Spring이 method를 가로채 다른 Thread에서 실행 시켜주는 동작 방식입니다.
이 때문에 Spring이 해당 @Async method를 가로챈 후, 다른 Class에서 호출이 가능해야 하므로,private method는 사용할 수 없습니다.

비동기 자기 호출 결과

@Controller
public class TestController {

    @Async
    public void asyncMethod(int i) {
        try {
            Thread.sleep(500);
            System.out.println(i + "번째 작동");
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
    }

    @GetMapping("async")
    public String testAsync() {
        for(int i = 0; i < 50; i++) {
            asyncMethod(i);
        }
        return "";
    }

}

자기 호출로 비동기를 한번 테스트 해보았습니다.

비동기가 아닌 동기적으로 작동된것을 보아 @Async이 적용이 안된것을 확인할 수 있었습니다.

비동기 실행 결과

@Service
public class TestService {
    @Async
    public void asyncMethod(int i) {
        try {
            Thread.sleep(500);
            System.out.println(i + "번째 작동");
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
    }
}
@Controller
public class TestController {
    @Autowired	// 귀찮아서 Autowired 씀
    private TestService testService;

    @GetMapping("async")
    public String testAsync() {
        for(int i = 0; i < 50; i++) {
            testService.asyncMethod(i);
        }
        return "";
    }

}


비동기로 작동되는 모습을 제대로 확인하였습니다.

느낀 점

@Async 어노테이션으로 비동기를 좀더 쉽게 작성할 수 있어서 좋았지만
이것 역시 Custom 해서 써야할것같고
당연한 이야기겠지만 Thread를 결국 관리를 해줘야된다는 점에서
Thread를 리스크를 지니게 되는것같습니다.
(저는 Thread 관리가 가장 무서워요 ㅠㅠ)

Java에서 코틀린의 코루틴 또는 자바스크립트의 async await 과 같은 기능이
지원됐으면 좋겠습니다.........

profile
실력있는 개발자가 되보자!

0개의 댓글