假设我们有两个bean,在Spring中定义
<bean class="foo.A"/>
<bean class="foo.B"/>
public class A {
@Autowired
private B b;
}
public class B {
public void foo() {
...
}
}
我想要实现的是拦截对B.foo()
的所有调用。查看文档,我编写了拦截器C
并更改了bean B
的定义,如下所示:
public class C implements org.springframework.aop.MethodBeforeAdvice {
public void before(final Method method, final Object[] args, final Object target) {
// interception logic goes here
}
}
<bean class="foo.C"/>
<bean class="org.springframework.aop.framework.ProxyFactoryBean" scope="prototype">
<property name="proxyTargetClass" value="true"/>
<property name="singleton" value="false"/>
<property name="target">
<bean class="foo.B" scope="prototype"/>
</property>
<property name="interceptorNames">
<list>
<value>foo.C</value>
</list>
</property>
</bean>
问题:启动时,Spring容器会抱怨:找不到匹配的[foo.B]类型的匹配bean:预计至少有一个bean可以作为此依赖项的autowire候选者。换句话说,它无法将B
注入A
,因为B
隐藏在 org.springframework.aop.framework.ProxyFactoryBean 之后,不再“自动” “得到认可。如果我将定义替换为简单的class=foo.B
,容器就可以正常启动了。解决这个问题的最佳方法是什么?
加分问题:是否可以在不涉及B.foo()
且仅使用注释(最好不涉及ProxyFactoryBean
)的情况下实施<aop:...
的拦截?< / p>
答案 0 :(得分:5)
为foo.B
定义一个界面(例如foo.BInterface
)并在A类中使用foo.BInterface
。
还要注意Autowired
注射只进行一次。因此,如果foo.A
是单身,它只会收到第一个创建的foo.B
实例,而您希望它是原型。
回答奖金:是的,但可能会更复杂。作为一种可能的解决方案,您可以实施BeanPostProcessor
。在实现中,您可以使用动态代理替换foo.B.所以基本上你也这样做,但不是使用<aop:
,而是使用基本的Spring功能自己做。再说一遍:你没有解决“原型不是自动装配”的问题,你还需要一个界面。
答案 1 :(得分:1)
也许您希望在ProxyFactoryBean
之外定义Bean'foo.B',并从目标属性中引用它。
<bean class="foo.C"/>
<bean id="fooB" class="foo.B" scope="prototype"/>
<bean class="org.springframework.aop.framework.ProxyFactoryBean" scope="prototype">
<property name="proxyTargetClass" value="true"/>
<property name="singleton" value="false"/>
<property name="target" ref="fooB"/>
<property name="interceptorNames">
<list>
<value>foo.C</value>
</list>
</property>
</bean>
答案 2 :(得分:0)
Tarlog的回答是正确的,但为了更清楚: 你应该通过他们的界面而不是他们的类来连接对象:
public class A {
@Autowired
private C b;
}
public class B implements C{
public void foo() {
...
}
}