@ Nguồn so với @Autowired


380

Mà chú thích, @Resource ( jsr250 ) hoặc @Autowired (Spring-cụ thể) Tôi nên sử dụng trong DI?

Tôi đã sử dụng thành công cả trong quá khứ, @Resource(name="blah")@Autowired @Qualifier("blah")

Bản năng của tôi là gắn bó với @Resourcethẻ vì nó đã được người jsr phê chuẩn.
Bất cứ ai cũng có suy nghĩ mạnh mẽ về điều này?


FYI - Tôi đã xóa 'cập nhật', nó nên được hỏi như một câu hỏi riêng biệt. Theo nhận xét bị từ chối này, "Bản chỉnh sửa này lệch khỏi mục đích ban đầu của bài đăng. Ngay cả các chỉnh sửa phải thực hiện thay đổi mạnh mẽ cũng nên cố gắng duy trì các mục tiêu của chủ sở hữu bài đăng"
mlo55

Câu trả lời:


194

Vào mùa xuân trước 3.0, không vấn đề gì.

Vào mùa xuân 3.0, có hỗ trợ cho chú thích tiêu chuẩn ( JSR-330 ) @javax.inject.Inject- sử dụng nó, với sự kết hợp của @Qualifier. Lưu ý rằng mùa xuân bây giờ cũng hỗ trợ @javax.inject.Qualifierchú thích meta:

@Qualifier
@Retention(RUNTIME)
public @interface YourQualifier {}

Vì vậy, bạn có thể có

<bean class="com.pkg.SomeBean">
   <qualifier type="YourQualifier"/>
</bean>

hoặc là

@YourQualifier
@Component
public class SomeBean implements Foo { .. }

Và sau đó:

@Inject @YourQualifier private Foo foo;

Điều này làm cho việc sử dụng tên String ít hơn, có thể sai chính tả và khó bảo trì hơn.


Đối với câu hỏi ban đầu: cả hai, mà không chỉ định bất kỳ thuộc tính nào của chú thích, thực hiện tiêm theo loại. Sự khác biệt là:

  • @Resource cho phép bạn chỉ định tên của đậu được tiêm
  • @Autowired cho phép bạn đánh dấu nó là không bắt buộc.

Điều này có thể giống như một câu hỏi ngớ ngẩn, nhưng khi bạn sử dụng kiểu tiêm này, bạn có cần một trình thiết lập công khai cho foohoặc một hàm tạo trong SomeBeanmột Fooparam không?
Snekse

@Snekse - Có câu trả lời của tôi: stackoverflow.com/questions35336674/ trên
Snekse

không Bạn không cần bất kỳ thứ gì trong số đó. Chỉ là lĩnh vực. (Mùa xuân cư trú thông qua sự phản chiếu)
Bozho

@Bozho Câu trả lời này thực sự không cho thấy sự khác biệt giữa @Resource@Autowired, câu trả lời thực tế là câu trả lời được đăng bởi @Ichthyo, tôi nghĩ rằng câu trả lời này phải được cập nhật.
Boris Treukhov

1
Đúng. Trong thực tế, đôi khi tôi trả lời các câu hỏi bằng cách cung cấp một giải pháp thay thế tốt hơn cho phương pháp này. Nhưng tôi đã bao gồm câu trả lời cho câu hỏi ban đầu bên dưới, để hoàn chỉnh
Bozho

509

Cả @Autowired(hoặc @Inject) và @Resourcelàm việc tốt như nhau. Nhưng có một sự khác biệt về khái niệm hoặc sự khác biệt về ý nghĩa

  • @Resourcecó nghĩa là cho tôi một tài nguyên được biết đến theo tên . Tên được trích xuất từ ​​tên của setter chú thích hoặc trường hoặc nó được lấy từ Parameter name.
  • @Injecthoặc @Autowiredcố gắng nối dây trong một thành phần khác phù hợp theo loại .

Vì vậy, về cơ bản đây là hai khái niệm khá khác biệt. Thật không may, Spring-Thực hiện @Resourcecó một dự phòng tích hợp, sẽ khởi động khi phân giải tên không thành công. Trong trường hợp này, nó rơi trở lại @Autowiredđộ phân giải -kind theo loại. Mặc dù dự phòng này là thuận tiện, IMHO nó gây ra nhiều nhầm lẫn, bởi vì mọi người không nhận thức được sự khác biệt về khái niệm và có xu hướng sử dụng @Resourcecho tự động dựa trên loại.


81
Vâng, đây là những gì nên là một câu trả lời được chấp nhận. Ví dụ: nếu bạn có một @Resourcetrường có chú thích và tên trường khớp với id của một bean trong container thì Spring sẽ ném org.springframework.beans.factory.BeanNotOfRequiredTypeExceptionnếu các loại của chúng khác nhau - điều này là do các bean được khớp đầu tiên theo tên trong @Resourcechú thích, không phải theo loại. Nhưng nếu tên của tài sản không khớp với tên của hạt đậu, thì Spring sẽ nối chúng theo loại.
Boris Treukhov

