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

查看:38
本文介绍了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>

创建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.

有一些解决方法:

  1. 使用完整的 AspectJ 代替动态代理 - 然后编织将直接在您的 Cab 代码中,而不是围绕它的代理.
  2. 不要在 cab 的 run() 方法内部调用 this.setMeter(),而是在某处保留对代理的引用,并调用 proxy.setMeter().

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

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