2009-05-06 26 views
22

Tôi có một hạt đơn mà cần cho mỗi cuộc gọi của một hàm để trả về một tham chiếu đến một bean nguyên mẫu mới (khác). Cách duy nhất mà tôi có thể nghĩ đến việc làm này là để lấy một thể hiện bean mẫu mới từ BeanFactory/ApplicatioContext bằng cách gọi phương thức getBean() của nó. Mẫu mã sẽ theo dõi ...Đậu nguyên mẫu mùa xuân kết hợp với đậu đơn và tiêm phụ thuộc. Có cách tiếp cận nào chỉ cấu hình không?

Có cách nào tốt hơn để thực hiện việc này không? Chỉ thông qua cấu hình, hy vọng? (Cá nhân, tôi nghi ngờ có ...)

<bean id="protoBean" scope="prototype" 
     class="com.blahblah.ProtoBean" /> 

<bean id="singletonBean" 
     class="com.blahblah.SingletonBean" /> 

public class ProtoBean { 

    .... 
} 

public class SingletonBean { 

    private BeanFactory factory; 

    public ProtoBean dispense() { 
     return (ProtoBean) factory.getBean("protoBean"); 
    } 

    .... 
} 

Trả lời

14

hãy nhìn vào Method Injection

+1

Câu trả lời này đã lỗi thời, như Christopher đã nói, từ mùa xuân 3.0, phần tử '' là đúng cách để làm điều đó. Ngoài ra, như chỉ ra bởi shrini1000, phương pháp tiêm làm cho lớp vụng về để kiểm tra. –

4

Sử dụng tiêm phương pháp làm cho các lớp singleton-đậu khó khăn cho đơn vị kiểm tra (bạn cần phải tạo một lớp con để thực hiện phương pháp đưa ra sự phụ thuộc). Thêm vào đó nó không thể tái sử dụng được vì bạn không thể trực tiếp khởi tạo nó, vì vậy nếu bạn không sử dụng Spring và muốn sử dụng lớp này, bạn sẽ cần phải phân lớp và cung cấp phương thức trả về bean.

Một cách tiếp cận tốt hơn IMHO là sử dụng một proxy, một nguồn mục tiêu mẫu thử nghiệm và một bean đích mẫu thử nghiệm, như sau. Lớp đơn lớp đậu như vậy dễ dàng kiểm tra đơn vị và có thể tái sử dụng tốt hơn.

<bean id="targetPooledObject" class="pool.PooledObject" scope="prototype"> 
    <constructor-arg value="42" /> 
</bean> 

<bean id="prototypeTargetSource" class="org.springframework.aop.target.PrototypeTargetSource"> 
    <property name="targetBeanName" value="targetPooledObject" /> 
</bean> 

<bean id="pooledObject" class="org.springframework.aop.framework.ProxyFactoryBean"> 
    <property name="targetSource" ref="prototypeTargetSource" />   
</bean> 

<bean id="poolConsumer" class="pool.PoolConsumer"> 
    <property name="pooledObject" ref="pooledObject" /> 
</bean> 

Bây giờ chúng ta có thể tiêm pooledObject vào một bean singleton (poolConsumer như trình bày ở trên), và cho mỗi cuộc gọi phương pháp mà chúng tôi thực hiện trên đó đậu singleton, (ví dụ như mỗi lần chúng tôi gọi poolConsumer.callPooledObjectMethod() nó sẽ gọi pooledObject.foo()), chúng tôi có được một bean PooledObject mới.

Tiếp theo là các mã tương ứng:

public class PooledObject 
{ 
    private int x; 

    public PooledObject(int x) 
    { 
     this.x = x; 
    } 

    public void foo() 
    { 
     System.out.println("foo called"); 
    } 
} 

public class PoolConsumer 
{ 
    private PooledObject pooledObject; 

    public PooledObject getPooledObject() 
    { 
     return pooledObject; 
    } 

    public void setPooledObject(PooledObject pooledObject) 
    { 
     this.pooledObject = pooledObject; 
    } 

    public void callPooledObjectMethod() 
    { 
     pooledObject.foo(); 
    } 
} 
+1

thú vị, nhưng bạn có thể vui lòng xây dựng (tức là, thêm mã java) – Yaneeve

+1

@Yaneeve đã thêm mã và sửa đổi cấu hình một chút để phản ánh nó hay không. Hãy tha thứ cho sự ô uế mã của tôi. – shrini1000

+0

@Yaneeve chúng ta cũng có thể tạo một hồ bơi đậu vào mùa xuân. Sử dụng cấu hình tương tự như trên, nhưng sử dụng 'CommonsPoolTargetSource' thay vì 'PrototypeTargetSource'. Điều này có thể hữu ích, ví dụ: khi xử lý các tin nhắn JMS thông qua Spring theo kiểu MDB. Sau đây là một số chi tiết: http://stackoverflow.com/a/12668538/266103 – shrini1000

10

Từ mùa xuân 3.0, chúng ta có thể sử dụng <aop:scoped-proxy> cho dependency injection về phạm vi thích hợp. Đằng sau hiện trường, Spring tiêm các đối tượng được ủy quyền và chịu trách nhiệm tìm kiếm bối cảnh đúng phạm vi, có thể là nguyên mẫu, phiên hoặc yêu cầu, vv Xem các tài liệu chính thức here.

Và để làm cho cuộc sống dễ dàng hơn, Spring cũng đã giới thiệu thuộc tính proxyMode cho @Scope, vì vậy chúng tôi không chỉ giới hạn trong các khai báo XML. Ví dụ:

@Scope(value = "prototype", proxyMode = ScopedProxyMode.INTERFACES) 

Đảm bảo ghi rõ bean được tiêm là proxy để cảnh báo những người khác rằng getClass() và quá trình truyền có thể không mang lại kết quả mong đợi. Ngoài ra, hãy đảm bảo equals() và hashCode() trong lớp proxy sử dụng các phương thức truy cập thay vì truy cập trực tiếp các biến lớp.

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