简体   繁体   English

ApplicationContext.getBean(Class clazz)与代理不兼容

[英]ApplicationContext.getBean(Class clazz) doesn't go well with proxies

I have a bean definition in Spring and it's proxy counterpart which is meant to be used everywhere: 我在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>

This all works well; 这一切都运作良好; and in pre-Spring v3 world I was using it like 而在Spring-v3之前的世界里,我就像使用它一样

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

In Spring 3 it became possible to do type safe lookups, eg: 在Spring 3中,可以进行类型安全查找,例如:

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

Again, this works well for ordinary beans whereas for proxied beans I am getting my.BeanTarget instead of my.Bean . 同样,这适用于普通bean,而对于代理bean,我得到my.BeanTarget而不是my.Bean I have tried to inline my.BeanTarget (as shown in Spring documentation) to make it hidden, but all I got was 我试图内联my.BeanTarget (如Spring文档中所示)使其隐藏,但我得到的只是

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

So is it possible to use type safe bean lookups with proxied beans and if yes - how? 那么是否可以使用代理bean的类型安全bean查找,如果是 - 如何?

The problem here is the scope="prototype" on your ProxyFactoryBean . 这里的问题是您的ProxyFactoryBean上的scope="prototype"

The context will only eagerly-initialize singleton bean definitions. 上下文只会急切地初始化单例bean定义。 Beans of non-singleton scope are only initialized when asked for. 非单一范围的豆只在被要求时才被初始化。 This means that when you ask the context for beans of a given type, the context cannot initialize those non-singleton beans in order to ask them for their type, it has to go purely on the information in the bean definition. 这意味着当您向上下文询问给定类型的bean时,上下文无法初始化那些非单例bean以询问它们的类型,它必须完全依赖于bean定义中的信息。

In the case of ProxyFactoryBean , the type of the generated proxy is determined by complex logic that requires the bean to be fully initialized. ProxyFactoryBean的情况下,生成的代理的类型由复杂逻辑确定,该逻辑需要完全初始化bean。 Without that initialization, ProxyFactoryBean can only report the target type as null . 如果没有初始化, ProxyFactoryBean只能将目标类型报告为null

I can't say a way around this, other than using a singleton bean definition, or explicitly asking for the bean by name, eg 除了使用单例bean定义,或者通过名称明确要求bean,我不能说出这个方法,例如

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

and then: 然后:

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

Here, we use the convention of bean names being the interface they implement. 在这里,我们使用bean名称的约定作为它们实现的接口。

It looks like the scope of proxies created by ProxyFactoryBean should be specified using singleton property instead of scope attribute: 看起来应该使用singleton属性而不是scope属性来指定ProxyFactoryBean创建的代理scope

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

This solved the problem when target bean is inner. 这解决了目标bean内部时的问题。

When you have several top-level beans of the same class, you can use a type-safe lookup by id: 如果您有多个同一类的顶级bean,则可以使用id进行类型安全查找:

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

Can't you make my.Interface foo = ctx.getBean(my.Bean.class); 你不能让my.Interface foo = ctx.getBean(my.Bean.class); ?

As Spring works with Interfaces, in the context of aop, you could define different set of interfaces and request the one you expect. 当Spring使用Interfaces时,在aop的上下文中,您可以定义不同的接口集并请求您期望的接口。 This way no cast will be needed to a real class but Spring will manage interfaces. 这样就不需要对真正的类进行强制转换,但Spring会管理接口。

Let's say you have Class A implements B. You want to cast A to B but it is refused as A is a proxy due to aop. 假设您有A类实现B.您想要将A转换为B但是它被拒绝,因为A是aop的代理。 Then make A implements C and C extends B. C owns needed methods, and C is private interface accessed only from your implementation code. 然后使A实现C和C扩展B. C拥有所需的方法,C是仅从您的实现代码访问的专用接口。 Finally ask spring to inject either B or C depending on your expectations. 最后请求spring根据您的期望注入B或C.

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

This way, even if real class is a proxy, it implements your Private Interface with all what your need. 这样,即使真正的类是代理,它也可以根据您的需要实现您的私有接口。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM