2012-07-18 41 views
15

Tôi có một biểu đồ các hạt đậu mùa xuân tự động lấy nhau. Minh họa đơn giản hóa quá mức:Mùa xuân tạo ra nhiều phiên bản của một singleton?

<context:annotation-config/> 
<bean class="Foo"/> 
<bean class="Bar"/> 
<bean class="Baz"/> 

... 

public class Foo { 
    @Autowired Bar bar; 
    @Autowired Baz baz; 
} 

public class Bar { 
    @Autowired Foo foo; 
} 

public class Baz { 
    @Autowired Foo foo; 
} 

Tất cả những hạt này không có phạm vi nào được chỉ định là đơn độc (làm cho chúng không rõ ràng bất kỳ điều gì, tôi đã thử).

Vấn đề là sau khi instantiation của một bối cảnh ứng dụng duy nhất, trường hợp của BarBaz chứa trường hợp khác nhau của Foo. Làm sao điều này xảy ra được?

Tôi đã cố gắng tạo công khai không có hàm tạo args cho Foo và gỡ lỗi đã xác nhận Foo được tạo nhiều lần. Dấu vết ngăn xếp cho tất cả các sáng tạo này là here.

Tôi cũng đã cố gắng để cho phép debug logging cho mùa xuân, và trong số tất cả các dòng khác, đã nhận như sau:

DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo' 
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo' 
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo' 

Tôi hiểu rằng đậu của tôi là tham khảo chéo nhau, nhưng tôi mong chờ Spring framework để tôn trọng phạm vi singleton và khởi tạo một hạt đơn một lần, và sau đó autowire nó cho bất cứ ai muốn nó.

Thực tế thú vị là nếu tôi sử dụng trường học cũ private hàm tạo với public static Foo getInstance accessor, điều này chỉ hoạt động tốt - không có ngoại lệ nào được ném trong khi thiết lập ngữ cảnh.

FWIW, tôi đang sử dụng phiên bản Spring 3.0.5 (cũng đã thử với 3.1.2, cùng một kết quả) với hàm xây dựng o.s.c.s.ClassPathXmlApplicationContext(String ...configLocations).

Tôi có thể dễ dàng chuyển đổi mã của mình để sử dụng trình khởi tạo tĩnh nhưng tôi muốn hiểu lý do tại sao Spring hoạt động theo cách này. Đây có phải là một lỗi?

EDIT: Một số điều tra bổ sung cho thấy

  • Sau bối cảnh ứng dụng được khởi tạo, tất cả các yêu cầu tiếp theo để context.getBean(Foo.class)luôn trở lại cùng một ví dụ của Foo.
  • Thay thế @Autowired với bộ định vị (khoảng 20 tập quán đậu này) vẫn cho kết quả nhiều cấu trúc của đối tượng này, nhưng tất cả các phụ thuộc được tiêm cùng một tham chiếu.

Với tôi ở trên cho thấy đây là lỗi mùa xuân liên quan đến việc triển khai @Autowired. Tôi sẽ đăng lên các diễn đàn cộng đồng Spring và đăng lại ở đây nếu tôi quản lý để có được bất kỳ điều gì hữu ích.

+0

Có thể hiển nhiên nhưng chỉ có 1 JVM khi chơi? Phụ thuộc tròn? –

+0

Có, đây chỉ là một JVM. Thông tư phụ thuộc - có, nhưng tôi tin rằng tôi đã giải thích điều này trong bài viết của mình. – mindas

+0

Tôi hiểu nhưng điều gì sẽ xảy ra nếu bạn có ví dụ như một công cụ xây dựng? Làm thế nào để Spring giải quyết vấn đề đó? –

Trả lời

11

Ngữ cảnh con có thể phục hồi cùng một hạt đơn nếu bạn không cẩn thận với ngữ cảnh: là các chú thích quét ngữ cảnh mùa xuân khác cũng như các chú thích MVC và các chú thích khác). Đây là vấn đề thường gặp khi sử dụng các servlet Spring trong các ứng dụng web, xem Why DispatcherServlet creates another application context?

Đảm bảo bạn không quét lại các thành phần trong ngữ cảnh con hoặc bạn chỉ quét các gói/chú thích cụ thể và loại trừ các gói/chú thích đó quét thành phần ngữ cảnh.

+0

những singletones này có tải cùng một trình nạp lớp không? – gstackoverflow

+0

Bạn có thể cung cấp ví dụ tối thiểu nơi singleton mùa xuân sẽ tải twiсe? – gstackoverflow

0

Hãy thử sử dụng tiêm setter thay vì cách khởi tạo và xem liệu nó có hoạt động hay không. Trong bean bean xml chỉ định Bean A ref cho Bean B và ngược lại.

+0

Tôi đã cập nhật bài đăng của mình. Chỉ cần nhắc lại - tôi biết cách khắc phục vấn đề, nhưng quan trọng hơn là tôi đang cố gắng hiểu ** tại sao ** điều này xảy ra. – mindas

0

cấu hình Spring của tôi là như sau:

<context:annotation-config/> 

<bean class="Bar" /> 
<bean class="Foo" /> 
<bean class="Baz" /> 

Lớp học là giống hệt như của bạn

ứng dụng thử nghiệm như sau:

import org.springframework.context.ApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 

public class SpringTest { 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     ApplicationContext ctx = new ClassPathXmlApplicationContext("META-INF/spring/testctx.xml"); 

     Foo foo = ctx.getBean(Foo.class); 
     Baz baz = ctx.getBean(Baz.class); 
     Bar bar = ctx.getBean(Bar.class); 

     System.out.println(foo.equals(baz.foo)); 
     System.out.println(foo.equals(bar.foo)); 
     System.out.println(baz.equals(foo.baz)); 

     System.out.println(foo.baz.toString()); 
     System.out.println(baz.toString()); 
     System.out.println(foo.bar.toString()); 
     System.out.println(bar.toString()); 

    } 

} 

Output từ ứng dụng thử nghiệm như sau:

true 
true 
true 
[email protected] 
[email protected] 
[email protected] 
[email protected] 

Sử dụng 3.0.6 nó hoạt động hoàn toàn tốt (đậu đơn là thực sự đơn). Có thể có điều gì khác mà bạn không minh họa ở đây làm rối loạn cấu hình của bạn. Tất nhiên, như một lưu ý phụ, sử dụng gói mặc định có thể gây ra một số phép thuật misterious xảy ra ;-)

+0

Cảm ơn bạn đã nỗ lực vào việc này. Trong trường hợp của tôi nó là đồ thị phức tạp hơn nhiều của các đối tượng, hàng trăm người trong số họ. Vì những lý do rõ ràng, tôi không thể đăng tất cả chúng ở đây, chỉ cần cắt giảm kịch bản tối thiểu để minh họa điểm. – mindas

+0

@mindas Bạn đã thử sắp xếp lại các định nghĩa bean trong tập tin chưa? Hãy thử đặt Foo ở vị trí thứ hai hoặc cuối cùng. – partlov

1

Vì lý do nào đó, chúng tôi cũng nhận được điều này một cách ngẫu nhiên trong các thử nghiệm và dịch vụ tích hợp (phiên bản mùa xuân 4.1.4, java 1.8).

Có vẻ như có thể có nhiều hơn một thủ phạm - Autowiring dường như đang gây ra điều này lúc đầu.

Tuy nhiên, chúng tôi đã giải quyết các lỗi nhất quán nhất bằng cách đảm bảo chúng tôi cung cấp cho mỗi bean bị ảnh hưởng là trường 'id'.

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