2009-07-29 22 views
35

Khi bạn bắt đầu rối tung xung quanh với các công cụ tự động-proxy Spring, bạn thường chạy vào hành vi này như tài liệu:Theo dõi xuống nguyên nhân của của mùa xuân "không đủ điều kiện để tự động proxy"

lớp mà thực hiện giao diện BeanPostProcessor là đặc biệt và do đó chúng được xử lý theo cách khác nhau bởi vùng chứa. Tất cả BeanPostProcessors và trực tiếp đậu tham chiếu của họ sẽ được khởi tạo khi khởi động, như là một phần của giai đoạn khởi động đặc biệt của ApplicationContext, sau đó tất cả những BeanPostProcessors sẽ được đăng ký một cách sắp xếp - và áp dụng cho tất cả đậu thêm . Kể từ AOP tự động proxy được thực hiện như một BeanPostProcessor chính nó, không BeanPostProcessors hoặc trực tiếp đậu tham chiếu có đủ điều kiện cho tự động proxy (và do đó sẽ không có khía cạnh 'dệt' vào chúng.

Đối với bất kỳ ví dụ đậu, bạn sẽ thấy một thông báo đăng nhập thông tin: “Bean 'foo' là không đủ điều kiện cho việc xử lý bởi tất cả BeanPostProcessors (ví dụ: không đủ điều kiện để tự động proxy)”.

Nói cách khác, nếu tôi viết BeanPostProcessor của riêng mình, và lớp đó tham chiếu trực tiếp các bean khác trong ngữ cảnh, thì những bean được tham chiếu đó sẽ không đủ điều kiện để tự động proxy, và một thông báo được ghi vào hiệu ứng đó. Vấn đề của tôi là theo dõi nơi mà tham chiếu trực tiếp có thể rất khó khăn, vì "tham chiếu trực tiếp" có thể thực tế là một chuỗi phụ thuộc chuyển tiếp kết thúc bằng một nửa số hạt trong ngữ cảnh ứng dụng. Tất cả mùa xuân cung cấp cho bạn là thông điệp thông tin duy nhất, và nó không thực sự giúp đỡ nhiều, vượt ra ngoài nói với bạn khi một hạt đậu đã bị bắt trong trang web của tài liệu tham khảo.

Trình xử lý BeanPostProcessor mà tôi đang phát triển không có tham chiếu trực tiếp đến các hạt khác, nhưng đó là một tập hợp các tham chiếu rất hạn chế. Mặc dù vậy, khá nhiều mỗi hạt trong bối cảnh của tôi sau đó bị loại trừ khỏi việc tự động được ủy quyền, theo các thông điệp tường trình, nhưng tôi không thể nhìn thấy sự phụ thuộc đó đang xảy ra ở đâu.

Có ai tìm thấy cách tốt hơn để theo dõi việc này không?

+0

Bạn cũng có thể nhận được thông báo thông tin đó cho các lớp 'PersistenceExceptionTranslator'. – Raedwald

Trả lời

17

Chỉ cần để mang lại một số kết thúc cho câu hỏi này, sự sụp đổ của biểu đồ đối tượng uninitialized được gây ra bởi BeanPostProcessor sử dụng @Autowired để có được phụ thuộc của nó, và cơ chế autowire hiệu quả gây ra mọi định nghĩa bean khác được khởi tạo trước khi BeanPostProcessor của tôi có cơ hội để có tiếng nói trong vấn đề này. Giải pháp không phải là sử dụng autowiring cho BPP của bạn.

+2

Đây không phải là giải pháp; Tôi phải làm gì thay vì khi tôi cần đậu trong bộ xử lý bài của mình? –

3

Không chắc chắn nếu nó là của bất kỳ sự giúp đỡ, nhưng Eclipse Spring IDE 's graph view vẻ như nó có thể hữu ích trong việc phân loại ra tài liệu tham khảo đậu ..

21

Thực hiện theo công thức này:

  1. mở BeanPostProcessorChecker trong IDE của bạn (nó là một lớp bên trong của AbstractApplicationContext)
  2. Đặt một breakpoint trên if (logger.isInfoEnabled()) { trong phương pháp postProcessAfterInitialization
  3. Chạy mã của bạn
  4. Khi bạn nhấn điểm ngắt, tìm các cuộc gọi đến getBean(String,Class<T>) trong ngăn xếp ngăn xếp của bạn.

    Một trong các cuộc gọi này sẽ cố gắng tạo một BeanPostProcessor. Đậu đó phải là thủ phạm.

nền

Hãy tưởng tượng tình huống này:

public class FooPP implements BeanPostProcessor { 
    @Autowire 
    private Config config; 
} 

Khi mùa xuân đã tạo config (vì nó là một sự phụ thuộc của FooPP), nó có một vấn đề: Hợp đồng nói rằng tất cả BeanPostProcessor phải được áp dụng cho mọi bean đang được tạo. Nhưng khi mùa xuân cần config, có ít nhất một PP (cụ thể là FooPP) không sẵn sàng cho dịch vụ!

này trở nên tệ hơn khi bạn sử dụng một lớp @Configuration để xác định đậu này:

@Configuration 
public class BadSpringConfig { 
    @Lazy @Bean public Config config() { return new Config(); } 
    @Lazy @Bean public FooPP fooPP() { return new FooPP(); } 
} 

Mỗi lớp cấu hình là một bean. Điều đó có nghĩa là để xây dựng một nhà máy đậu từ BadSpringConfig, mùa xuân cần phải áp dụng sau xử lý fooPP nhưng để làm được điều đó, trước hết nó cần nhà máy sản xuất hạt ...

Trong ví dụ này, có thể phá vỡ một trong các phụ thuộc theo chu kỳ. Bạn có thể thực hiện FooPP thực hiện BeanFactoryAware để nhận Spring chèn BeanFactory vào bộ xử lý bài đăng. Bằng cách đó, bạn không cần autowiring.

Sau đó trong mã, bạn lười biếng có thể yêu cầu cho đậu:

private LazyInit<Config> helper = new LazyInit<Config>() { 

    @Override 
    protected InjectionHelper computeValue() { 
     return beanFactory.getBean(Config.class); 
    } 
}; 

@Override 
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 
    String value = helper.get().getConfig(...); 
} 

(source for LazyInit)

Để phá vỡ chu kỳ giữa các bean factory và bộ xử lý bài, bạn cần phải cấu hình các bài bộ xử lý trong tệp cấu hình XML. Mùa xuân có thể đọc và xây dựng tất cả các cấu trúc mà không bị lẫn lộn.

+0

là giải pháp này vẫn còn phù hợp trong ứng dụng đa luồng như dịch vụ web? – hudi

+0

'LazyInit' là an toàn, vì vậy có. –

+0

Tôi đã có thể sử dụng điều này để theo dõi vấn đề này khi tôi đang chuyển đổi một ứng dụng Jersey thành Spring Boot. Hóa ra tôi đã có một bean được gọi là "conversionService", và ConfigurationPropertiesBindingPostProcessor tìm kiếm một bean (tùy chọn) với tên đó. Vì nó là một BeanPostProcessor tham chiếu đến bean của tôi, các bean của tôi được tham chiếu bởi dịch vụ chuyển đổi của tôi đã không nhận được đúng cách (ví dụ: các trường @Autowired của họ không được thiết lập). –

Các vấn đề liên quan