Bạn có thể tham khảo bài đăng khác cho biết sự khác biệt giữa hai bài này khi bạn cố gắng sử dụng một MAP đơn giản. stackoverflow.com/questions/13913752/ cường
Anver Sadhat

4
+1 để thực sự trả lời câu hỏi thay vì chỉ đề xuất một "cách thực hành tốt nhất" hoàn toàn khác như câu trả lời được chấp nhận. Tôi cũng tìm thấy bài đăng trên blog này, trong đó hiển thị kết quả của một số tình huống phổ biến với cả ba kiểu chú thích, hữu ích: blog.sourceallies.com/2011/08/ trên
Jules

1
Đối với người đọc, vui lòng tìm một bản tóm tắt của bài viết được chỉ ra bởi @Jules tại đây: stackoverflow.com/a/23887596/363573
Stephan

3
Một hàm ý của điều này: Khi bạn muốn tiêm bean Map / List, @Autowirekhông thể và sẽ không hoạt động. Bạn sẽ phải sử dụng @Resourcetrong trường hợp đó.
Ricardo van den Broek

76

Sự khác biệt chính là, @Autowiredlà một chú thích mùa xuân. Trong khi đó, @Resourceđược chỉ định bởi JSR-250, như bạn đã chỉ ra cho mình. Vì vậy, cái sau là một phần của Java trong khi cái trước là Spring cụ thể.

Do đó, bạn đã đúng khi đề xuất rằng, theo một nghĩa nào đó. Tôi thấy mọi người sử dụng @Autowiredvới @Qualifiervì nó mạnh hơn. Chuyển từ một số khuôn khổ sang một số khác được coi là rất khó, nếu không phải là huyền thoại, đặc biệt là trong trường hợp của Mùa xuân.


7
+1, vì @Autowiredvới @Qualifierthực sự mạnh hơn so với tiêu chuẩn JSR @Resourcechú thích (nghĩ về phụ thuộc tùy chọn ví dụ với @Autowired(required=false). Bạn không thể làm điều đó với @Resource)
Stefan Haberl

70

Tôi muốn nhấn mạnh một nhận xét từ @Jules về câu trả lời này cho câu hỏi này. Nhận xét mang đến một liên kết hữu ích: Spring tiêm với @Resource, @Autowired và @Inject . Tôi khuyến khích bạn đọc nó hoàn toàn, tuy nhiên đây là một bản tóm tắt nhanh về tính hữu dụng của nó:

Làm thế nào các chú thích chọn thực hiện đúng?

@Autowired@Inject

  1. Các trận đấu theo loại
  2. Giới hạn bởi Vòng loại
  3. Trận đấu theo tên

@Resource

  1. Trận đấu theo tên
  2. Các trận đấu theo loại
  3. Giới hạn theo Vòng loại (bỏ qua nếu tìm thấy kết quả trùng khớp theo tên)

Tôi nên sử dụng chú thích nào (hoặc kết hợp) để tiêm đậu?

  1. Đặt tên rõ ràng cho thành phần của bạn [@Component ("beanName")]

  2. Sử dụng @Resourcevới namethuộc tính [@Resource (name = "beanName")]

Tại sao tôi không nên sử dụng @Qualifier?

Tránh @Qualifierchú thích trừ khi bạn muốn tạo một danh sách các loại đậu tương tự. Ví dụ, bạn có thể muốn đánh dấu một bộ quy tắc bằng một @Qualifierchú thích cụ thể . Cách tiếp cận này làm cho nó đơn giản để đưa một nhóm các lớp quy tắc vào một danh sách có thể được sử dụng để xử lý dữ liệu.

Có tiêm đậu làm chậm chương trình của tôi?

Quét các gói cụ thể cho các thành phần [context:component-scan base-package="com.sourceallies.person"]. Mặc dù điều này sẽ dẫn đến nhiều component-scancấu hình hơn nhưng nó sẽ giảm khả năng bạn sẽ thêm các thành phần không cần thiết vào bối cảnh Mùa xuân của mình.


Tham khảo: Spring Tiêm với @Resource, @Autowired và @Inject


39

Đây là những gì tôi nhận được từ Tài liệu tham khảo Spring 3.0.x : -

tiền boa

Nếu bạn có ý định thể hiện tiêm theo hướng chú thích theo tên, chủ yếu không sử dụng @Autowired, ngay cả khi về mặt kỹ thuật có thể đề cập đến tên bean thông qua các giá trị @Qualifier. Thay vào đó, hãy sử dụng chú thích JSR-250 @Resource, được xác định theo ngữ nghĩa để xác định một thành phần mục tiêu cụ thể bằng tên duy nhất của nó, với kiểu khai báo là không liên quan cho quy trình khớp.

