在AspectJ中使用虫洞模式,是否可以在虫洞建议中看到执行方法名称?
我有一个示例,其中服务类(ClientService)在域类(客户端)上调用getter。我想要的是在建议中知道调用getter的服务方法的名称。 我没有看到服务对象本身的问题,但我需要服务方法的名称。
这是我的方面:
public aspect MyAspect {
pointcut serviceExecution(ClientService srv) : execution(* ClientService.*(..)) && this(srv);
pointcut modelGetter(Client client) : execution(public * Client.get*()) && this(client);
pointcut wormhole(ClientService srv, Client client) : cflow(serviceExecution(srv)) && modelGetter(client);
Object around(ClientService srv, Client client) : wormhole(srv, client) {
// what is the name of the service-method calling?
Object ret = proceed(srv, client);
return ret;
}
}
这可能吗?
由于
-J
答案 0 :(得分:4)
<强>客户端:强>
package de.scrum_master.app;
public class Client {
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
客户服务包括样本主要方法:
package de.scrum_master.app;
public class ClientService {
private Client client;
public ClientService(Client client) { this.client = client; }
public String getSomething() { return client.getName(); }
public void setSomething(String something) { client.setName(something); }
public static void main(String[] args) {
ClientService clientService = new ClientService(new Client());
clientService.setSomething("new value");
clientService.getSomething();
}
}
<强>方面:强>
在这里,您需要将切入点modelGetter
更改为使用call()
而不是execution()
和target()
而不是this()
。
package de.scrum_master.aspect;
import de.scrum_master.app.Client;
import de.scrum_master.app.ClientService;
public aspect MyAspect {
pointcut serviceExecution(ClientService srv) :
execution(* ClientService.*(..)) && this(srv);
pointcut modelGetter(Client client) :
call(public * Client.get*()) && target(client);
pointcut wormhole(ClientService srv, Client client) :
cflow(serviceExecution(srv)) && modelGetter(client);
Object around(ClientService srv, Client client) : wormhole(srv, client) {
System.out.println("Caller: " + thisEnclosingJoinPointStaticPart.getSignature().toShortString() + " -> " + srv);
System.out.println("Callee: " + thisJoinPointStaticPart.getSignature().toShortString() + " -> " + client);
return proceed(srv, client);
}
}
控制台输出:
Caller: ClientService.getSomething() -> de.scrum_master.app.ClientService@72bcecc0
Callee: Client.getName() -> de.scrum_master.app.Client@515b6c19
更新:嗯,实际上,如果客户端服务直接调用客户端,则不需要使用虫洞模式。后者只应在调用链较长时使用(其他类或方法调用)。在这种情况下,我的示例代码将失败,因为thisEnclosingJoinPointStaticPart
总是捕获客户端方法调用之外的调用链中的最后一个调用者,而不一定是您感兴趣的控制流开始时的客户端服务入口点。 ,我更新了示例代码以显示更通用的解决方案:
客户:与上述相同
新客户委托(介绍一些间接):
package de.scrum_master.app;
public class ClientDelegate {
private Client client;
public ClientDelegate(Client client) { this.client = client; }
public String getName() { return client.getName(); }
public void setName(String name) { client.setName(name); }
}
使用委托更新了客户服务:
package de.scrum_master.app;
public class ClientService {
private ClientDelegate clientDelegate;
public ClientService(ClientDelegate clientDelegate) { this.clientDelegate = clientDelegate; }
public String getSomething() { return clientDelegate.getName(); }
public void setSomething(String something) { clientDelegate.setName(something); }
public static void main(String[] args) {
ClientService clientService = new ClientService(new ClientDelegate(new Client()));
clientService.setSomething("new value");
clientService.getSomething();
}
}
更新了方面:
现在方面不再是一个sigleton,而是使用percflow()
实例化。它还为客户端服务控制流提供了额外的before()
建议,并将其连接点上下文保存在私有成员serviceContext
中。稍后需要这样才能将信息打印到控制台。
在around()
建议中,我也从call()
切换回execution()
,从target()
切换回this()
,因为现在我们不使用thisEnclosingJoinPointStaticPart
不再。
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint.StaticPart;
import de.scrum_master.app.Client;
import de.scrum_master.app.ClientService;
public aspect MyAspect percflow(serviceExecution(ClientService)) {
private StaticPart serviceContext;
pointcut serviceExecution(ClientService srv) :
execution(* ClientService.*(..)) && this(srv);
pointcut modelGetter(Client client) :
execution(public * Client.get*()) && this(client);
pointcut wormhole(ClientService srv, Client client) :
cflow(serviceExecution(srv)) && modelGetter(client);
before(ClientService srv) : serviceExecution(srv) {
serviceContext = thisJoinPointStaticPart;
}
Object around(ClientService srv, Client client) : wormhole(srv, client) {
System.out.println("Service: " + serviceContext.getSignature().toShortString() + " -> " + srv);
System.out.println("Client: " + thisJoinPointStaticPart.getSignature().toShortString() + " -> " + client);
return proceed(srv, client);
}
}
新的控制台输出:
Service: ClientService.getSomething() -> de.scrum_master.app.ClientService@4cc4dfc5
Client: Client.getName() -> de.scrum_master.app.Client@113f25e3
答案 1 :(得分:0)
静态连接点信息(thisJoinPointStaticPart
)应包含正确的方法名称。但我相信只有当modelGetter设置为call
而不是execution
https://www.eclipse.org/aspectj/doc/next/runtime-api/org/aspectj/lang/JoinPoint.StaticPart.html