2010-08-26 18 views
8

Tôi có một định nghĩa bean trong mùa xuân và đó là đối proxy đó có nghĩa là để được sử dụng ở khắp mọi nơi:ApplicationContext.getBean (Lớp clazz) không suôn sẻ với proxy

<bean name="my.Bean" class="org.springframework.aop.framework.ProxyFactoryBean" scope="prototype"> 
    <property name="proxyInterfaces" value="my.Interface"/> 
    <property name="target" ref="my.BeanTarget"/> 
    <property name="interceptorNames"> 
    <list> 
     <value>someInterceptor</value> 
    </list> 
    </property> 
</bean> 

<bean name="my.BeanTarget" class="my.InterfaceImpl" scope="prototype"> 
    <property name="foo" ref="bar"/> 
</bean> 

bài này hoạt động tốt; và trong v3 thế giới trước mùa xuân Tôi đã sử dụng nó như

ApplicationContext ctx = ...; 
my.Interface foo = (my.Interface) ctx.getBean("my.Bean"); // cast is necessary 

Trong mùa xuân 3 nó đã trở thành có thể làm được loại tra cứu an toàn, ví dụ:

my.Interface foo = ctx.getBean(my.Interface.class); 

Một lần nữa, điều này hoạt động tốt cho đậu bình thường trong khi cho đậu proxied Tôi đang nhận được my.BeanTarget thay vì my.Bean. Tôi đã cố gắng để inline my.BeanTarget (như trong tài liệu hướng dẫn Spring) để làm cho nó ẩn, nhưng tất cả tôi nhận được

org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [my.Interface] is defined: expected single bean but found 0: 

Vậy là nó có thể sử dụng loại tra cứu đậu an toàn với đậu proxy và nếu có - làm thế nào?

+0

Bạn có thực sự cần tương tác trực tiếp với ngữ cảnh không? Hầu hết các ứng dụng của tôi chỉ cần khởi động nó và sau đó mọi thứ khác được xử lý với việc tiêm phụ thuộc (hoạt động cho các bean được proxied). Tôi đã thực hiện một số công cụ khung nơi tôi đã cần phải truy cập vào bối cảnh, nhưng, theo kinh nghiệm của tôi, nó rất hiếm. – SteveD

+0

Hệ thống của chúng tôi khá rộng và một số bit và lớp không được sinh ra trong Spring (cũng không thể), vì vậy chúng phải sử dụng beanFactory/appCtx để nhận các phụ thuộc cần thiết. – mindas

Trả lời

6

Vấn đề ở đây là scope="prototype" trên ProxyFactoryBean của bạn.

Ngữ cảnh sẽ chỉ háo hức khởi tạo định nghĩa bean đơn. Đậu của phạm vi không singleton chỉ được khởi tạo khi được yêu cầu. Điều này có nghĩa là khi bạn hỏi bối cảnh cho các loại đậu của một loại nhất định, bối cảnh không thể khởi tạo những hạt không phải là singleton để yêu cầu chúng cho loại của chúng, nó phải hoàn toàn dựa vào thông tin trong định nghĩa bean.

Trong trường hợp ProxyFactoryBean, loại proxy được tạo được xác định bởi logic phức tạp yêu cầu bean được khởi tạo hoàn toàn. Nếu không có khởi tạo đó, ProxyFactoryBean chỉ có thể báo cáo loại mục tiêu là null.

Tôi không thể nói cách khác, ngoài việc sử dụng định nghĩa bean đơn hoặc yêu cầu tên đậu một cách rõ ràng, ví dụ:

<bean id="my.Interface"> class="ProxyFactoryBean"... > 

và sau đó:

ctx.getBean(MyInterface.class.getName()); 

Ở đây, chúng tôi sử dụng quy ước tên đậu là giao diện mà họ thực hiện.

1

Bạn không thể thực hiện my.Interface foo = ctx.getBean(my.Bean.class);?

2

Dường như phạm vi của proxy được tạo ra bởi ProxyFactoryBean nên được chỉ định sử dụng singleton tài sản thay vì scope thuộc tính:

<bean name="my.Bean" class="org.springframework.aop.framework.ProxyFactoryBean"> 
    <property name="singleton" value="false"/> 
    ... 
</bean> 

này đã giải quyết được vấn đề khi đậu mục tiêu là bên trong.

Khi bạn có nhiều đậu cấp cao nhất của lớp tương tự, bạn có thể sử dụng một tra cứu kiểu an bởi id:

my.Interface foo = ctx.getBean("my.Bean", my.Interface.class); 
+0

Tôi chấp nhận câu trả lời này quá nhanh. Nó chỉ ra rằng singleton = false tài sản không phải là điều tương tự như scope = prototype. Tôi đã quản lý để có được đậu đơn được bọc trong proxy mục tiêu mặc dù singleton = false đã được chỉ định. câu trả lời của skaffman thực sự gần gũi hơn với sự thật. – mindas

+0

Đối số chuỗi trong chuỗi 'getBean (String, Class)' là gì? Bạn có thể giải thích dùm không? – Freakyuser

+0

Đó là tên của bean được yêu cầu trong ngữ cảnh ứng dụng. Nó tương ứng với thuộc tính 'id' hoặc' name' trong cấu hình XML. – axtavt

0

Khi Spring hoạt động với Giao diện, trong ngữ cảnh của aop, bạn có thể xác định bộ giao diện khác nhau và yêu cầu giao diện bạn mong đợi. Bằng cách này, không cần phải cast cho một lớp thực sự nhưng Spring sẽ quản lý các giao diện.

Giả sử bạn có lớp A thực hiện B. Bạn muốn truyền từ A đến B nhưng bị từ chối vì A là proxy do aop. Sau đó, thực hiện A thực hiện C và C mở rộng B. C sở hữu các phương thức cần thiết, và C là giao diện riêng được truy cập chỉ từ mã thực hiện của bạn. Cuối cùng yêu cầu mùa xuân tiêm B hoặc C tùy thuộc vào kỳ vọng của bạn.

PrivateItf executor = context.getBean(PrivateItf.class); 

Bằng cách này, ngay cả khi lớp thực là proxy, nó thực hiện Giao diện riêng của bạn với tất cả những gì bạn cần.

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