Làm thế nào để gọi một phương thức sau khi khởi tạo đậu hoàn tất?


237

Tôi có một trường hợp sử dụng trong đó tôi cần gọi một phương thức (không tĩnh) trong bean chỉ một lần khi tải ApplicationContext lên. Có ổn không, nếu tôi sử dụng MethodInvokingFactoryBean cho việc này? Hoặc chúng ta có một giải pháp tốt hơn?

Là một lưu ý phụ, tôi sử dụng ConfigContextLoaderListener để tải Bối cảnh ứng dụng trong ứng dụng web. Và muốn, nếu bean 'A' được khởi tạo, chỉ cần gọi phương thứcA () một lần.

Làm thế nào điều này có thể được thực hiện độc đáo?

Câu trả lời:


197

Bạn có thể sử dụng một cái gì đó như:

<beans>
    <bean id="myBean" class="..." init-method="init"/>
</beans>

Điều này sẽ gọi phương thức "init" khi bean được khởi tạo.


15
Tuy nhiên, postConstruct sẽ tốt hơn trong hầu hết các trường hợp, vì chúng tôi không muốn gây rối với khởi tạo đậu mùa xuân.
lwpro2

4
@ lwpro2 Ý bạn là gì khi "không muốn gây rối với khởi tạo đậu mùa xuân" ở đây?
Yngve Sneen Lindal

@Mercer Traieste tôi nên cung cấp gì cho thuộc tính lớp ở đây? Tôi có thể cung cấp cho lớp điều khiển ở đây?
KJEjava48

313

Để mở rộng về đề xuất @PostConstruct trong các câu trả lời khác, theo tôi, đây thực sự là giải pháp tốt nhất.

  • Nó giữ cho mã của bạn được tách rời khỏi API mùa xuân (@PostConstruct có trong javax. *)
  • Nó chú thích rõ ràng phương thức init của bạn như là một cái gì đó cần được gọi để khởi tạo bean
  • Bạn không cần phải nhớ thêm thuộc tính init-method vào định nghĩa bean mùa xuân của mình, spring sẽ tự động gọi phương thức (giả sử bạn đăng ký tùy chọn annotation-config ở một nơi khác trong ngữ cảnh).

9
Cảm ơn, điều này làm việc. Lưu ý nếu bạn muốn sử dụng với Spring, bạn phải bao gồm "<bối cảnh: annotation-config />" để đăng ký bean CommonAnnotationBeanPostProcessor (như đã đề cập ở trên)
khylo

2
Một công cụ phù hợp <context:component-scan>cũng hoạt động và có thể hữu ích để giảm thời gian khởi động nếu bạn có các thư viện không phải là Spring lớn trên đường dẫn lớp.
Donal Fellows

5
JavaDoc cho PostConstruct nói rằng chỉ có một phương thức có thể được chú thích với nó cho mỗi lớp: docs.oracle.com/javaee/5/api/javax/annotation/ trộm
Andrew Swan

@PostConstruct không hoạt động với người quản lý giao dịch, hãy xem: forum.spring.io/forum/spring-projects/data/ trộm
mmm

2
@PostConstruct cũng sẽ không được sử dụng nhiều cho bạn khi bean bạn đang tạo không phải là một lớp của riêng bạn mà là một lớp bên thứ ba
John Rix

102

Có ba cách tiếp cận khác nhau để xem xét, như được mô tả trong tài liệu tham khảo

Sử dụng thuộc tính init-method

Ưu điểm:

  • Không yêu cầu bean để thực hiện một giao diện.

Nhược điểm:

  • Không có dấu hiệu ngay lập tức phương pháp này được yêu cầu sau khi xây dựng để đảm bảo bean được cấu hình chính xác.

Triển khai LaunchizingBean

Ưu điểm:

  • Không cần chỉ định phương thức init hoặc bật xử lý quét / chú thích thành phần.
  • Thích hợp cho các bean được cung cấp cùng với thư viện, nơi chúng tôi không muốn ứng dụng sử dụng thư viện này liên quan đến vòng đời của bean.

Nhược điểm:

  • Xâm lấn hơn phương pháp init.

Sử dụng chú thích vòng đời JSR-250 @PostConstruct

