@Async가 동작하기 위해서는 먼저 AsyncConfig를 만들어주어야 한다.
@Configuration
@EnableAsync
public class AsyncConfig {
}
비동기로 동작하게 하기 위해 커스텀 쓰레드풀을 만들어 주어야 한다.
- 기본 쓰레드와, 메세징을 위한 쓰레드를 빈으로 등록하고 각각 이름을 붙여준다.
@Configuration
public class AppConfig {
@Bean(name = "defaultTaskExecutor")
public ThreadPoolTaskExecutor defaultTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(200);
executor.setMaxPoolSize(300);
return executor;
}
@Bean(name = "messagingTaskExecutor")
public ThreadPoolTaskExecutor messagingTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(200);
executor.setMaxPoolSize(300);
return executor;
}
}
테스트를 위한 컨트롤러
@RequiredArgsConstructor
@RestController
public class AsyncController {
private final AsyncService asyncService;
@GetMapping("/1")
public String asyncCall_1() {
asyncService.asyncCall_1();
return "asyncCall_1 success";
}
@GetMapping("/2")
public String asyncCall_2() {
asyncService.asyncCall_2();
return "asyncCall_2 success";
}
@GetMapping("/3")
public String asyncCall_3() {
asyncService.asyncCall_3();
return "asyncCall_3 success";
}
}
비동기 테스트를 위한 서비스
@Service
@RequiredArgsConstructor
public class AsyncService {
private final EmailService emailService;
// 빈에 등록된 emailService proxy 를 사용하기 때문에 비동기로 동작한다.
public void asyncCall_1() {
System.out.println("[asyncCall_1] :: " + Thread.currentThread().getName());
emailService.sendMail();
emailService.sendMailWithCustomThreadPool();
}
// 직접 인스턴스를 만들었기 때문에 등록된 빈을 사용하지 않아 비동기로 동작하지 않는다.
public void asyncCall_2() {
System.out.println("[asyncCall_2] :: " + Thread.currentThread().getName());
EmailService emailService = new EmailService();
emailService.sendMail();
emailService.sendMailWithCustomThreadPool();
}
// 이미 AsyncService빈을 받아와서 내부 메서드를 불러다가 사용하게 되면 비동기로 동작하지 않는다.
// @Transactional 사용시에 @Transactional이 붙은 내부 메서드를 호출할 때 일어나는 문제와 같다.
public void asyncCall_3() {
System.out.println("[asyncCall_3] :: " + Thread.currentThread().getName());
sendMail();
}
@Async
public void sendMail() {
System.out.println("[sendMail] :: " + Thread.currentThread().getName());
}
}
실제로 비동기로 동작해야 하는 메세징 서비스
@Service
@RequiredArgsConstructor
public class EmailService {
// Async를 사용하기 위해서는 접근 제어자를 private으로 하면 안된다. public처리 해야 한다.
@Async("defaultTaskExecutor")
public void sendMail() {
System.out.println("[sendMail] :: " + Thread.currentThread().getName());
}
@Async("messagingTaskExecutor")
public void sendMailWithCustomThreadPool() {
System.out.println("[sendMail2] :: " + Thread.currentThread().getName());
}
}
asyncCall_2와 asyncCall_3은 비동기로 처리되지 않는다.
- 스프링 컨텍스트에 등록된 빈을 가져다 써야 제대로 동작한다.
- 내부 메서드를 호출하면 빈 안에서 또 호출하는 상태가 되어 이 또한 제대로 동작하지 않는다. (이런 부분은 SonarLint, Sonarqube가 잡아준다.)
'Backend > spring boot' 카테고리의 다른 글
redis, sentinel 설치 (0) | 2024.03.11 |
---|---|
Logback에 대해 알아보자 (0) | 2024.03.10 |
[Spring Cloud] OpenFeign 사용법 (0) | 2024.03.10 |
Spring batch란? (0) | 2024.03.07 |