พลังเงียบของ Spring Events ที่ Java Dev ชอบมองข้าม

February 02, 2026 · 2 min read · 3 views

คุณเคยเจอสถานการณ์แบบนี้ไหม? เมื่อ User สมัครสมาชิกเสร็จ (registerUser) สิ่งที่ระบบต้องทำต่อคือ:

  1. ส่ง Welcome Email
  2. ส่ง Notification เข้า Slack ทีม
  3. สร้าง Wallet เริ่มต้นให้ User
  4. เก็บ Log ลง Audit Service

Code ปกติที่เรามักจะเขียนกัน:

java
@Service
public class UserService {
    // Inject มาเพียบ!
    private final UserRepository userRepository;
    private final EmailService emailService;
    private final SlackService slackService;
    private final WalletService walletService;
    private final AuditService auditService;

    public void register(UserDto dto) {
        User user = userRepository.save(dto.toEntity());
        
        // ผูก Logic ทุกอย่างไว้ตรงนี้
        emailService.sendWelcome(user);
        slackService.notifyTeam(user);
        walletService.createInitialWallet(user);
        auditService.logRegistration(user);
    }
}

ปัญหาคืออะไร? (The Impact)

Code นี้ทำงานได้ แต่ "High Coupling" สุดๆ

  • ถ้าวันหนึ่งระบบ Email ล่ม? -> register พังไปด้วย
  • ถ้าต้องเพิ่ม SMS Notification? -> ต้องมาแก้ class UserService (ผิดหลัก Open/Closed Principle)
  • UserService บวมขึ้นเรื่อยๆ ทั้งที่หน้าที่หลักคือแค่ "สมัครสมาชิก"

ทางออก: พลิกกระบวนท่าด้วย ApplicationEventPublisher

ใน Spring Boot เรามี Event Bus อยู่ในตัวแล้ว ไม่ต้องลง Kafka หรือ RabbitMQ เพิ่มสำหรับการสื่อสารภายในแอพ สิ่งที่คุณต้องทำคือ "ตะโกนบอกว่ามีเหตุการณ์เกิดขึ้น" แล้วให้คนอื่นไปจัดการต่อเอง

เปลี่ยน Code เป็นแบบนี้:

java
@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;
    private final ApplicationEventPublisher publisher; // พระเอกของเรา

    public void register(UserDto dto) {
        User user = userRepository.save(dto.toEntity());
        
        // แค่บอกว่า "มีคนสมัครแล้วนะ!" จบหน้าที่
        publisher.publishEvent(new UserRegisteredEvent(user));
    }
}

และสร้าง Listener แยกกันไปเลย:

java
@Component
public class NotificationListener {

    @EventListener
    @Async // ใส่ Async ได้เลย ถ้าไม่อยากให้รอกัน
    public void handleEmail(UserRegisteredEvent event) {
        emailService.sendWelcome(event.getUser());
    }

    @EventListener
    public void handleSlack(UserRegisteredEvent event) {
        slackService.notifyTeam(event.getUser());
    }
}

ทำไมท่านี้ถึง Impact เยอะ?

  1. Decoupling ขั้นสุด: UserService ไม่รู้จัก EmailService อีกต่อไป การแก้ไข Logic การส่งเมล ไม่กระทบ Logic การสมัครสมาชิก
  2. Performance Boost ง่ายๆ: แค่เติม @Async บน Listener งานหนักๆ อย่างส่งเมลหรือคุยกับ 3rd Party ก็จะแยก Thread ออกไปทันที ทำให้ User ไม่ต้องรอ Loading นาน
  3. Transaction Control (@TransactionalEventListener): นี่คือ Hidden Gem จริงๆ คุณสามารถสั่งให้ Listener ทำงาน "เฉพาะตอนที่ Commit Transaction หลักสำเร็จแล้วเท่านั้น" ได้ (เช่น ถ้า Save User ไม่สำเร็จ ก็ไม่ต้องส่งเมล) โดยเปลี่ยนจาก @EventListener เป็น @TransactionalEventListener
java
@Component
public class NotificationListener {

    // phase = AFTER_COMMIT คือ Default (ไม่ต้องใส่ก็ได้ แต่ใส่ให้ชัดเจนดีกว่า)
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    @Async
    public void handleEmail(UserRegisteredEvent event) {
        emailService.sendWelcome(event.getUser());
    }

    @EventListener
    public void handleSlack(UserRegisteredEvent event) {
        slackService.notifyTeam(event.getUser());
    }
}

บทสรุป

การเขียน Code ไม่ใช่แค่ทำให้มัน "ทำงานได้" แต่ต้องทำให้มัน "เติบโตได้" การใช้ Spring Events คือกุญแจสำคัญที่จะเปลี่ยน Spaghetti Code ให้กลายเป็น Modular Architecture ที่สวยงามและดูแลรักษาง่ายครับ

Responses (1)

ผู้เยี่ยมชม 1 day ago

สุดยอดครับ ปกติพังทีพังหมดเลย