Let's say we have two beans, defined in Spring
<bean class="foo.开发者_如何学JAVAA"/>
<bean class="foo.B"/>
public class A {
@Autowired
private B b;
}
public class B {
public void foo() {
...
}
}
What I want to achieve is the interception of all calls to B.foo()
. Looking at documentation, I wrote interceptor C
and changed the definition of bean B
as follows:
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>
Problem: when starting up, Spring container complains: No matching bean of type [foo.B] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. In other words, it can't inject B
into A
because B
is hidden behind org.springframework.aop.framework.ProxyFactoryBean and no longer "automagically" recognized. If I replace the definition into a simple class=foo.B
, container starts fine. What's the best way to solve this?
Bonus question: is it possible to implement interception of B.foo()
without involvement of ProxyFactoryBean
and only using annotations (preferably without involvement of <aop:...
)?
Define an interface for foo.B
(e.g. foo.BInterface
) and use foo.BInterface
in the class A.
Also pay attention that Autowired
injections are done only once. So if foo.A
is singleton, it will receive only the first created instance of foo.B
, while you want it to be a prototype.
Answer to bonus: Yes, but it may be more complicated. As a possible solution you can implement BeanPostProcessor
. In the implementation you can replace the foo.B with dynamic proxy. So basically you do the same, but instead of using <aop:
you do it yourself using basic Spring functionality. And again: you don't solve the "prototype is not autowired" problem and you still need an interface.
Perhaps you want to have the Bean 'foo.B' defined outside of the ProxyFactoryBean
, and refer to it from the target property.
<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>
Tarlog's answer is correct, but to make it more clear: you should wire objects by their interface, not by their class:
public class A {
@Autowired
private C b;
}
public class B implements C{
public void foo() {
...
}
}
精彩评论