Spring Core & Boot
31/41
Bài 31 / 41~12 phútSpring Boot & Auto-configurationLộ trình · chặng 14/21Miễn phí… lượt xem

@ConditionalOn* Family Và Thứ Tự Nạp Bean Autoconfig

Tìm hiểu 12 annotation @ConditionalOn*, cơ chế back-off nhường bean của @ConditionalOnMissingBean và cách sắp xếp thứ tự nạp bằng DAG topological sort.

TL;DR: @ConditionalOn* là tập hợp các bộ lọc điều kiện đảm bảo các lớp cấu hình tự động chỉ đăng ký bean khi thỏa mãn toàn bộ yêu cầu về môi trường runtime. Trong đó, @ConditionalOnMissingBean đóng vai trò trung tâm trong mô hình Back-Off: Spring Boot chỉ tạo bean mặc định khi lập trình viên chưa tự định nghĩa bean cùng loại. Các annotation @AutoConfigureBefore và @AutoConfigureAfter thiết lập đồ thị có hướng (DAG) để sắp xếp thứ tự thẩm định, ngăn ngừa lỗi tranh chấp định nghĩa bean. Khi gặp sự cố nạp bean, Actuator endpoint /actuator/conditions là công cụ chẩn đoán chính xác nhất.

Làm chủ họ annotation này và nguyên lý sắp xếp thứ tự giúp bạn loại bỏ hoàn toàn các lỗi xung đột bean vô hình khi xây dựng hệ thống phức tạp.

1. Vì sao Auto-configuration bắt buộc phải có điều kiện kích hoạt?

Nếu Spring Boot tự động nạp toàn bộ các bean mà không kiểm tra điều kiện, xung đột bean sẽ xảy ra liên tục:

Java
// Gia su khong co dieu kien can thiep
@AutoConfiguration
public class CacheAutoConfiguration {
    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager(); // Luon tao mac dinh
    }
}

Khi dự án của bạn muốn chuyển sang Redis và tự định nghĩa một RedisCacheManager, container sẽ cùng lúc có 2 bean CacheManager, dẫn tới lỗi NoUniqueBeanDefinitionException ngay lúc khởi động. Do đó, mọi bean cấu hình sẵn của Spring Boot đều bắt buộc phải đi kèm điều kiện thẩm định.

2. Họ 12 annotation @ConditionalOn* giải quyết những bài toán nào?

Spring Boot cung cấp sẵn 12 annotation chuyên biệt để truy vấn trạng thái môi trường:

AnnotationCâu hỏi thẩm định môi trườngTrường hợp sử dụng tiêu biểu
@ConditionalOnClassClass chỉ định có mặt trên classpath không?Kích hoạt cấu hình khi người dùng thêm starter
@ConditionalOnMissingClassClass chỉ định vắng mặt trên classpath?Cung cấp phương án thay thế khi thiếu driver
@ConditionalOnBeanBean kiểu chỉ định đã được đăng ký chưa?Tạo bean phụ thuộc vào một bean khác
@ConditionalOnMissingBeanBean kiểu chỉ định chưa hề tồn tại?Tạo bean mặc định nhường quyền cho người dùng
@ConditionalOnPropertyThuộc tính cấu hình có giá trị khớp không?Bật tắt tính năng bằng Feature Flag
@ConditionalOnWebApplicationỨng dụng có đang chạy môi trường Web không?Khai báo các Controller và Servlet Filter

Khi gắn nhiều annotation điều kiện trên cùng một lớp hoặc phương thức, Spring áp dụng quy tắc AND: tất cả điều kiện đều phải thỏa mãn thì bean mới được đăng ký.

3. Cơ chế Back-Off của @ConditionalOnMissingBean vận hành ra sao?

@ConditionalOnMissingBean là nền tảng giúp Spring Boot duy trì tính linh hoạt "Opinionated but not lock-in":

Java
@AutoConfiguration
public class CacheAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean // Chi tao neu nguoi dung CHUA tu khai bao
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager();
    }
}

Khi bạn khai báo một bean CacheManager của riêng mình trong mã nguồn, Spring Boot nhận diện bean đã tồn tại và tự động rút lui.

Đối chiếu hai cách đổi CacheManager sang Redis: cách khai @Bean CacheManager của bạn thì @ConditionalOnMissingBean thấy bean đã có nên nhường đúng bean đó, phần còn lại của autoconfig vẫn chạy gồm binding property, bean phụ và listener trong cùng class; cách exclude cả CacheAutoConfiguration thì cả class bị loại khỏi danh sách ngay từ bước filter nên mất luôn binding property, listener và bean phụ, phải tự khai lại bằng tay

So với việc dùng exclude để loại bỏ cả class cấu hình, cơ chế back-off ưu việt hơn vì nó chỉ ghi đè đúng bean mục tiêu mà vẫn giữ lại toàn bộ các thiết lập phụ trợ (như properties binding và cache listener).

4. Tại sao thứ tự nạp qua @AutoConfigureBefore và After lại quan trọng?

Vì @ConditionalOnMissingBean phụ thuộc hoàn toàn vào trạng thái hiện tại của container, thứ tự thẩm định giữa các autoconfig mang tính sống còn:

Đối chiếu hai thứ tự evaluate cho cùng một cặp autoconfig: A khai @Bean Foo không điều kiện, B khai @Bean Foo có @ConditionalOnMissingBean; nhánh A được xét trước thì A đăng ký Foo from-A, B thấy Foo đã có nên nhường, context có đúng một bean Foo; nhánh B được xét trước thì B thấy chưa có Foo nên đăng ký Foo from-B, A không có điều kiện nên đăng ký đè lên và nổ BeanDefinitionOverrideException ngay lúc startup

