2023. 12. 21. 22:19ใBackend/๐ฟ Spring
๋ชฉ์ฐจ
- ์๋ก
- @EnableAsync ๋์์๋ฆฌ
- @Async ๋์์๋ฆฌ
- ๊ฒฐ๋ก
์ค์ต ํ๊ฒฝ
- Java 17
- Springboot 3.2.0
์๋ก
์ค๋ฌด์์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ํด CompletableFuture ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ค. ์ ๋์ํ๋ ๊ฒ์ ํ์ธํ์ง๋ง ๋ฌธ๋ @Async ์ด๋ ธํ ์ด์ ์ ์ด์ฉํ๋ฉด ๋ ํธ๋ฆฌํ์ง ์์๊น ํ๋ ์๊ฐ๊ณผ @Async๋ ์ด๋ค ์๋ฆฌ๋ก ๋น๋๊ธฐ๋ฅผ ์ฒ๋ฆฌํ๋์ง ๊ถ๊ธํด์ก๋ค. @Async ๋ด๋ถ ๋์์ ๋๋ฒ๊น ํ ๊ฒฐ๊ณผ ๊ฒฐ๊ตญ @Async ์ญ์ CompletableFuture์ ์ฌ์ฉํ๊ณ ์์๋ค.
์ด ๊ธ์์๋ ์คํ๋ง๋ถํธ์์ @Async ์ด๋ ธํ ์ด์ ์ด ๋ถ์ ๋ฉ์๋๊ฐ ์ด๋ป๊ฒ ๋น๋๊ธฐ๋ก ์ฒ๋ฆฌ๋๋์ง์ ๋๋ถ์ด @EnableAsync ๊ฐ ์ด๋ป๊ฒ ๋์ํ๋์ง๋ฅผ ๋ค๋ค๋ณด๊ฒ ๋ค.
@EnableAsync ๋์์๋ฆฌ
@EnableAsync
main() ๋ฉ์๋๊ฐ ์๋ ํด๋์ค์ @EnableAsync ๋ฅผ ๋ถ์ธ ํ ํ๋ก์ ํธ๋ฅผ ์คํํ๋ค.
๋๋ฒ๊ฑฐ๋ฅผ ์ฐ์ผ๋ฉด์ ์ด๋ค ์๋ฆฌ๋ก @Async ๊ฐ ๋ฑ๋ก๋๋์ง ํ์ธํด๋ณด์.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
...
AdviceMode mode() default AdviceMode.PROXY;
}
@EnableAsync ๋ด๋ถ์์ AsyncConfigurationSelector ํด๋์ค๋ฅผ ์ํฌํธ ํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
AdviceMode๋ PROXY ์ ASPECTJ 2๊ฐ์ง ํ์ ์ด ์กด์ฌํ๋๋ฐ ์ฌ๊ธฐ์ PROXY๋ก ๋ํดํธ ์ค์ ๋๋ค.
PROXY ํ์ ์ JDK proxy-based ๋ก ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ํด๋์ค์๋ง ์ ์ฉ ๊ฐ๋ฅํ๋ค.
AsyncConfigurationSelector
AsyncConfigurationSelector์์๋ AdviceMode์ ๋ฐ๋ผ ProxyAsyncConfiguration์ด๋ AspectJAsyncConfiguration์ ๋ฐฐ์ด์ ๋ด์ ๋ฆฌํดํ๋ค. ์ฌ๊ธฐ์ PROXY ๋ชจ๋๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ProxyAsyncConfiguration ๊ฐ ๋ฆฌํด๋๋ค. ProxyAsyncConfiguration ํด๋์ค๋ก ์ด๋ํด๋ณด์.
ProxyAsyncConfiguration
์ด๊ณณ์์ AsyncAnnotationBeanPostProcessor์ Bean์ผ๋ก ์์ฑํ๋ค.
AsyncAnnotationBeanPostProcessor
ํด๋น ๋นํ์ฒ๋ฆฌ๊ธฐ์์ AsyncAnnotationAdvisor๋ฅผ ์ด๋๋ฐ์ด์ ๋ก ํ ๋นํ๋ค.
(AsyncAnnotationAdvisor๋ BeanFactoryAware์ ๊ตฌํ์ฒด๋ก setBeanFactory()๋ฅผ ์ค๋ฒ๋ผ์ด๋)
AsyncAnnotationAdvisor๋ก ์ด๋ํด ๋ณด์.
AsyncAnnotationAdvisor
AsyncAnnotationAdvisor์ ์์ฑ์ ๋ถ๋ถ์ด๋ค.
๋ณต์กํด ๋ณด์ด์ง๋ง ๊ฒฐ๊ตญ Advisor์์ advice์ pointcut์ ํ ๋นํ๋ ๋ถ๋ถ์ด ํต์ฌ์ด๋ค.
๋ง์ง๋ง ๋ ๋ผ์ธ์์ ๊ฐ๊ฐ buildAdvice()์ buildPointcut() ๋ฉ์๋๋ก ๊ฐ์ ํ ๋นํ๊ณ ์๋ค.
์ค๊ฐ ์ ๋ฆฌ๋ฅผ ํ์๋ฉด ์ฐ๋ฆฌ๋ @EnableAsync์ ๋์๊ณผ์ ์ ํ์ ํ๋ ์ค์ด๋ฉฐ @EnableAsync๋ @Async ๊ฐ ๋์ํ๊ธฐ ์ํ ์ฌ์ ์ค์ ๊ณผ์ ์ผ๋ก ์๊ณ ์๋ค. ์ฆ @Async ๊ฐ ๋ถ์ ๋ฉ์๋๋ฅผ ๋น๋๊ธฐ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํ ์คํ๋ง์ ์ฌ์ ์ค์ ๊ณผ์ ์ด๋ค. ์ง๊ธ๊น์ง์ ๊ณผ์ ์ ์ดํด๋ณด๋ฉด @Async ๊ฐ ๋์ํ๊ธฐ ์ํด์ Proxy ์ค์ ๊ณผ AsyncAnnotationAdvisor ์ด ํ์ํ ๊ฑธ ์๊ฒ ๋๋ค.
๋ค์ AsyncAnnotationAdvisor๋ก ๋์์ ํด๋น ์ด๋๋ฐ์ด์ ์ ์ด๋ค ํฌ์ธํธ์ปท๊ณผ ์ด๋๋ฐ์ด์ค๊ฐ ํ ๋น๋๋์ง ์ฝ๋๋ก ํ์ธํด ๋ณด์.
AsyncAnnotationAdvisor.buildAdvice()
advice๋AnnotationAsyncExecutionInterceptor ๊ฐ ํ ๋น๋๋ค.
AsyncAnnotationAdvisor.pointcut()
pointcut ์๋ [..., interface org.springframework.scheduling.annotation.Async, ...] ์ด ํ ๋น๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค. ์ฆ AsyncAnnotationBeanPostProcessor๋ผ๋ ๋น ํ์ฒ๋ฆฌ๊ธฐ์ ์ํด @Async๋ AsyncAnnotationAdvisor ๊ฐ ๋์ํ ์ ์๋ ํฌ์ธํธ์ปท์ด ๋๋ค.
๋ค์ด์ด๊ทธ๋จ์ผ๋ก ํ์ธํ๋ฉด ์๋์ ๊ฐ๋ค.
@Async ๋์ ๊ณผ์
EnableAsync ๊ฐ ์ด๋ค ์์ผ๋ก ๋์ํ๋์ง ํ์ ํ์ผ๋ ์ค์ ๋ก @Async๋ฅผ ์ฌ์ฉํด ๋ณด์. ์ฐ์ ์ ํ๋ฆฌ์ผ์ด์ ํด๋์ค์ @EnableAsync๋ฅผ ์ค์ ํ๋ค. ์ด๋ก์จ ์คํ๋ง๋ถํธ๊ฐ ์คํ๋ ๋AsyncAnnotationAdvisor ๊ฐ ๋ฑ๋ก๋๋ ๊ฒ์ ์ ๊ณผ์ ์ ํตํด ํ์ธํ๋ค.
AsyncExecutionInterceptor
@Async ์ด๋ ธํ ์ด์ ์ด ๋ถ์ ๋ฉ์๋๊ฐ ํธ์ถ๋๋ฉด AsyncExecutionInterceptor.invoke()์์ ์์ฒญ์ ๊ฐ๋ก์ฑ๋ค.
์ ๋ค์ด์ด๊ทธ๋จ์์ AsyncAnnotationAdvice์ ์ํด AnnotationAsyncExecutionInterceptor ๊ฐ ์์ฑ๋๋ ๊ฒ๊ณผ AsyncExecutionInterceptor ์ AnnotationAsyncExecutionInterceptor์ ๋ถ๋ชจํด๋์ค๋ ๊ฑธ ํ์ธํ ์ ์๋ค.
๋ง์ง๋ง ๋ผ์ธ์์ doSubmit()๊ฐ ํธ์ถ๋๋ฉฐ, ํด๋น ๋ฉ์๋๋ AsyncExecutionAspectSupport ์ถ์ ํด๋์ค์ ์ ์๋ผ ์๋ค.
์ด๋ ์ธ์๋ก task ๋๋ค์๊ณผ executor๋ฅผ ๋๊ฒจ ํธ์ถํ๋ค.
doSubmit
๊ฒฐ๊ตญ @Async ์ด๋ ธํ ์ด์ ์ผ๋ก ์ ์ธ๋ ๋ฉ์๋๋ ์ต์ข ์ ์ผ๋ก doSubmit() ๋ก์ง์ ๋ฐ๋ผ ๋น๋๊ธฐ๋ก ๋์ํ๋ค. ์ด๋ @Async ๋ฉ์๋์ ๋ฆฌํด ํ์ ์ ๋ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ ์์ดํ๊ฒ ๊ตฌํ๋๋ค.
์ด ๋ฆฌํด ํ์ ์ doSubmit()์ ์ธ ๋ฒ์งธ ์ธ์๋ก invoke() ๋ฉ์๋์์ invocation.getMethod().getReturnType()์ ํด๋น๋๋ค.
๊ฐ๊ฐ์ ์ผ์ด์ค๋ 4๊ฐ์ง๋ก ์ ๋ฆฌ๋๋ค.
1. CompletableFuture
2. ListenableFuture
3. Future
4. void
CompletableFuture์ ListenableFuture๋ ๋ชจ๋ Future ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ค.
์ค์ต ์ฝ๋๋ฅผ ํตํด @Async ์ด๋ ธํ ์ด์ ์ด ์ ์ธ๋ ๋ฉ์๋๋ ์ด๋ค ์์ผ๋ก doSubmit() ๋ด๋ถ์์ ์ฒ๋ฆฌ๋๋์ง ํ์ธํด ๋ณด์.
@RestController
@RequiredArgsConstructor
public class SampleController {
private final AsyncService asyncService;
@GetMapping("return-async-future")
public void returnFuture() throws InterruptedException, ExecutionException {
log.info("before Async");
asyncService.completableFutureAsync()
.thenAccept(result -> log.info("Return of Async | {}", result));
log.info("after Async");
return;
}
}
@Service
public class AsyncService {
@Async
public CompletableFuture<Integer> completableFutureAsync() throws InterruptedException {
log.info("middle of completableFutureAsync()");
return new AsyncResult<>(1).completable();
}
}
์์ ์ฝ๋์ ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ ์๋์ ๊ฐ๋ค.
@Async ์ฒ๋ฆฌ๋ completableFutureAsync() ๋ด๋ถ์ ๋ก๊ทธ๊ฐ 'after Async' ๋ณด๋ค ๋ฆ๊ฒ ์ถ๋ ฅ๋๋๋ฐ, ์ด๋ ํด๋น ๋ฉ์๋๊ฐ ๋ ผ๋ธ๋กํน ๋น๋๊ธฐ์์ผ๋ก ์ฒ๋ฆฌ๋์์ ์ ์ ์๋ค. ๋ฉ์๋์ ๊ฒฐ๊ณผ๋ callback ํ์์ผ๋ก thenAccept ๋ด๋ถ์์ ์ฒ๋ฆฌ๋๋ค. ๋น๋๊ธฐ ๋ฉ์๋์ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํด ๋ฐ์ ์ฒ๋ฆฌํด์ผ ํ๋ค๋ฉด thenAccep(), thenApply() ๋ฑ์ ๋ฉ์๋๋ฅผ ํ์ฉํ ์ ์๋ค.
ํ์ฌ ์ผ์ด์ค์์ @Async ๋ฌ๋ฆฐ ๋ฉ์๋์ ๋ฆฌํดํ์ ์ CompletableFuture๋ก ์ฒซ ๋ฒ์งธ ๋ถ๊ธฐ๋ฌธ์ ๊ฑธ๋ ค ๋ฆฌํด๋๋ค.
ํด๋น ๋ถ๊ธฐ๋ฌธ์์ task๋ฅผ submitCompletable() ๋ฉ์๋์ ์ธ์๋ก ๋๊ธฐ๊ณ ์ต์ข ์ ์ผ๋ก CompletableFuture ํด๋์ค๊ฐ ํด๋น task๋ฅผ ์ฒ๋ฆฌํ๋ค.
์ด๋ ์ฐ๋ฆฌ๋ ๋ณ๋์ executor๋ฅผ ์ง์ ํ์ง ์์๊ธฐ ๋๋ฌธ์ ThreadPoolTaskExecutor์์ ํด๋น ์์ ์ ์ฒ๋ฆฌํ๋ค. ๋ค๋ง ์ด์ฒ๋ผ ๋ณ๋์ executor๋ฅผ ์ง์ ํ์ง ์์ผ๋ฉด ForkJoinPool์ CommonPool์ ์ฌ์ฉํ๊ฒ ๋๋๋ฐ, ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด์ ์ ์์์น ๋ชปํ ์ฅ์ ๊ฐ ๋ฐ์ํ ์ ์์ผ๋ ์ฌ์ฉ์ ์ฃผ์ํ ํ์๊ฐ ์๋ค๊ณ ํ๋ค. (์ถ์ฒ : https://brunch.co.kr/@springboot/401 )
์คํ๋ง๋ถํธ 3.0 ์ด์ ์๋..
์๋ ์ฝ๋๋ ์คํ๋ง๋ถํธ 2.7.8 ๋ฒ์ ์ doSubmit() ๊ตฌํ ๋ก์ง์ผ๋ก returnType ์ด CompletableFuture ์ผ ๊ฒฝ์ฐ,
๋ช ์์ ์ผ๋ก CompletableFuture.supplyAsync() ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์ฆ @Async ์ด๋ ธํ ์ด์ ์ ์ธ๋ ๋ฉ์๋๋ ๊ฒฐ๊ตญ CompletableFuture ํด๋์ค๋ฅผ ํตํด ๋น๋๊ธฐ ๋ก์ง์ด ์ฒ๋ฆฌ๋๋ ๊ฑธ ํ์ธํ ์ ์๋ค.
์ ๋ฆฌ
์คํ๋ง๋ถํธ์์ ๊ฐ๋จํ๊ฒ ๋น๋๊ธฐ ํธ์ถ์ ์ ์ฉํ ์ ์๋ @Async์ ๋์์๋ฆฌ๋ฅผ ์ดํด๋ดค๋ค.
์ ๋ฆฌํ์๋ฉด
- @Async๋ @EnableAsync ๋ฅผ ํ์๋ก ํ๋ฉฐ ์ด๋ Proxy ๋ชจ๋๋ก ์ค์ ๋์ด ์๋ค.
- ์ฆ @Async ๋ ๊ธฐ๋ณธ์ ์ผ๋ก Spring AOP ์ ์ฝ์ฌํญ์ ๋ฐ๋ฅธ๋ค. ์ด๋ pointcut ์ @Async, advice๋ AnnotationAsyncExecutionInterceptor๊ฐ ๋๋ค.
- @Async ๋ฉ์๋๋ AsyncExecutionInterceptor์ ๋์์ด ์ธํฐ์ ํธ๋๊ณ ๋ฆฌํด ํ์ ์ ๋ฐ๋ผ ๋น๋๊ธฐ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํดํ๋ค.
- ๊ฒฐ๊ณผ์ ์ผ๋ก @Async ์ด๋ ธํ ์ด์ ์ด ์ ์ธ๋ ๋ฉ์๋๋ ๋ด๋ถ์์ CompletableFuture ํด๋์ค์ ์ํด ๋น๋๊ธฐ๋ก ๋์ํ๋ค.
๊ฒฐ๊ตญ ์คํ๋ง์์ @Async๋ฅผ ํตํ ๋น๋๊ธฐ๋ก์ง์ ํต์ฌ์ CompletableFuture๋ผ๋ ๊ฒฐ๋ก ์ ๋จ๊ธฐ๊ฒ ๋๋ค. ๋ค์ ํฌ์คํ ์์ ์ด CompletableFuture์ ์ ์ฒด(?)์ ์๋ฆฌ์ ๋ํด ๋ ๊น์ด ๋ค๋ค ๋ณผ ์์ ์ด๋ค.
ref