Field Injection chính xác là gì và làm thế nào để tránh nó?


130

Tôi đã đọc trong một số bài đăng về Spring MVC và Portlet rằng việc tiêm trường không được khuyến khích. Theo tôi hiểu, tiêm trường là khi bạn tiêm Bean @Autowirednhư thế này:

@Component
public class MyComponent {
    @Autowired
    private Cart cart;
}

Trong quá trình nghiên cứu của mình, tôi cũng đã đọc về việc tiêm hàm tạo :

@Component
public class MyComponent {
    private final Cart cart;

    @Autowired
    public MyComponent(Cart cart){
       this.cart = cart;
    }
}

Ưu điểm và nhược điểm của cả hai loại tiêm này là gì?


CHỈNH SỬA 1: Vì câu hỏi này được đánh dấu là trùng lặp với câu hỏi này nên tôi đã kiểm tra nó. Vì không có bất kỳ ví dụ mã nào trong câu hỏi cũng như trong câu trả lời nên tôi không rõ nếu tôi đoán đúng với suy đoán của mình mà tôi đang sử dụng loại tiêm nào.


3
Nếu field-injection tệ như bạn mô tả thì tại sao Spring lại cho phép? Chèn trường có lợi ích riêng của nó, trong việc làm cho mã dễ đọc hơn và ít dài dòng hơn. Nếu bạn đủ kỷ luật trong việc viết mã của mình, bạn có thể chắc chắn rằng mọi thứ sẽ không bị phá vỡ ngay cả khi bạn sử dụng phương thức tiêm trường.
tro

@ashes Bởi vì nó là một tính năng gọn gàng vào thời điểm đó và những tác động của nó hoàn toàn không được suy nghĩ thấu đáo. Cùng một lý do Date(int,int,int)tồn tại.
chrylis -cautilyoptimistic-

Câu trả lời:


225

Các loại tiêm

Có ba tùy chọn về cách có thể đưa các phụ thuộc vào bean:

  1. Thông qua một nhà xây dựng
  2. Thông qua setters hoặc các phương pháp khác
  3. Thông qua phản ánh, trực tiếp vào các lĩnh vực

Bạn đang sử dụng tùy chọn 3. Đó là những gì đang xảy ra khi bạn sử dụng @Autowiredtrực tiếp trên sân của mình.


Hướng dẫn tiêm

Hướng dẫn chung, được Spring khuyến nghị (xem các phần về DI dựa trên bộ xây dựng hoặc DI dựa trên bộ cài ) như sau:

  • Đối với các phụ thuộc bắt buộc hoặc khi nhắm đến tính bất biến, hãy sử dụng hàm tạo chèn
  • Đối với các phụ thuộc tùy chọn hoặc có thể thay đổi, hãy sử dụng bộ định tuyến tiêm
  • Tránh tiêm tại hiện trường trong hầu hết các trường hợp

Hạn chế tiêm trường

Các lý do tại sao tiêm ngoài hiện trường được chú ý như sau:

  • Bạn không thể tạo các đối tượng bất biến, như bạn có thể làm với phương thức chèn vào hàm tạo
  • Các lớp của bạn có khớp nối chặt chẽ với vùng chứa DI của bạn và không thể được sử dụng bên ngoài nó
  • Các lớp của bạn không thể được khởi tạo (ví dụ: trong các bài kiểm tra đơn vị) mà không có phản ánh. Bạn cần vùng chứa DI để khởi tạo chúng, điều này làm cho các thử nghiệm của bạn giống các thử nghiệm tích hợp hơn
  • Các phụ thuộc thực sự của bạn bị ẩn từ bên ngoài và không được phản ánh trong giao diện của bạn (hàm tạo hoặc phương thức)
  • Nó thực sự dễ dàng để có như mười phụ thuộc. Nếu bạn đang sử dụng hàm tạo chèn, bạn sẽ có một hàm tạo với mười đối số, điều này sẽ báo hiệu rằng có điều gì đó khó hiểu. Nhưng bạn có thể thêm các trường được chèn bằng cách sử dụng trường được tiêm vô thời hạn. Có quá nhiều phụ thuộc là một dấu hiệu đỏ mà lớp thường làm nhiều hơn một việc và nó có thể vi phạm Nguyên tắc Trách nhiệm Đơn lẻ.

Phần kết luận

Tùy thuộc vào nhu cầu của bạn, bạn chủ yếu nên sử dụng phương thức tiêm hàm tạo hoặc một số kết hợp giữa phương thức khởi tạo và tiêm bộ định tuyến. Tiêm thực địa có nhiều hạn chế và cần tránh. Ưu điểm duy nhất của tiêm trường là nó thuận tiện hơn để viết, điều này không vượt trội hơn tất cả các khuyết điểm.


đọc thêm

