Spring AOP 方面未在线程中触发 [英] Spring AOP aspect not triggered in thread
问题描述
在线程运行之前调用的每个方法都运行良好,但是在启动线程之后它不会进入方面.
Every method that called before thread is running, works good, but after starting a thread It doesn't enters aspect.
我正在使用实现接口的 JDK 动态代理对象,从其他线程调用的所有公共方法,而不是从对象本身调用.
I'm using JDK dynamic proxy objects that implements interface, all public methods called from other thread and not from object itself.
我使用的是 spring 3.0.6.
I'm using spring 3.0.6.
请帮助我了解我遗漏了什么.
Please help me to understand what I'm missing.
方面:
@Aspect
public class CabLoggingAspect {
public void init() {
System.out.println("CabLoggingAspect: init()");
}
@Pointcut("execution(* com.station.taxi.ICab.*(..))")
public void anyCall() { }
@Before("anyCall()")
public void logAnyCall(JoinPoint joinPoint) {
System.out.println("CabLoggingAspect: logAnyCall(): "+joinPoint.getSignature().getName());
}
}
弹簧配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<bean id="cab" class="com.station.taxi.Cab" scope="prototype" />
<aop:aspectj-autoproxy>
<aop:include name="cabLoggingAspect"/>
</aop:aspectj-autoproxy>
<!-- AspectJ -->
<bean id="cabLoggingAspect" class="com.station.taxi.aop.CabLoggingAspect" init-method="init"/>
</beans>
创建bean:
public ICab createCab(int num, String whileWaiting) {
Object o = mApplicationContext.getBean("cab", num, whileWaiting);
return (ICab)o;
}
运行线程:
// public interface ICab extends Runnable { ...
// ...
// initCabs.add(mContext.createCab(Integer.valueOf(cabNum), whileWaiting));
// ...
for(ICab cab: initCabs) {
cab.setMeter(createTaxiMeter());
cab.setStationEventListener(this);
mInitThreads.add(cab);
}
// ...
for(Runnable t: mInitThreads) {
new Thread(t).start();
}
输出:
CabLoggingAspect: init()
CabLoggingAspect: logAnyCall(): setMeter
CabLoggingAspect: logAnyCall(): setStationEventListener
CabLoggingAspect: logAnyCall(): setMeter
CabLoggingAspect: logAnyCall(): setStationEventListener
CabLoggingAspect: logAnyCall(): run
CabLoggingAspect: logAnyCall(): run
run() 函数被调用,方面没有打印任何其他内容.我正在修改现有项目,所有线程都在运行,我可以看到线程的输出,与方面的实现无关
run() function called and nothing else printed by aspect. I'm modifying existing project, all thread are running and I can see output from threads, not related to implementation of aspect
15/07/2012 23:19:05 Usjy - Passanger is ready and running...
15/07/2012 23:19:05 Usjy - Took cab starting transit
15/07/2012 23:19:06 MCMk - Passanger is ready and running...
15/07/2012 23:19:06 MCMk - Took cab starting transit
15/07/2012 23:19:08 Usjy - Arrived at TelAviv paid 5.8
15/07/2012 23:19:10 MCMk - Arrived at TelAviv paid 6.3
更新/解决方案
问题
正如 Biju Kunjummen 在他的回答中所描述的那样.当线程运行时,它会通知调用者并传递自身实例.以下所有调用均直接绕过代理在此实例上执行.
As described by Biju Kunjummen in his answer. When thread is running it notifies back to the caller and pass self instance. All following calls were executed on this instance directly bypassing proxy.
公共类 CabImpl 实现 ICab {@覆盖公共无效运行(){
mStationListener.onCabReady(this);}}
public class CabImpl implements ICab {
@Override
public void run() {
mStationListener.onCabReady(this);
}
}
解决方案
因为我有多个地方通过事件传递原始对象的实例,所以快速的解决方案是在实例中存储对代理对象的引用并发送它.但更正确的解决方案是使用AspectJ,这会说明不必要的代码修改和依赖.
Because I have multiple places where I pass the instance of the original object with event, the quick solution was to store reference to the proxy object inside instance and send it. But more correct solution is to use AspectJ, this will illuminate unnecessary code modification and dependencies.
cab 对象内部的修改
Modifications inside cab object
private ICab mAopProxy;
//...
public void setAopProxy(ICab proxy) {
mAopProxy = proxy;
}
@Override
public void run() {
mStationListener.onCabReady(mAopProxy);
//...
}
创建驾驶室
Advised advised = (Advised)mApplicationContext.getBean("cab", num, whileWaiting);
Cab cab = (Cab) advised.getTargetSource().getTarget();
cab.setAopProxy((ICab)advised);
推荐答案
我看到您的 Cab 实现了 Runnable 接口,您正在使用 Cab 创建一个线程并启动该线程.
I see that your Cab implements Runnable interface and you are creating a thread with Cab and starting up the thread.
我假设 Cab 中的 run 方法正在调用 Cab 公开的其他方法,如果是这种情况,那么它将完全绕过动态代理,您会看到这种行为.
I am assuming the run method in Cab is calling the other methods exposed by Cab, if that is the case then it would bypass the dynamic proxy completely and you would see this behavior.
例如.如果客户端(不是 Cab)调用 setMeter,则调用流程为:
For eg. if a client(not Cab) calls setMeter, then the call flow would be:
client->CabDynamicProxy.setMeter()->cab.setMeter();
现在考虑 Cab 本身通过其另一个方法(在本例中为 run())调用 setMeter 的情况:
Now consider the case of Cab itself calling setMeter through another of its methods(run() in this case):
Thread.start()->CabDynamicProxy.run()->cab.run()->cab.setMeter();
cab.run() 中的 this
不会解析为动态代理,而是解析为实际的 cab 本身,因此完全绕过方面.
The this
from cab.run() would resolve not to the dynamic proxy but to the actual cab itself and hence bypass aspects completely.
有一些解决方法:
- 使用完整的 AspectJ 代替动态代理 - 然后编织将直接在您的 Cab 代码中,而不是围绕它的代理.
- 不要在 cab 的 run() 方法内部调用 this.setMeter(),而是在某处保留对代理的引用,并调用 proxy.setMeter().
这篇关于Spring AOP 方面未在线程中触发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!