Làm thế nào để tiêm phụ thuộc vào một đối tượng tự khởi tạo trong Spring?


128

Hãy nói rằng chúng tôi có một lớp học:

public class MyClass {
    @Autowired private AnotherBean anotherBean;
}

Sau đó, chúng tôi đã tạo một đối tượng của lớp này (hoặc một số khung công tác khác đã tạo ra thể hiện của lớp này).

MyClass obj = new MyClass();

Có thể vẫn còn tiêm phụ thuộc? Cái gì đó như:

applicationContext.injectDependencies(obj);

(Tôi nghĩ Google Guice có cái gì đó như thế này)

Câu trả lời:


194

Bạn có thể làm điều này bằng cách sử dụng autowireBean()phương pháp AutowireCapableBeanFactory. Bạn truyền cho nó một đối tượng tùy ý và Spring sẽ coi nó giống như một thứ gì đó do chính nó tạo ra và sẽ áp dụng các bit và phần tự động khác nhau.

Để nắm giữ AutowireCapableBeanFactory, chỉ cần tự động rằng:

private @Autowired AutowireCapableBeanFactory beanFactory;

public void doStuff() {
   MyBean obj = new MyBean();
   beanFactory.autowireBean(obj);
   // obj will now have its dependencies autowired.
}

Câu trả lời hay (+1). Ngoài ra còn có một phương pháp thứ hai nơi bạn có thể ảnh hưởng đến cách thức tự động xảy ra: static.springsource.org/spring/docs/3.0.x/javadoc-api/org/ọ
Sean Patrick Floyd

Nhưng chuyện gì sẽ xảy ra nếu tôi có hai đối tượng, và lần đầu tiên tự động thứ hai. Làm thế nào autowire nhà máy đậu xử lý các phụ thuộc trong trường hợp?
Vadim Kirilchuk

3
Đây thực sự là một mô hình xấu. Nếu đây là cách bạn thực sự sử dụng MyBean thì tại sao không chỉ có hàm tạo với AnotherBean làm tham số. Một cái gì đó như: codeprivate @Autowired AnotherBean bean; công khai void doStuff () {MyBean obj = new MyBean (bean); } code. Có vẻ giống như với tất cả các chú thích này, mọi người thực sự bối rối và chỉ không sử dụng mẫu cơ bản có trong java SDK kể từ ngày 1. :(
Denis

3
Tôi đồng ý - Spring đã định nghĩa lại toàn bộ ngôn ngữ. Bây giờ chúng tôi sử dụng các giao diện như các lớp cụ thể, các phương thức như các thể hiện của lớp và tất cả các cách thức phức tạp và mã hóa các phương thức nặng để thực hiện những gì bạn đã từng làm với một thiết kế mới và hợp lý.
Rodney P. Barbati

@Denis nếu MyBean có các phụ thuộc mà lớp thực tế không cần, bạn đang đăng ký các phụ thuộc không thực sự tồn tại, chỉ để ví dụ một lớp, vì vậy thực sự không có sự khác biệt.
Dalton

17

Bạn cũng có thể đánh dấu MyClass của mình bằng chú thích @Configurable:

@Configurable
public class MyClass {
   @Autowired private AnotherClass instance
}

Sau đó, tại thời điểm tạo ra nó sẽ tự động tiêm phụ thuộc của nó. Bạn cũng nên có <context:spring-configured/>trong bối cảnh ứng dụng của bạn xml.


2
Galz666, phương pháp của bạn trông sạch sẽ hơn nhiều cho những gì tôi muốn làm. Tuy nhiên tôi không thể làm cho nó hoạt động. Tôi không có tệp xml và đang sử dụng hoàn toàn cấu hình Java. Có tương đương với <context:spring-configured/>?
masstroy

1
Đây là giải pháp sạch, nhưng đòi hỏi nỗ lực hơn một chút: Bạn nên sử dụng dệt thời gian tải như iimuhin hiển thị ở trên hoặc thêm trình biên dịch AspectJ vào dự án. Thời gian tải như tên đề xuất sẽ gây thêm chi phí tại thời gian chạy.
jsosnowski

4

Chỉ có cùng một nhu cầu và trong trường hợp của tôi, đó đã là logic bên trong lớp java không thể quản lý Spring có quyền truy cập ApplicationContext. Lấy cảm hứng từ giàn giáo. Giải quyết bằng:

AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
factory.autowireBean(manuallyCreatedInstance);

3

Tôi muốn chia sẻ giải pháp của mình theo @Configurablecách tiếp cận như brieflyđược đề cập trong câu trả lời @ glaz666 bởi vì

  • Câu trả lời của @skaffman đã gần 10 tuổi và điều đó không có nghĩa là không đủ tốt hoặc không hoạt động
  • Câu trả lời của @ glaz666 rất ngắn gọn và không thực sự giúp tôi giải quyết vấn đề của mình, nhưng, đã chỉ cho tôi đi đúng hướng

Thiết lập của tôi

  1. Khởi động mùa xuân 2.0.3 với Spring Neo4j & Aop starts (dù sao cũng không liên quan)
  2. Khởi tạo một bean khi Spring Bootsẵn sàng sử dụng @Configurablephương pháp (sử dụngApplicationRunner )
  3. Lớp & Nhật thực

Các bước

Tôi cần phải làm theo các bước dưới đây để làm cho nó hoạt động

  1. Việc @Configurable(preConstruction = true, autowire = Autowire.BY_TYPE, dependencyCheck = false)được đặt lên trên Beanđó là được khởi tạo thủ công. Trong trường hợp của tôi, Beanđó là được khởi tạo thủ công có@Autowired các dịch vụ do đó, các đạo cụ cho chú thích ở trên.
  2. Chú thích chính của Spring Boot XXXApplicaiton.java(hoặc tệp được chú thích @SpringBootApplication) với @EnableSpringConfigured@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
  3. Thêm các phụ thuộc trong tệp xây dựng của bạn (ví dụ: build.gradle hoặc pom.xml tùy thuộc vào loại bạn sử dụng) compile('org.springframework.boot:spring-boot-starter-aop')compile('org.springframework:spring-aspects:5.0.7.RELEASE')
  4. Mới + lên của bạn Beanđược chú thích với @Configurablebất cứ nơi nào và phụ thuộc của nó sẽ được tự động.

* Liên quan đến điểm số 3 ở trên, tôi biết rằng việc org.springframework.boot:spring-boot-starter-aopkéo quá mức spring-aop(như được hiển thị ở đây là mavencentral ), nhưng trong trường hợp của tôi, Eclipse đã không giải quyết được các @EnableSpringConfiguredchú thích do đó, tại sao tôi lại thêm vào sự spring-aopphụ thuộc một cách rõ ràng vào bộ khởi động. Nếu bạn phải đối mặt với cùng một vấn đề, chỉ cần tuyên bố sự phụ thuộc hoặc tiếp tục phiêu lưu tìm hiểu

  • Có mâu thuẫn phiên bản không
  • Tại sao org.springframework.context.annotation.aspect.* không có sẵn
  • Thiết lập IDE của bạn có đúng không
  • Vân vâ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.