gpt4 book ai didi

multithreading - Spring AOP 方面未在线程中触发

转载 作者:行者123 更新时间:2023-12-03 13:00:43 34 4
gpt4 key购买 nike

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

我正在使用实现接口(interface)的 JDK 动态代理对象,
所有从其他线程而不是从对象本身调用的公共(public)方法。

我正在使用 Spring 3.0.6。

请帮助我了解我所缺少的。

方面:

@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());
}
}

Spring 配置:
<?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() 函数,并且没有其他任何内容按方面打印。我正在修改现有项目,所有线程都在运行,我可以看到线程的输出,与方面的实现无关
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 在他的回答中所描述的那样。当线程运行时,它会通知调用者并传递 self 实例。以下所有调用都是在此实例上直接绕过代理执行的。

公共(public)类 CabImpl 实现 ICab {
@覆盖
公共(public)无效运行(){
mStationListener.onCabReady(this);
}
}

解决方案

因为我有多个地方通过事件传递原始对象的实例,所以快速的解决方案是将对代理对象的引用存储在实例中并发送它。但更正确的解决方案是使用 AspectJ,这将阐明不必要的代码修改和依赖关系。

cab 对象内部的修改
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 接口(interface),并且您正在使用 Cab 创建一个线程并启动该线程。

我假设 Cab 中的 run 方法正在调用 Cab 公开的其他方法,如果是这种情况,那么它将完全绕过动态代理,您会看到这种行为。

例如。如果客户端(不是 Cab)调用 setMeter,则调用流程为:

client->CabDynamicProxy.setMeter()->cab.setMeter();

现在考虑 Cab 本身通过它的另一个方法调用 setMeter 的情况(在这种情况下为 run()):
Thread.start()->CabDynamicProxy.run()->cab.run()->cab.setMeter();
this from cab.run() 不会解析为动态代理,而是解析为实际的 cab 本身,因此完全绕过方面。

有一些解决方法:
  • 而不是动态代理使用完整的 AspectJ - 然后编织将
    直接在您的 Cab 代码中,而不是它周围的代理。
  • 不要在 cab 的 run() 方法中调用 this.setMeter(),而是在某处保留对代理的引用,然后调用 proxy.setMeter()。
  • 关于multithreading - Spring AOP 方面未在线程中触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11495320/

    34 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com