เลิกใช้ @Autowired บน Field: ทำไม Constructor Injection ถึงดีกว่า?

February 09, 2026 · 2 min read · 0 views

ในการเขียน Spring Boot เราคุ้นเคยกับการใช้ Dependency Injection (DI) เพื่อดึง Bean มาใช้งาน วิธีที่ง่ายและพบบ่อยที่สุดคือการแปะ @Autowired ไว้บน Field (Field Injection)

java
// แบบที่พบได้บ่อย (Field Injection)
@Service
public class OrderService {
    @Autowired
    private UserRepository userRepository; // <--- สะดวก แต่มีปัญหาแฝง
}

แม้จะดูสั้นและสะดวก แต่ทีมพัฒนา Spring Framework (Pivotal) และ Java Experts ทั่วโลกต่างแนะนำให้ หลีกเลี่ยง วิธีนี้ และหันมาใช้ Constructor Injection แทน

บทความนี้จะอธิบายเหตุผล 3 ข้อหลัก ว่าทำไม Field Injection ถึงไม่ควรใช้ และเราจะเขียน Code ให้ดีขึ้นได้อย่างไร

เหตุผลที่ 1: ปัญหาเรื่อง Null Safety และการทำ Unit Test

ปัญหา (Problem)

Field Injection ซ่อน Dependency ไว้ภายใน Class หากเราต้องการเขียน Unit Test แบบ Pure Java (ไม่โหลด Spring Context เพื่อความเร็ว) เราจะไม่สามารถส่ง Mock Object เข้าไปใน Class นั้นได้เลย นอกจากการใช้ Reflection หรือ Framework ช่วย

java
// Unit Test จะพัง
OrderService service = new OrderService();
service.findOrder(); // Throws NullPointerException เพราะ userRepository เป็น null

การแก้ปัญหา (Solution)

Constructor Injection บังคับให้เราต้องส่ง Dependency เข้าไปตั้งแต่ตอนสร้าง Object ทำให้มั่นใจได้ว่า Object นั้นจะไม่มีสถานะที่ไม่สมบูรณ์ (Incomplete State)

java
// Constructor Injection
public OrderService(UserRepository userRepository) {
    this.userRepository = userRepository;
}

// ใน Unit Test เราสามารถส่ง Mock ได้ง่ายๆ
OrderService service = new OrderService(new MockUserRepository());

เหตุผลที่ 2: Immutability (ความคงทนของข้อมูล)

ปัญหา (Problem)

การใช้ Field Injection บังคับให้ Field นั้นต้องเป็น Mutable (แก้ไขค่าได้) เราไม่สามารถประกาศตัวแปรเป็น final ได้ เพราะ Spring ต้องใช้ Reflection มา set ค่าให้หลังจากสร้าง Object เสร็จแล้ว

การแก้ปัญหา (Solution)

Constructor Injection อนุญาตให้เราประกาศ Field เป็น final ได้ ซึ่งเป็นหัวใจสำคัญของ Immutable Design ทำให้มั่นใจได้ว่า Dependency นั้นจะไม่ถูกเปลี่ยนค่ากลางคันตลอดอายุการทำงานของ Application

java
private final UserRepository userRepository; // ปลอดภัยกว่า

เหตุผลที่ 3: Circular Dependency (การเรียกวน)

ปัญหา (Problem)

หาก Service A เรียก Service B และ Service B เรียก Service A (A -> B -> A)

  • Field Injection: Spring อาจจะยอมให้ Application รันขึ้นมาได้ ก่อนจะไปพังตอน Runtime (StackOverflowError) เมื่อมีการเรียกใช้ Method
  • Constructor Injection: Spring จะแจ้ง Error ตั้งแต่ตอน Start Application (BeanCurrentlyInCreationException) ทำให้เรารู้ตัวและแก้ปัญหาการ Design Architecture ที่ผิดพลาดได้ทันที (Fail Fast)

วิธีเขียน Constructor Injection ให้สั้นกระชับด้วย Lombok

หลายคนไม่ชอบ Constructor Injection เพราะต้องเขียน Code เยอะ (Boilerplate)

java
// แบบดั้งเดิม (Boilerplate เยอะ)
@Service
public class OrderService {
    private final UserRepository userRepository;
    private final EmailService emailService;

    // ต้องมานั่งเขียน Constructor เอง
    public OrderService(UserRepository userRepository, EmailService emailService) {
        this.userRepository = userRepository;
        this.emailService = emailService;
    }
}

เราสามารถใช้ Lombok Annotation @RequiredArgsConstructor มาช่วยสร้าง Constructor ให้กับ Field ที่เป็น final โดยอัตโนมัติ

Code ฉบับสมบูรณ์ (Best Practice)

java
@Service
@RequiredArgsConstructor // 1. สร้าง Constructor ให้อัตโนมัติ
public class OrderService {

    // 2. ประกาศเป็น final เพื่อความปลอดภัย (Immutability)
    private final UserRepository userRepository;
    private final EmailService emailService; 
    
    // ไม่ต้องมี @Autowired
    // ไม่ต้องเขียน Constructor เอง
}

สรุป

การเปลี่ยนจาก Field Injection มาเป็น Constructor Injection ไม่ใช่แค่เรื่องความสวยงาม แต่เป็นเรื่องของความเสถียร (Robustness) ของ Software:

  1. Testability: เขียน Unit Test ง่าย ไม่ต้องพึ่ง Reflection
  2. Immutability: ใช้ final ได้ ป้องกันการเปลี่ยนค่าโดยไม่ตั้งใจ
  3. Fail Fast: เจอ Circular Dependency ตั้งแต่ตอน Start App
  4. Clean Code: ใช้ @RequiredArgsConstructor ทำให้ Code สั้น กระชับ และอ่านง่าย

หาก Code ของคุณยังเต็มไปด้วย @Autowired บน Field ลองเริ่มทยอย Refactor วันนี้ เพื่อ Code Quality ที่ดีขึ้นในระยะยาวครับ

Responses (0)

No responses yet. Be the first to respond.