พลังเงียบของ Spring Events ที่ Java Dev ชอบมองข้าม
February 02, 2026
·
2 min read
·
3 views
คุณเคยเจอสถานการณ์แบบนี้ไหม?
เมื่อ User สมัครสมาชิกเสร็จ (registerUser) สิ่งที่ระบบต้องทำต่อคือ:
- ส่ง Welcome Email
- ส่ง Notification เข้า Slack ทีม
- สร้าง Wallet เริ่มต้นให้ User
- เก็บ 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 เยอะ?
- Decoupling ขั้นสุด:
UserServiceไม่รู้จักEmailServiceอีกต่อไป การแก้ไข Logic การส่งเมล ไม่กระทบ Logic การสมัครสมาชิก - Performance Boost ง่ายๆ: แค่เติม
@Asyncบน Listener งานหนักๆ อย่างส่งเมลหรือคุยกับ 3rd Party ก็จะแยก Thread ออกไปทันที ทำให้ User ไม่ต้องรอ Loading นาน - 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 ที่สวยงามและดูแลรักษาง่ายครับ
สุดยอดครับ ปกติพังทีพังหมดเลย