客户:
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();
}
}
更新方面:
方面现在不再是单例,而是使用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