Tôi đã viết một bài báo trên blog về lý do tại sao tiêm trường thường không được khuyến khích: Tiêm phụ thuộc trường được coi là có hại .


12
Nói chung là ý kiến ​​không hay và không hay khi nói với thế giới "nên tránh tiêm thuốc". Chỉ ra ưu và khuyết điểm và để người khác tự quyết định;) Nhiều người có kinh nghiệm và cách nhìn nhận sự việc khác.
ăn kiêng

6
Đó có thể là trường hợp ở đây, nhưng có những trường hợp khác mà cộng đồng đã đi đến một sự đồng thuận chung để ngăn cản điều gì đó. Lấy ví dụ, Ký hiệu Hungary.
Jannik

Bạn đưa ra một số điểm tốt như khả năng kiểm tra và khả năng hiển thị phụ thuộc nhưng tôi không đồng ý với tất cả. Constructor tiêm không có nhược điểm? Bạn có thể mong muốn có 5 hoặc 6 trường để đưa vào lớp thực hiện các thành phần thực của cuộc gọi. Tôi cũng không đồng ý với bạn về tính bất biến. Việc có các trường cuối cùng là không bắt buộc để có một lớp bất biến. Nó là thích hợp hơn. Đó là rất khác nhau.
davidxxx

Tôi nghĩ rằng bạn có nghĩa là "Đối với phụ thuộc bắt buộc hoặc khi nhắm đến tính bất biến "
Alex Terreaux

1
Tôi đã đề cập đến liên kết ở đầu câu trả lời mà liên kết đến các tài liệu xuân
Vojtech Ruzicka

47

Đây là một trong những cuộc thảo luận không bao giờ kết thúc trong phát triển phần mềm, nhưng những người có ảnh hưởng lớn trong ngành ngày càng có nhiều ý kiến ​​hơn về chủ đề này và bắt đầu đề xuất phương thức chèn hàm tạo là lựa chọn tốt hơn.

Tiêm xây dựng

Ưu điểm:

  • Khả năng kiểm tra tốt hơn . Bạn không cần bất kỳ thư viện chế nhạo nào hoặc bối cảnh Spring trong các bài kiểm tra đơn vị. Bạn có thể tạo một đối tượng mà bạn muốn kiểm tra với từ khóa mới . Các bài kiểm tra như vậy luôn nhanh hơn vì chúng không dựa vào cơ chế phản xạ. ( Câu hỏi này được hỏi sau đó 30 phút. Nếu tác giả đã sử dụng hàm khởi tạo thì nó sẽ không xuất hiện).
  • Tính bất biến . Khi các phụ thuộc được thiết lập, chúng không thể thay đổi được.
  • Mã an toàn hơn . Sau khi thực thi một phương thức khởi tạo, đối tượng của bạn đã sẵn sàng để sử dụng vì bạn có thể xác thực bất kỳ thứ gì được truyền dưới dạng tham số. Đối tượng có thể sẵn sàng hoặc không, không có trạng thái ở giữa. Với tiêm trường bạn thực hiện một bước trung gian khi đối tượng dễ vỡ.
  • Biểu thức rõ ràng hơn của các phụ thuộc bắt buộc . Vấn đề này là không rõ ràng.
  • Làm cho các nhà phát triển suy nghĩ về thiết kế . dit đã viết về một phương thức khởi tạo với 8 tham số, đây thực sự là dấu hiệu của một thiết kế tồi và phản mẫu đối tượng God . Không quan trọng cho dù một lớp có 8 phụ thuộc trong phương thức khởi tạo của nó hoặc trong các trường, nó luôn luôn sai. Mọi người miễn cưỡng thêm nhiều phụ thuộc vào một hàm tạo hơn là thông qua các trường. Nó hoạt động như một tín hiệu cho não của bạn rằng bạn nên dừng lại một lúc và suy nghĩ về cấu trúc mã của bạn.

Nhược điểm:

  • Nhiều mã hơn (nhưng IDE hiện đại làm giảm bớt nỗi đau).

Về cơ bản, tiêm trường ngược lại.


1
Khả năng kiểm tra, vâng, Thật là một cơn ác mộng đối với tôi khi chế nhạo những hạt đậu đã được tiêm trên cánh đồng. Một lần, tôi đã sử dụng tiêm contsructor, tôi không cần phải làm bất cứ nhạo báng không cần thiết
kenobiwan

25

Vấn đề của hương vị. Nó là sự quyết định của bạn.

Nhưng tôi có thể giải thích, tại sao tôi không bao giờ sử dụng hàm tạo chèn .

  1. Tôi không muốn thực hiện một constructor cho tất cả của tôi @Service, @Repository@Controllerđậu. Ý tôi là, có khoảng 40-50 hạt đậu hoặc hơn. Mỗi khi tôi thêm một trường mới, tôi sẽ phải mở rộng hàm tạo. Không, tôi không muốn và tôi không cần phải làm thế.

  2. Điều gì sẽ xảy ra nếu Bean (Dịch vụ hoặc Bộ điều khiển) của bạn yêu cầu tiêm nhiều loại đậu khác? Một hàm tạo với 4 tham số trở lên là rất xấu.

  3. Nếu tôi đang sử dụng CDI, hàm tạo không liên quan đến tôi.


