OPEN HYPER STEP
← 목록으로 (Java+Spring)
JAVA · 77 / 99
java
CHAPTER 77 / 99
읽기 약 2
FUNCTION

비동기 처리: @Async + 이벤트


핵심 개념

@Async·@EventListener·ApplicationEvent — 이메일 발송 비동기·이벤트 기반 아키텍처.

본문

@Async 비동기 실행

JAVA📋 코드 (45줄)
@Configuration
@EnableAsync
public class AsyncConfig {

    @Bean(name = "taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(50);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("async-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}


@Service
@RequiredArgsConstructor
public class EmailService {

    @Async("taskExecutor")
    public CompletableFuture<Void> sendWelcomeEmail(String to) {
        log.info("이메일 발송 시작: {}", to);
        // ... SMTP 호출 (느림)
        Thread.sleep(2000);
        log.info("이메일 발송 완료");
        return CompletableFuture.completedFuture(null);
    }
}


@Service
@RequiredArgsConstructor
public class UserService {
    private final EmailService emailService;
    private final UserRepository userRepo;

    public User signup(SignupDto dto) {
        User user = userRepo.save(new User(dto));
        // 이메일 발송이 회원가입 응답을 막지 않음
        emailService.sendWelcomeEmail(user.getEmail());
        return user;
    }
}

이벤트 기반 — ApplicationEvent

JAVA📋 코드 (41줄)
// 이벤트 정의
public record OrderPlacedEvent(Long orderId, String userEmail, BigDecimal total) {}


// 발행
@Service
@RequiredArgsConstructor
public class OrderService {
    private final ApplicationEventPublisher publisher;
    private final OrderRepository orderRepo;

    @Transactional
    public Order placeOrder(OrderRequest req) {
        Order order = orderRepo.save(new Order(req));
        // 이벤트 발행 — 트랜잭션 커밋 후 처리됨
        publisher.publishEvent(new OrderPlacedEvent(
            order.getId(), order.getUserEmail(), order.getTotal()
        ));
        return order;
    }
}


// 리스너
@Component
@Slf4j
@RequiredArgsConstructor
public class OrderEventListener {
    private final EmailService emailService;
    private final NotificationService notificationService;
    private final InventoryService inventoryService;

    @Async
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void handleOrderPlaced(OrderPlacedEvent event) {
        log.info("주문 후처리: {}", event.orderId());
        emailService.sendOrderConfirmation(event.userEmail(), event.orderId());
        notificationService.send(event.userEmail(), "주문이 접수되었습니다");
        inventoryService.decrementForOrder(event.orderId());
    }
}

CompletableFuture 체이닝

JAVA📋 코드 (12줄)
public CompletableFuture<UserDashboard> getDashboard(Long userId) {
    CompletableFuture<User> userFuture = userService.findByIdAsync(userId);
    CompletableFuture<List<Order>> ordersFuture = orderService.findByUserAsync(userId);
    CompletableFuture<List<Notification>> notifsFuture = notifService.findByUserAsync(userId);

    return CompletableFuture.allOf(userFuture, ordersFuture, notifsFuture)
        .thenApply(v -> new UserDashboard(
            userFuture.join(),
            ordersFuture.join(),
            notifsFuture.join()
        ));
}

다음 챕터

CH.9 "파일 업로드와 S3" — 멀티파트와 클라우드 스토리지.


AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude

무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6

내 Spring 코드의 비동기 처리 부분을 분석해서
스레드 풀·rejection 정책와 개선 우선순위를 알려줘.
ChatGPT

무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro

비동기 처리 vs 다른 패턴 비교를
실전 사례 5개로 보여주고 @Async vs Kafka 트레이드오프를 알려줘.
Gemini

무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro

내 코드베이스 전체를 분석해서
비동기 처리 관련 동기 호출이 막는 위치를 보고해줘.
Grok

무료: Grok 4.1 / SuperGrok $30/mo

2026년 한국 기업의 비동기 처리 채택률과
한국 SaaS의 비동기 처리 패턴를 솔직히 알려줘.

⭐ 이것만 기억하세요
비동기 처리: @Async + 이벤트 이 3가지만 확실히 잡으세요
1.@Async는 별도 스레드 풀 권장 — 기본 스레드는 무한 생성될 수 있어 OOM
2.TransactionalEventListener로 트랜잭션 커밋 후 처리 — 롤백 시 이벤트 무시
3.다음 챕터 CH.9에서 파일 업로드 — S3 + pre-signed URL


공유하기
진행도 77 / 99