【问题标题】:Wormhole pattern w. AspectJ: How to get caller method name?虫洞模式 w。 AspectJ:如何获取调用方方法名称?
【发布时间】:2014-07-30 15:34:46
【问题描述】:

在 AspectJ 中使用虫洞模式,有没有一种方法可以在虫洞通知中看到正在执行的方法名称?

我有一个示例,其中服务类 (ClientService) 调用域类 (Client) 上的 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

【问题讨论】:

    标签: aop aspectj


    【解决方案1】:

    客户:

    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
    

    【讨论】:

    • 请注意:我已经用更通用的解决方案大量更新了答案,该解决方案适用于涉及间接的真实虫洞场景。
    • 太棒了!你的更新做到了:这正是我需要的。
    【解决方案2】:

    静态连接点信息 (thisJoinPointStaticPart) 应包含正确的方法名称。但我相信只有当modelGetter设置为call而不是execution时才会发生这种情况

    https://www.eclipse.org/aspectj/doc/next/runtime-api/org/aspectj/lang/JoinPoint.StaticPart.html

    【讨论】:

      猜你喜欢
      • 2012-08-21
      • 1970-01-01
      • 2013-07-07
      • 2011-10-27
      • 2011-07-03
      • 1970-01-01
      • 2014-07-11
      • 2019-01-21
      • 1970-01-01
      相关资源
      最近更新 更多