我在Spring中有一个bean定义,它的代理对应物可以在任何地方使用:
<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>
这一切都运作良好;在Spring-v3之前的世界中我使用它就像
一样ApplicationContext ctx = ...;
my.Interface foo = (my.Interface) ctx.getBean("my.Bean"); // cast is necessary
在Spring 3中,可以进行类型安全查找,例如:
my.Interface foo = ctx.getBean(my.Interface.class);
同样,这适用于普通bean,而对于代理bean,我得到的是my.BeanTarget
而不是my.Bean
。我试图内联my.BeanTarget
(如Spring文档中所示)将其隐藏起来,但我得到的只是
org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [my.Interface] is defined: expected single bean but found 0:
因此可以对代理bean使用类型安全bean查找,如果是 - 如何?
答案 0 :(得分:6)
此处的问题是scope="prototype"
上的ProxyFactoryBean
。
上下文只会急切地初始化单例bean定义。非单一范围的豆只在被要求时才被初始化。这意味着当你向上下文询问给定类型的bean时,上下文不能初始化那些非单例bean以询问它们的类型,它必须完全依赖于bean定义中的信息。
在ProxyFactoryBean
的情况下,生成的代理的类型由需要完全初始化bean的复杂逻辑确定。如果没有初始化,ProxyFactoryBean
只能将目标类型报告为null
。
除了使用单例bean定义,或者通过名称明确要求bean之外,我无法解决这个问题,例如。
<bean id="my.Interface"> class="ProxyFactoryBean"... >
然后:
ctx.getBean(MyInterface.class.getName());
在这里,我们使用bean名称的约定作为它们实现的接口。
答案 1 :(得分:2)
看起来ProxyFactoryBean
创建的代理范围应使用singleton
属性而不是scope
属性指定:
<bean name="my.Bean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="singleton" value="false"/>
...
</bean>
这解决了目标bean内部时的问题。
如果您有多个同一类的顶级bean,则可以使用id进行类型安全查找:
my.Interface foo = ctx.getBean("my.Bean", my.Interface.class);
答案 2 :(得分:1)
你不能做my.Interface foo = ctx.getBean(my.Bean.class);
吗?
答案 3 :(得分:0)
当Spring使用Interfaces时,在aop的上下文中,您可以定义不同的接口集并请求您期望的接口。这样就不需要对真正的类进行强制转换,但Spring会管理接口。
让我们假设您有A类实现B.您想要将A转换为B但是由于aop,A被拒绝,因为A是代理。 然后使A实现C和C扩展B. C拥有所需的方法,C是仅从您的实现代码访问的专用接口。 最后请求春天注入B或C,具体取决于您的期望。
PrivateItf executor = context.getBean(PrivateItf.class);
这样,即使真正的类是代理,它也可以根据您的需要实现您的私有接口。