Do hậu quả cụ thể của sự khác biệt về ngữ nghĩa này, các loại đậu được xác định là loại bộ sưu tập hoặc loại bản đồ không thể được tiêm thông qua @Autowired, vì loại khớp không phù hợp với chúng. Sử dụng @Resource cho các loại đậu như vậy, tham khảo bộ sưu tập cụ thể hoặc bản đồ đậu theo tên duy nhất.

@Autowired áp dụng cho các trường, hàm tạo và phương thức đa đối số, cho phép thu hẹp thông qua các chú thích vòng loại ở cấp tham số. Ngược lại, @Resource chỉ được hỗ trợ cho các trường và các phương thức setter thuộc tính bean với một đối số duy nhất. Kết quả là, gắn bó với vòng loại nếu mục tiêu tiêm của bạn là một hàm tạo hoặc một phương thức đa đối số.


Đối với phiên bản hiện tại, hãy xem docs.spring.io/spring/docs/civerse/spring-framework-reference/ ((mẹo đã được cập nhật)
Lu55

28

@Autowired + @Qualifier sẽ chỉ hoạt động với spring DI, nếu bạn muốn sử dụng một số DI khác trong tương lai @Resource là lựa chọn tốt.

sự khác biệt khác mà tôi thấy rất có ý nghĩa là @Qualifier không hỗ trợ hệ thống dây động, vì @Qualifier không hỗ trợ giữ chỗ, trong khi @Resource làm điều đó rất tốt.

Ví dụ: nếu bạn có một giao diện với nhiều triển khai như thế này

interface parent {

}
@Service("actualService")
class ActualService implements parent{

}
@Service("stubbedService")
class SubbedService implements parent{

}

với @Autowired & @Qualifier, bạn cần đặt triển khai con cụ thể như

@Autowired
@Qualifier("actualService") or 
@Qualifier("stubbedService") 
Parent object;

không cung cấp trình giữ chỗ trong khi với @Resource, bạn có thể đặt trình giữ chỗ và sử dụng tệp thuộc tính để thực hiện việc triển khai con cụ thể như

@Resource(name="${service.name}")
Parent object;  

nơi service.name được đặt trong tệp thuộc tính là

#service.name=actualService
 service.name=stubbedService

Mong rằng sẽ giúp được ai đó :)


16

Cả hai đều tốt như nhau. Ưu điểm của việc sử dụng Tài nguyên là trong tương lai nếu bạn muốn một khung DI khác ngoài mùa xuân, việc thay đổi mã của bạn sẽ đơn giản hơn nhiều. Sử dụng Autowired mã của bạn được kết hợp chặt chẽ với lò xo DI.


17
Sẽ không bao giờ xảy ra. Và ngay cả khi nó đã làm - thực hiện tìm / thay thế tên chú thích sẽ là vấn đề ít nhất của bạn.
Daniel Alexiuc

13

Khi bạn phân tích phê bình từ các lớp cơ sở của hai chú thích này. Bạn sẽ nhận ra những khác biệt sau.

@Autowiredsử dụng AutowiredAnnotationBeanPostProcessor để tiêm phụ thuộc.
@Resourcesử dụng CommonAnnotationBeanPostProcessorđể tiêm phụ thuộc.

Mặc dù họ sử dụng các lớp xử lý bài khác nhau, tất cả chúng đều hoạt động gần như giống hệt nhau. Sự khác biệt cực kỳ nằm trong đường dẫn thực thi của chúng, mà tôi đã nhấn mạnh dưới đây.

@Autowired / @Inject

1.Matches theo Loại
2.Restrict by Qualifier
3.Matches by Name

@Resource

1.Matches by Name
2.Matches by Type
3.Restrict by Qualifier (bỏ qua nếu tìm thấy kết quả trùng khớp theo tên)


6

Với việc @Resourcebạn có thể tự thực hiện bean, có thể cần thiết để chạy tất cả logic bổ sung được thêm bởi các bộ xử lý bài bean như các công cụ liên quan đến giao dịch hoặc bảo mật.

Với Spring 4.3+ @Autowiredcũng có khả năng làm điều này.


2

@Resourcethường được sử dụng bởi các đối tượng cấp cao, được xác định thông qua JNDI. @Autowiredhoặc @Injectsẽ được sử dụng bởi các loại đậu phổ biến hơn.

Theo tôi biết, nó không phải là một đặc điểm kỹ thuật, thậm chí không phải là một quy ước. Đó là cách logic tiêu chuẩn hơn sẽ sử dụng các chú thích này.


0

Như một lưu ý ở đây: SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContextSpringBeanAutowiringSupport.processInjectionBasedOnServletContext KHÔNG làm việc với @Resource chú thích. Vì vậy, có sự khác biệt.

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.