Spring AOP方面未在线程中触发 [英] Spring AOP aspect not triggered in thread

查看:55
本文介绍了Spring AOP方面未在线程中触发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在线程运行之前调用的每个方法都可以正常工作,但是在启动线程之后不会进入方面.

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>

创建豆:

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 {@Overridepublic void run(){
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.

出租车对象内部的修改

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.

有一些解决方法:

  1. 代替动态代理使用完整的AspectJ-然后编织将直接位于您的出租车代码中,而不是周围的代理人.
  2. 而不是从cab的run()方法内部调用this.setMeter(),而是在某处保留对代理的引用,然后调用proxy.setMeter().

这篇关于Spring AOP方面未在线程中触发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