SPRING SERIES - LỖI IM LẶNG

Thời Điểm Và Danh Sách BPP

LIFECYCLE - XANH = TẦNG PHÓNG TO Đọc từ trái sang phải. Màu đậm dần nghĩa là gần cơ chế hơn. Dấu * đánh dấu điểm bài viết khai thác.

Triệu chứng A - bean sinh sớm

@Value không inject - field giữ giá trị mặc định

Cùng một gốcBPP cần thiết chưa có mặt tại thời điểm object đi qua lifecycle.

Triệu chứng B - proxy sinh muộn

@Transactional trong @PostConstruct không mở transaction

Mức 1 - bản đồ đầy đủ

AbstractApplicationContext.refresh()

12 bước điều phối thật trong source

  1. prepareRefresh()Bật trạng thái, kiểm tra property bắt buộc
  2. obtainFreshBeanFactory()Tạo hoặc làm mới BeanFactory
  3. prepareBeanFactory()Thêm ApplicationContextAwareProcessor thủ công
  4. postProcessBeanFactory()Hook cho lớp context con
  5. invokeBeanFactoryPostProcessors()BFPP chạy khi List BPP còn chưa đầy
  6. registerBeanPostProcessors()Tìm, sắp thứ tự, thêm các BPP còn lại
  7. initMessageSource()Khởi tạo message source
  8. initApplicationEventMulticaster()Khởi tạo bộ phát event
  9. onRefresh()Hook cho context chuyên biệt
  10. registerListeners()Đăng ký listener bean
  11. finishBeanFactoryInitialization()Tạo các singleton non-lazy còn lại
  12. finishRefresh()Công bố context đã sẵn sàng
Mức 2 - zoom bước 5 và 6

List BPP đầy lên khi nào?

Không phải rỗng hoặc đầy, mà đầy dần theo thời gian

  1. prepareBeanFactory()Tự thêm ApplicationContextAwareProcessor
  2. BFPP được tạo sớm@Value chưa có processor phụ trách
  3. EnvironmentAware vẫn chạyProcessor ở bước 1 gọi callback này
  4. registerBeanPostProcessors()AutowiredAnnotationBeanPostProcessor và các BPP khác vào List
  5. Bean tạo về sau đi qua ListHook property, init và proxy chạy đúng lượt

Ranh giới chính xác: EnvironmentAware không phải BPP. Nó là callback do ApplicationContextAwareProcessor gọi. Vì processor này được thêm thủ công ở bước 3 của refresh(), một BFPP sinh ở bước 5 vẫn nhận được Environment.

Mức 3 - zoom nơi List được dùng

Một bean đi qua 7 chặng

Đường singleton phổ biến, không có circular reference

  1. InstantiateConstructor tạo object trần
  2. postProcessProperties()@Autowired@Value được inject
  3. Aware cơ bảnBeanNameAware, BeanClassLoaderAware, BeanFactoryAware được gọi trực tiếp
  4. BPP before initializationEnvironmentAware, @PostConstruct chạy trên object chưa được AOP bọc
  5. afterPropertiesSet()Callback của InitializingBean
  6. Custom init methodVí dụ @Bean(initMethod = "warmUp")
  7. BPP after initializationAuto-proxy creator có thể trả về AOP proxy

Lối ra theo đúng lifecycle

  • BFPP cần cấu hìnhImplement EnvironmentAware hoặc nhận Environment bằng API hạ tầng.
  • Logic cần proxyChạy sau khi context sẵn sàng, ví dụ ApplicationRunner, và gọi qua proxy.

Khi KHÔNG được kết luận

  • Thấy một field @Value nullChưa đủ để kết luận bean sinh sớm; còn có key sai, profile sai hoặc binding sai.
  • Thấy không có transaction trong initChưa đủ để kết luận chỉ do thời điểm; self-invocation cũng có thể bỏ qua proxy.