Java ApplicationContext.getBean(Class clazz) 不适用于代理
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3574092/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ApplicationContext.getBean(Class clazz) doesn't go well with proxies
提问by mindas
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, e.g.:
在 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
. I have tried to inline my.BeanTarget
(as shown in Spring documentation) to make it hidden, but all I got was
同样,这对普通 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:
So is it possible to use type safe bean lookups with proxied beans and if yes - how?
那么是否可以对代理 bean 使用类型安全的 bean 查找,如果是,如何使用?
采纳答案by skaffman
The problem here is the scope="prototype"
on your ProxyFactoryBean
.
这里的问题是scope="prototype"
你的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.
上下文只会急切地初始化单例 bean 定义。非单例范围的 Bean 仅在被要求时才初始化。这意味着当您向上下文询问给定类型的 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. Without that initialization, ProxyFactoryBean
can only report the target type as null
.
在 的情况下ProxyFactoryBean
,生成的代理的类型由需要完全初始化 bean 的复杂逻辑决定。如果没有那个初始化,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, e.g.
除了使用单例 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 名称的约定作为它们实现的接口。
回答by Bozho
Can't you make my.Interface foo = ctx.getBean(my.Bean.class);
?
你不能做my.Interface foo = ctx.getBean(my.Bean.class);
吗?
回答by axtavt
It looks like the scope of proxies created by ProxyFactoryBean
should be specified using singleton
property instead of scope
attribute:
看起来ProxyFactoryBean
应该使用singleton
属性而不是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);
回答by Cyrille Cormier
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.
由于 Spring 与接口一起工作,因此在 aop 的上下文中,您可以定义不同的接口集并请求您期望的接口。这样就不需要对真正的类进行强制转换,但 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. 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.
假设您有 A 类实现 B。您想将 A 强制转换为 B,但由于 AOP,A 是代理而被拒绝。然后使 A 实现 C,C 扩展 B。C 拥有所需的方法,而 C 是只能从您的实现代码访问的私有接口。最后让 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.
这样,即使真正的类是代理,它也会根据您的需要实现您的私有接口。