Nếu autoconfig B chạy trước A, B thấy chưa có bean và tự tạo; sau đó A chạy mà không có điều kiện sẽ cố tạo thêm bean nữa, làm nổ lỗi BeanDefinitionOverrideException.

Để xử lý, Spring Boot cung cấp các chỉ dẫn thứ tự:

Java
@AutoConfiguration(after = DataSourceAutoConfiguration.class)
public class HibernateJpaAutoConfiguration { /* ... */ }

@AutoConfiguration(after = HibernateJpaAutoConfiguration.class)
public class JpaRepositoriesAutoConfiguration { /* ... */ }

5. Thuật toán sắp xếp thứ tự AutoConfigurationSorter xử lý DAG thế nào?

Spring Boot không chạy cấu hình tuần tự theo danh sách ngẫu nhiên. Lớp AutoConfigurationSorter thực hiện các bước sau:

  1. Thu thập toàn bộ các quan hệ phụ thuộc từ @AutoConfigureBefore và @AutoConfigureAfter.
  2. Xây dựng một đồ thị có hướng không chu trình (DAG - Directed Acyclic Graph).
  3. Áp dụng thuật toán Topological Sort để tạo ra một chuỗi thực thi tuyến tính an toàn tuyệt đối.

Nếu xuất hiện phụ thuộc vòng tròn (A after B, B after A), Spring Boot sẽ lập tức báo lỗi IllegalStateException khi khởi động.

6. Làm thế nào để điều tra lỗi nạp Bean bằng Actuator /conditions?

Khi một bean không được nạp như mong đợi, hãy kích hoạt endpoint Actuator:

YAML
management:
  endpoints:
    web:
      exposure:
        include: conditions

Truy cập GET /actuator/conditions trả về cấu trúc chi tiết:

  • positiveMatches: Danh sách cấu hình đã nạp thành công kèm lý do pass.
  • negativeMatches: Danh sách cấu hình bị bỏ qua kèm nguyên nhân cụ thể (ví dụ: thiếu class hoặc thiếu property).
  • exclusions: Danh sách các cấu hình bị loại trừ thủ công qua exclude.

Khi phát triển cục bộ, bạn có thể truyền cờ --debug khi chạy ứng dụng để Spring Boot in toàn bộ bảng kiểm tra này ra màn hình console.

7. Những cạm bẫy thứ tự phổ biến khi cấu hình điều kiện?

  • Quên @ConditionalOnMissingBean trên bean mặc định: Dẫn đến việc khi người dùng tự khai báo bean, container bị trùng lặp bean.
  • Đặt @AutoConfigureAfter trên class @Configuration thông thường: Annotation này hoàn toàn vô tác dụng trên các class cấu hình của ứng dụng; nó chỉ có hiệu lực trên các class gắn @AutoConfiguration nạp qua file imports.

Tóm tắt

  • @ConditionalOn* bảo vệ hệ thống khỏi xung đột bean bằng cách thẩm định môi trường runtime theo quy tắc AND.
  • @ConditionalOnMissingBean hiện thực hóa cơ chế back-off, cho phép lập trình viên ghi đè cấu hình mặc định một cách tự nhiên.
  • Thứ tự thẩm định quyết định kết quả của các điều kiện phụ thuộc; được kiểm soát qua @AutoConfigureBefore và @AutoConfigureAfter.
  • AutoConfigurationSorter sử dụng thuật toán Topological Sort trên đồ thị DAG để loại bỏ phụ thuộc vòng tròn.
  • Sử dụng /actuator/conditions để đọc báo cáo ConditionEvaluationReport thay vì đoán mò khi gỡ lỗi.

Tự kiểm tra

Tự kiểm tra
0/5 câu đã trả lời
  1. Q1
    Cơ chế Back-Off trong Spring Boot Auto-configuration hoạt động như thế nào?
  2. Q2
    Tại sao việc ghi đè bean qua cơ chế Back-Off lại được khuyến nghị hơn việc loại trừ hoàn toàn bằng exclude trên @SpringBootApplication?
  3. Q3
    Lớp AutoConfigurationSorter của Spring Boot sử dụng cấu trúc dữ liệu và giải thuật nào để sắp xếp thứ tự nạp các lớp cấu hình tự động?
  4. Q4
    Annotation @AutoConfigureAfter chỉ có hiệu lực khi được đặt trên loại lớp nào?
  5. Q5
    Khi một bean autoconfig không được tạo như kỳ vọng, bạn nên tra cứu mục nào trong phản hồi của endpoint /actuator/conditions để tìm nguyên nhân?

Bài tiếp theo: Mini-Challenge: Trace 1 Request Qua Từng Layer

Bài này có giúp bạn hiểu bản chất không?

Bài này đáng gửi cho bạn học cùng?

Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.

Lộ trình Junior Java Backend Developer

Chặng 14/21 · Spring Boot & autoconfiguration — bài 6/16 của chặng

Ôn phỏng vấn

Bài này trả lời được các câu phỏng vấn sau — tự trả lời thử trước khi mở đáp án.

Thảo luận & góp ý

Hỏi đáp về bài này

Bài tiếp theo

Mini-Challenge: Trace 1 Request Và Thứ Tự Khởi Tạo Bean