CHỈNH SỬA # 1 : Vojtech Ruzicka đã nói:

lớp có quá nhiều phụ thuộc và có thể đang vi phạm nguyên tắc trách nhiệm duy nhất và cần được cấu trúc lại

Đúng. Lý thuyết và thực tế. Đây là ví dụ vi: DashboardControlleránh xạ tới một đường dẫn *:8080/dashboard.

My DashboardControllerthu thập rất nhiều thông tin từ các dịch vụ khác để hiển thị chúng trong trang tổng quan / trang tổng quan hệ thống. Tôi cần bộ điều khiển duy nhất này. Vì vậy, tôi chỉ phải bảo mật một đường dẫn này (xác thực cơ bản hoặc bộ lọc vai trò người dùng).

CHỈNH SỬA # 2 : Vì mọi người đều tập trung vào 8 tham số trong hàm tạo ... Đây là một ví dụ trong thế giới thực - mã kế thừa của khách hàng. Tôi đã thay đổi điều đó. Lập luận tương tự áp dụng cho tôi cho 4+ tham số.

Đó là tất cả về việc tiêm mã, không phải xây dựng phiên bản.


34
Hàm tạo rất xấu với 8 phụ thuộc thực sự rất tuyệt vời vì nó là một lá cờ đỏ rằng có gì đó không ổn, lớp có quá nhiều phụ thuộc và có thể đang vi phạm nguyên tắc trách nhiệm duy nhất và cần được cấu trúc lại. Nó thực sự là một điều tốt.
Vojtech Ruzicka

6
@VojtechRuzicka chắc chắn nó không đẹp nhưng đôi khi bạn không thể tránh được.
ăn kiêng

4
Tôi muốn nói một quy tắc ngón tay cái của 3, chứ đừng nói đến 40-50, các phụ thuộc cho bất kỳ lớp nào sẽ là một dấu hiệu cho thấy bạn cần phải cấu trúc lại. Không có chuyện một lớp với 40 phụ thuộc lại dính vào một hiệu trưởng chịu trách nhiệm duy nhất hoặc hiệu trưởng đóng / mở.
Amin J

4
@AminJ Quy tắc rất tuyệt, nhưng thực tế thì khác. Công ty tôi đang làm việc đã hơn 20 năm và chúng tôi có rất nhiều mã kế thừa. Tái cấu trúc là một ý tưởng hay, nhưng nó sẽ tốn kém tiền bạc. Ngoài ra tôi không biết tại sao đang nói đến nó nhưng tôi đã không bình 40-50 phụ thuộc, ý tôi là 40-50 đậu, components, modules ...
ăn kiêng

7
@dit, tình huống của bạn rõ ràng là một trong đó nợ kỹ thuật đang khiến bạn phải đưa ra các lựa chọn phụ tối ưu. Bằng cách nói của riêng bạn, bạn đang ở trong tình huống mà việc ra quyết định của bạn bị ảnh hưởng đáng kể bởi mã kế thừa hơn 20 năm tuổi. Khi bắt đầu trong một dự án mới, bạn vẫn khuyên bạn nên tiêm hiện trường, chèn ép hàm xây dựng chứ? Có lẽ bạn nên ghi trước câu trả lời của mình để chỉ ra trường hợp nào bạn sẽ chọn tiêm tại hiện trường.
Umar Farooq Khawaja

0

Thêm một nhận xét - Vojtech Ruzicka nói rằng Spring tiêm đậu theo ba cách như vậy (câu trả lời có số điểm lớn nhất):

  1. Thông qua một nhà xây dựng
  2. Thông qua setters hoặc các phương pháp khác
  3. Thông qua phản ánh, trực tiếp vào các lĩnh vực

Câu trả lời này là SAI - vì MỌI LOẠI THUỐC TIÊM XUÂN ĐỀU SỬ DỤNG PHẢN XẠ! Sử dụng IDE, đặt breakpoint trên setter / constructor và kiểm tra.

Đây có thể là vấn đề về khẩu vị nhưng cũng có thể là vấn đề của TRƯỜNG HỢP. @dieter đã cung cấp một trường hợp tuyệt vời khi tiêm trường tốt hơn. Nếu Bạn đang sử dụng chèn trường trong các bài kiểm tra tích hợp đang thiết lập ngữ cảnh Spring - đối số với khả năng kiểm tra của lớp cũng không hợp lệ - trừ khi Bạn muốn viết sau các bài kiểm tra cho các bài kiểm tra tích hợp của Bạn;)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.