问题描述
在AspectJ中使用虫洞模式,有没有办法在虫洞通知中看到执行方法名称?
Using the wormhole pattern with AspectJ, is there a way that the executing method name can be seen in the wormhole advice?
我有一个示例,其中服务类 (ClientService) 调用域类 (Client) 上的 getter.我想要的是在通知中知道调用getter的服务方法的名称.我看到服务对象本身没有问题,但我需要服务方法的名称.
I have an example where a service class (ClientService) calls getters on a domain class (Client). What I want, is to know in the advice to know the name of service method that called the getter.I have no problem seeing the service object itself, but I need the name of the service method.
这是我的方面:
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
推荐答案
客户:
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()
code> 而不是 this()
.
Here you need to change pointcut modelGetter
to use call()
instead of execution()
and target()
instead of 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
更新: 好吧,实际上如果客户端服务直接调用客户端,则不需要使用虫洞模式.只有在调用链较长(其他类或方法调用介于两者之间)时才应使用后者.在这种情况下,我的示例代码将失败,因为 thisEnclosureJoinPointStaticPart
将始终捕获客户端方法调用之外的调用链中的最后一个调用者,不一定是您感兴趣的控制流开头的客户端服务入口点因此,我更新了示例代码以显示更通用的解决方案:
Update: Well, actually if the client service directly calls the client you do not need to use a wormhole pattern. The latter should only be used if the call chain is longer (other classes or method calls in between). In that case my sample code would fail because thisEnclosingJoinPointStaticPart
would always capture the last caller in the call chain outside the client method call, not necessarily the client service entry point at the beginning of the control flow you are interested in. Thus, I have updated the sample code to show a more generic solution:
客户:同上
新的客户端委托(引入一些间接性):
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();
}
}
更新的方面:
方面现在不再是单例,而是使用 percflow()
实例化.它还为客户端服务控制流提供了一个额外的 before()
建议,将其连接点上下文保存在私有成员 serviceContext
中.这是稍后需要的,以便将信息打印到控制台.
The aspect now is not a sigleton anymore, but uses percflow()
instantiation. It also comes with an extra before()
advice for the client service control flow, saving its join point context in private member serviceContext
. This is needed later in order to print the information to the console.
在 around()
建议中,我也从 call()
切换回 execution()
和 target()
到 this()
因为现在我们不再使用 thisEnclosureJoinPointStaticPart
了.
In the around()
advice I also switched back from call()
to execution()
and from target()
to this()
because now we do not use thisEnclosingJoinPointStaticPart
anymore.
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
这篇关于虫洞图案 w.AspectJ:如何获取调用方方法名称?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!