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

发布于 2024-09-15 22:46:07 字数 1263 浏览 2 评论 0原文

我在 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之前的世界中,我像在Spring 3中一样使用它

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

,可以进行类型安全查找,例如:

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 查找,如果是的话 - 如何?

I have a bean definition in Spring and it's proxy counterpart which is meant to be used everywhere:

<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

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, e.g.:

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. I have tried to inline my.BeanTarget (as shown in Spring documentation) to make it hidden, but all I got was

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

好菇凉咱不稀罕他 2024-09-22 22:46:07

这里的问题是 ProxyFactoryBean 上的 scope="prototype"

上下文只会急切地初始化单例 bean 定义。非单例范围的 Bean 仅在需要时才进行初始化。这意味着当您向上下文请求给定类型的 bean 时,上下文无法初始化这些非单例 bean 来询问它们的类型,它必须纯粹依赖 bean 定义中的信息。

对于ProxyFactoryBean,生成的代理的类型由需要完全初始化bean 的复杂逻辑决定。如果没有该初始化,ProxyFactoryBean 只能将目标类型报告为 null

除了使用单例 bean 定义,或者通过名称显式询问 bean 之外,我无法解决这个问题,例如

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

然后:

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

在这里,我们使用 bean 名称的约定作为它们实现的接口。

The problem here is the scope="prototype" on your ProxyFactoryBean.

The context will only eagerly-initialize singleton bean definitions. 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.

In the case of ProxyFactoryBean, the type of the generated proxy is determined by complex logic that requires the bean to be fully initialized. Without that initialization, ProxyFactoryBean can only report the target type as null.

I can't say a way around this, other than using a singleton bean definition, or explicitly asking for the bean by name, e.g.

<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.

就是爱搞怪 2024-09-22 22:46:07

看起来应该使用 singleton 属性而不是 scope 属性指定由 ProxyFactoryBean 创建的代理范围:

<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); 

It looks like the scope of proxies created by ProxyFactoryBean should be specified using singleton property instead of scope attribute:

<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.

When you have several top-level beans of the same class, you can use a type-safe lookup by id:

my.Interface foo = ctx.getBean("my.Bean", my.Interface.class); 
千纸鹤带着心事 2024-09-22 22:46:07

你不能制作 my.Interface foo = ctx.getBean(my.Bean.class); 吗?

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

想你只要分分秒秒 2024-09-22 22:46:07

由于 Spring 使用接口,在 aop 的上下文中,您可以定义一组不同的接口并请求您期望的接口。这样就不需要对真实类进行强制转换,但 Spring 将管理接口。

假设你有一个类 A 实现了 B。你想将 A 强制转换为 B,但它被拒绝了,因为 A 是 aop 的代理。
然后让 A 实现 C,C 扩展 B。C 拥有所需的方法,而 C 是只能从您的实现代码访问的私有接口。
最后让 spring 根据您的期望注入 B 或 C。

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

这样,即使真实的类是代理,它也可以根据您的需要实现您的私有接口。

As Spring works with Interfaces, in the context of aop, you could define different set of interfaces and request the one you expect. This way no cast will be needed to a real class but Spring will manage interfaces.

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.
Then make A implements C and C extends B. C owns needed methods, and C is private interface accessed only from your implementation code.
Finally ask spring to inject either B or C depending on your expectations.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文