Ưu điểm:

  • Hữu ích khi sử dụng quét thành phần để tự động phát hiện đậu.
  • Làm cho nó rõ ràng rằng một phương pháp cụ thể sẽ được sử dụng để khởi tạo. Ý định gần với mã hơn.

Nhược điểm:

  • Khởi tạo không còn được chỉ định tập trung trong cấu hình.
  • Bạn phải nhớ bật xử lý chú thích (đôi khi có thể bị lãng quên)

4
Tôi nghĩ rằng đó thực sự là một điều tốt để sử dụng @PostConstructchính xác bởi vì nó là một phần của lớp mà nó cần phương thức gọi vào cuối quá trình xử lý khởi tạo.
Donal Fellows

Nếu lớp đó THỰC SỰ cần nó và bạn không thể thực hiện nó trong hàm tạo, thì tôi coi đó là mùi mã.
dùng482745

39

Bạn đã thử thực hiện InitializingBean? Nghe có vẻ chính xác những gì bạn đang theo đuổi.

Nhược điểm là bean của bạn trở nên nhận biết Spring, nhưng trong hầu hết các ứng dụng không quá tệ.


2
Có lý do nào để bạn chọn triển khai giao diện thay vì chỉ định phương thức init trong XML không?
Đánh dấu

4
Đó là một vấn đề của hương vị. Giao diện là một phần của mô hình thành phần Spring và phục vụ mục đích đó và chỉ với mục đích đó trong khi đối với một phương thức có tên tùy chỉnh, có thể không thực sự rõ ràng rằng nó phải được gọi để hoàn thành vòng đời thành phần. Vì vậy, điều này phục vụ truyền thông là chủ yếu. Tất nhiên với nhược điểm của sự phụ thuộc được giới thiệu vào khung công tác Spring. Một cách hay giữa là cách sử dụng @PostConstruct, vì nó có ngữ nghĩa rõ ràng nhưng không giới thiệu sự phụ thuộc ...
Oliver Drotbohm

7
Oliver cho tôi một số lý do thú vị, nhưng thực sự tôi đã quên mất phương thức init :) Một lý do khác là bản thân loại này biết rằng nó cần phải được "kết thúc" sau khi tất cả các thuộc tính đã được đặt - không phải vậy về cơ bản một cái gì đó nên có trong cấu hình.
Jon Skeet

8

Bạn có thể triển khai một BeanPostProcessor tùy chỉnh trong ngữ cảnh ứng dụng của bạn để làm điều đó. Hoặc nếu bạn không phiền khi thực hiện giao diện Spring trong bean của mình, bạn có thể sử dụng giao diện LaunchizingBean hoặc chỉ thị "init-method" (cùng liên kết).


Có ai có chi tiết về cách viết BeanPostProcessor không. Đó là âm thanh chính xác những gì tôi cần. Chúc mừng :)
đỉnh điểm

Tàu xuân với nhiều ví dụ. Chỉ cần nhìn vào API JavaDoc cho BeanPostProcessor và bạn sẽ tìm thấy các liên kết đến nhiều lớp triển khai. Sau đó nhìn vào mã nguồn cho họ.
Rob H

-7

Để rõ hơn bất kỳ sự nhầm lẫn về hai phương pháp, tức là sử dụng

  1. @PostConstruct
  2. init-method="init"

Từ kinh nghiệm cá nhân, tôi nhận ra rằng việc sử dụng (1) chỉ hoạt động trong một thùng chứa servlet, trong khi (2) hoạt động trong mọi môi trường, ngay cả trong các ứng dụng máy tính để bàn. Vì vậy, nếu bạn sẽ sử dụng Spring trong một ứng dụng độc lập, bạn sẽ phải sử dụng (2) để thực hiện "gọi phương thức này sau khi khởi tạo.


4
Về mặt kỹ thuật, @PostConstruct(khi được sử dụng trong ứng dụng dựa trên Spring) được gắn với tuổi thọ của bối cảnh Spring sở hữu. Các bối cảnh như vậy có thể được sử dụng trong tất cả các loại ứng dụng.
Donal Fellows

Đó là hành vi tôi mong đợi nhưng không hiệu quả với tôi.
Ayorinde
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.