Gọi một phương thức được chú thích @Bean trong cấu hình Spring java


100

Tôi tò mò về cách Spring injection xử lý các phương thức gọi với @Beanchú thích. Nếu tôi đặt một @Beanchú thích trên một phương thức và trả về một thể hiện, tôi hiểu rằng điều đó nói với spring tạo một bean bằng cách gọi phương thức và nhận thể hiện trả về. Tuy nhiên, đôi khi hạt đậu đó phải được sử dụng để nối các hạt đậu khác hoặc thiết lập mã khác. Cách thông thường được thực hiện là gọi @Beanphương thức chú thích để lấy một thể hiện. Câu hỏi của tôi là, tại sao điều này không gây ra nhiều trường hợp đậu nổi xung quanh?

Ví dụ, hãy xem đoạn mã dưới đây (lấy từ một câu hỏi khác). Các entryPoint()phương pháp được chú thích với @Bean, vì vậy tôi sẽ tưởng tượng mùa xuân sẽ tạo ra một thể hiện mới của BasicAuthenticationEntryPointnhư một hạt đậu. Sau đó, chúng tôi gọi entryPoint()lại trong khối cấu hình, nhưng có vẻ như entryPoint()trả về cá thể bean và không được gọi nhiều lần (tôi đã thử ghi nhật ký và chỉ nhận được một mục nhập nhật ký). Có khả năng chúng ta có thể gọi entryPoint()nhiều lần trong các phần khác của cấu hình và chúng ta sẽ luôn nhận được cùng một trường hợp. Sự hiểu biết của tôi về điều này có đúng không? Liệu mùa xuân có thực hiện một số viết lại kỳ diệu của các phương pháp được chú thích bằng@Bean không?

@Bean
public BasicAuthenticationEntryPoint entryPoint() {
    BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
    basicAuthEntryPoint.setRealmName("My Realm");
    return basicAuthEntryPoint;
}

@Override
protected void configure(HttpSecurity http) throws Exception {

    http
        .exceptionHandling()
            .authenticationEntryPoint(entryPoint())
            .and()
        .authorizeUrls()
            .anyRequest().authenticated()
            .and()
        .httpBasic();       
}

Câu trả lời:


133

Vâng, mùa xuân làm một số điều kỳ diệu . Kiểm tra tài liệu mùa xuân :

Đây là nơi điều kỳ diệu đến: Tất cả @Configurationcác lớp đều được phân lớp tại thời điểm khởi động với CGLIB . Trong lớp con, phương thức con trước tiên sẽ kiểm tra vùng chứa để tìm bất kỳ bean nào được lưu trong bộ nhớ cache (phạm vi) trước khi nó gọi phương thức cha và tạo một thể hiện mới.

Điều này có nghĩa là các cuộc gọi đến @Beancác phương thức được ủy quyền thông qua CGLIB và do đó, phiên bản bean được lưu trong bộ nhớ cache được trả về (một phiên bản mới không được tạo).

Phạm vi mặc định của @Beans là SINGLETON, nếu bạn chỉ định một phạm vi khác, chẳng hạn như PROTOTYPElời gọi sẽ được chuyển đến phương thức ban đầu.

Xin lưu ý rằng điều này không hợp lệ cho các phương thức tĩnh . Theo tài liệu mùa xuân:

Các lệnh gọi đến các @Beanphương thức tĩnh không bao giờ bị vùng chứa chặn, ngay cả trong @Configurationcác lớp (như được mô tả trước đó trong phần này), do các giới hạn kỹ thuật: Lớp con CGLIB chỉ có thể ghi đè các phương thức không tĩnh. Do đó, một lời gọi trực tiếp đến một @Beanphương thức khác có ngữ nghĩa Java tiêu chuẩn, dẫn đến một thể hiện độc lập được trả về ngay từ chính phương thức gốc.


Có thể ghi đè đậu được tạo theo cách này không? Ví dụ, tôi có một lớp được định nghĩa bằng Spring gọi trực tiếp một phương thức tạo bean. Điều tôi muốn không phải là bean được tạo bởi phương thức đó được sử dụng, mà là một bean do chính tôi tạo ra (bằng cách chú thích nó bằng @Bean@Primary).
Fons

4
Nhưng tôi cũng nhớ lại rằng proxy (jdk hoặc CGLIB, tùy theo cái nào) không thể hoạt động trong tự gọi, vậy @Configuration xác định sự phụ thuộc giữa các hạt như thế nào? Nó sử dụng một cách chính xác tự gọi
Nowhy

3
@Nowhy CGLib allows us to create proxy classes at runtime by creating sub class of specified class using Byte code generation. CGLib proxies are used in the case where Proxy is to be created for those class which does not have any interfaces or have methods which are not declared in the implementing interface. Trong trường hợp này, CGLIB tạo lớp con của lớp @Configuration và ghi đè các phương thức của nó (bao gồm cả phương thức @Bean). Vì vậy, khi chúng tôi gọi phương thức @Bean từ một phương thức khác, chúng tôi thực sự gọi phiên bản ghi đè của nó (nhờ liên kết động java).
Flame239,

Vì vậy, liệu AOP trong selfInvocation @Componentsẽ hoạt động nếu tôi sử dụng CHLIB để tạo proxy thay vì java Poxy?
Antoniossss
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.