24

Tôi có một tròn tham khảo tại một trong những dự án của tôi tại nơi làm việc sử dụng lò xo, mà tôi không thể sửa chữa, và không thành công với các lỗi sau khi khởi động:mùa xuân tròn tham khảo ví dụ

'org.springframework.security.authenticationManager': Requested bean is currently in creation: Is there an unresolvable circular reference? 

Tôi cố gắng để tái tạo cùng một vấn đề ở mức độ nhỏ hơn trong một dự án mẫu (không có tất cả các chi tiết về dự án công việc của tôi). Tuy nhiên tôi đã không thể đưa ra một kịch bản chính đáng mà mùa xuân không có lỗi. Dưới đây là những gì tôi có:

public class ClassA { 
    @Autowired 
    ClassB classB; 
} 

public class ClassB { 
    @Autowired 
    ClassC classC; 
} 

@Component 
public class ClassC { 
    @Autowired 
    ClassA classA; 
} 

@Configuration 
public class Config { 
    @Bean 
    public ClassA classA() { 
     return new ClassA(); 
    } 

    @Bean 
    public ClassB classB() { 
     return new ClassB(); 
    } 
} 

Tôi có một kịch bản tương tự trong dự án của tôi, mà thất bại, và tôi đã mong đợi mùa xuân để phàn nàn trong dự án mẫu của tôi là tốt. Nhưng nó hoạt động tốt! Ai đó có thể cho tôi một ví dụ đơn giản về cách phá vỡ mùa xuân với lỗi tham chiếu vòng tròn?

Chỉnh sửa: Tôi đã khắc phục sự cố bằng cách sử dụng javax.inject.Provider. Sự khác biệt duy nhất trong 2 dự án là các chú thích được sử dụng là javax.inject.Inject và javax.annotation.ManagedBean thay cho @Autowired và @Component.

Trả lời

23

Đây là một chủ đề cũ, vì vậy tôi đoán bạn gần như quên về vấn đề này, nhưng tôi muốn cho bạn biết về bí ẩn. Tôi gặp phải vấn đề tương tự, và tôi đã không biến mất một cách kỳ diệu, vì vậy tôi phải giải quyết vấn đề. Tôi sẽ giải quyết từng câu hỏi của bạn.

1. Tại sao bạn không thể tạo lại ngoại lệ tham chiếu vòng tròn?

Spring takes care of it. It creates beans and injects them as required.

2. Vậy tại sao dự án của bạn tạo ra ngoại lệ?

  • Như @sperumal nói, mùa xuân có thể tạo ra ngoại lệ tròn nếu bạn sử dụng constructor injection
  • Theo nhật ký, bạn sử dụng Xuân An trong dự án của bạn
  • Trong cấu hình Xuân An, họ làm sử dụng constructor tiêm
  • đậu của bạn mà tiêm authenticationManager có tham chiếu vòng tròn

3. Vậy tại sao có cũ sự lừa dối biến mất một cách thần bí?

Ngoại lệ có thể hoặc có thể không xảy ra tùy thuộc vào thứ tự tạo hạt. Tôi đoán bạn thực hiện một số *context.xml file hoặc lâu hơn, và tải chúng với cấu hình giống như dưới đây trong web.xml

<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value>classpath:*-context.xml</param-value> 
</context-param> 

Các tập tin xml sẽ được nạp bởi XmlWebApplicationContext lớp và thứ tự tải các tập tin không được bảo đảm. Nó chỉ tải các tập tin từ hệ thống tập tin. Vấn đề là ở đây. Không có vấn đề gì nếu lớp này tải tệp ngữ cảnh ứng dụng đầu tiên, vì các bean của bạn đã được tạo ra khi chúng được sử dụng để tiêm xây dựng Spring Security. Tuy nhiên, nếu nó tải tệp ngữ cảnh Spring Security đầu tiên, thì vấn đề tham chiếu vòng tròn xảy ra, bởi vì Spring cố gắng sử dụng các bean của bạn trong quá trình tiêm constructor trước khi chúng được tạo ra.

4. Cách giải quyết sự cố?

Buộc tải thứ tự của tệp xml. Trong trường hợp của tôi, tôi đã tải tệp tin xml bối cảnh bảo mật ở cuối tệp ngữ cảnh ứng dụng bằng cách sử dụng <import resource="">. Thứ tự tải có thể được thay đổi tùy thuộc vào môi trường ngay cả với cùng một mã, vì vậy tôi khuyên bạn nên đặt thứ tự để loại bỏ các vấn đề tiềm ẩn.

2

Một số đọc về vấn đề này:

http://blog.jdevelop.eu/?p=382

phụ thuộc vòng tròn như vậy là không mát mẻ và được tránh khi có thể

26

Bạn có thể sử dụng @Lazy để chỉ ra rằng đậu được lười biếng tạo, phá vỡ chu kỳ háo hức của autowiring.

Ý tưởng là một số đậu trên chu trình có thể được khởi tạo như một proxy, và ngay tại thời điểm nó thực sự cần thiết nó sẽ được khởi tạo. Điều này có nghĩa, tất cả các bean được khởi tạo ngoại trừ một bean là proxy. Sử dụng nó lần đầu tiên sẽ kích hoạt cấu hình và khi các bean khác đã được cấu hình, nó sẽ không là vấn đề.

Từ một Issue trong mùa xuân-Jira:

@Lazy chú thích có thể được sử dụng kết hợp với @Configuration để chỉ ra rằng tất cả đậu trong đó lớp cấu hình nên uể oải khởi tạo. Tất nhiên, @Lazy cũng có thể được sử dụng kết hợp với các phương thức @Bean riêng lẻ để cho biết việc khởi tạo lười biếng trên cơ sở từng người một . https://jira.springsource.org/browse/SJC-263

Có nghĩa là chú thích bean của bạn là @Lazy là đủ. Hoặc nếu bạn chỉ thích chú thích lớp cấu hình là @Lazy như sau:

@Configuration 
@Lazy 
public class Config { 
    @Bean 
    public ClassA classA() { 
     return new ClassA(); 
    } 

    @Bean 
    public ClassB classB() { 
     return new ClassB(); 
    } 
} 

Nếu bạn thực hiện giao diện đậu của bạn, thao tác này sẽ hoạt động khá tốt.

+1

Chỉ cần thêm vào điều này, chúng tôi nhấn một vấn đề tương tự (với tiêm SpringTemplateEngine). Giải pháp "setter injection" không có tác dụng gì, nhưng chú thích '@ Lazy' đã làm được điều này. Nó cảm thấy như một băng cứu trợ trên một vết thương đạn, nhưng bây giờ tôi sẽ giành chiến thắng và bỏ đi. Cảm ơn Mister Spaeth. – demaniak

9

Theo tài liệu mùa xuân, có thể nhận được vấn đề phụ thuộc theo Thông tư hoặc BeanCurrentlyInCreationException bằng cách sử dụng injection constructor injection.

Giải pháp khắc phục sự cố là sử dụng các trình cài đặt thay vì tiêm Constructor.

Tham khảo http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html.

+2

Tôi nghĩ rằng bạn hiểu lầm những gì đã được viết ở đó: Nếu bạn sử dụng chủ yếu tiêm constructor, ** nó có thể ** để tạo ra một kịch bản phụ thuộc unresolvable. –

+1

Constructor injection là thích hợp hơn tiêm setter - bean của bạn không tồn tại cho đến khi constructor invocation được hoàn thành, trong khi với setter injection bạn có thể bỏ qua một số tham số cần thiết và bean tồn tại trong một thời gian –

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