虫洞图案w。 AspectJ:如何获取调用方法名称?

时间:2014-07-30 15:34:47

标签: aspectj

在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

2 个答案:

答案 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