使用连接点调用(* *.*(..)),我可以将参数公开给建议(如果可用)吗?

发布于 2024-07-11 15:05:25 字数 1289 浏览 12 评论 0原文

在我的方面,我通过建议对 java.util.Set 实例的某些方法调用来跟踪某些集合的更改,特别是 add(Object)remove(对象)。 由于更改不会反映在集合本身中,因此调用 Set.contains(Object)Set.size() 将返回错误结果。

因此,我想拦截对 Set 实例的所有方法调用(addremove 除外),并将调用转发到我的最新集合。

当然,我可以使用不同的切入点定义两个建议,如下所示:

// matches Collection.size(), Collection.isEmpty(), ...
* around(Collection c) : call(* Collection.*()) && target(c)
            && !remove(/*...*/) && !add(/*...*/) {
    if (notApplicable())
        return proceed(c);

    return proceed(getUpToDateCollection());
}

// matches Collection.contains(Object), ...
* around(Collection c, Object arg) : call(* Collection.*(*)) && target(c) && args(arg) 
            && !remove(/*...*/) && !add(/*...*/) {
    if (notApplicable())
        return proceed(c, arg);

    return proceed(getUpToDateCollection(), arg);
}

它有效,但非常丑陋,我的建议的主体非常相似。 所以我想把它们“结合”起来; 有效地为两个切入点编织一个单一的建议,就像这样:

* around(Object[] args): call(* Collection.*(..)) && args(arr) {...}`

这可能吗? 我感觉不是,因为在一个切入点中我公开了参数(然后在建议中使用它),而在另一个切入点中没有参数,所以似乎不可能在封闭的建议中绑定“潜在标识符” ...但我希望我忽略了一些事情,你也许能够为我指明正确的方向。 谢谢!

With my aspect, I track the changes on certain collections by advising certain method calls on instances of java.util.Set, notably add(Object) and remove(Object). Since the changes are not reflected in the collection itself, invocations of Set.contains(Object) or Set.size() return wrong results.

Therefore I want to intercept all method calls to instances of Set (except add and remove), and forward the calls to my up-to-date collection.

Of course I could define two advices, using different pointcuts, something like this:

// matches Collection.size(), Collection.isEmpty(), ...
* around(Collection c) : call(* Collection.*()) && target(c)
            && !remove(/*...*/) && !add(/*...*/) {
    if (notApplicable())
        return proceed(c);

    return proceed(getUpToDateCollection());
}

// matches Collection.contains(Object), ...
* around(Collection c, Object arg) : call(* Collection.*(*)) && target(c) && args(arg) 
            && !remove(/*...*/) && !add(/*...*/) {
    if (notApplicable())
        return proceed(c, arg);

    return proceed(getUpToDateCollection(), arg);
}

It works, but it's pretty ugly, the bodies of my advices being quite analogous. So I would like to "combine" them; effectively having a single advice that be woven for both pointcuts, much like this:

* around(Object[] args): call(* Collection.*(..)) && args(arr) {...}`

Is this possible at all? I have the feeling it's not, because in one of the pointcuts I expose the argument (and subsequently use it in the advice) and in the other there is no argument, so it seems impossible to bind the "potential identifier" in the enclosing advice... But I'm hoping that I've overlooked something and you might be able to point me in the right direction. Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

如梦初醒的夏天 2024-07-18 15:05:25

仅供记录。
可以编写一个公开参数的切入点,然后在不访问这些参数参数的通知中使用此切入点。 我总是更喜欢显式定义切入点,而不是立即将切入点表达式写入建议定义中,仅通过切入点的名称(和参数)从建议中引用它

just for the record.
it is possible to write a pointcut which exposes an argument, and then use this pointcut in advice which doesn't access these argument parameter. Instead of writing the pointcut expression immediately into the advice definition, I'd allways prefer to define the pointcut explicitly, referring to it from the advice just by the pointcut's name (and arguments)

我不知道为什么这个问题在我的提要中作为“新”这么多年出现,但它仍然没有答案,所以我会回答:

  • 你的假设是正确的,你不能使用args() 为了绑定一个不存在的参数。
  • 如果您绝对想要一个建议正文,则可以使用 JoinPoint.getArgs(..) ,但它会很难看(如涉及循环和强制转换),并且可能比使用两个切入点慢。 如果做得错误,太宽的切入点也可能会匹配太多的连接点。
  • 我的建议(没有双关语)实际上是将重复的代码分解到辅助方法中,并从两个 AspectJ 建议中调用这些代码。 也许这些辅助方法还需要一个 ProceedingJoinPoint 参数,以便在您还想提取该部分时调用 proceed() 。 但也要考虑可读性。 这始终取决于您的具体情况。

如果您的代码实际上有点SSCCE,我可以以更具体的方式(使用方面代码)回答。

I have no idea why this question has popped up in my feed as "new" after so many years, but it is still unanswered, so I will answer:

  • Your assumption is correct, you cannot use args() in order to bind a non-existent argument.
  • You could, if you absolutely want to have a single advice body, use JoinPoint.getArgs(..), but it would be ugly (as in involving loops and casts) and potentially slower than having two pointcuts. A too broad pointcut would also potentially match too many joinpoints if done wrong.
  • My advice - no pun intended - is to actually factor out duplicate code into helper methods and call those from both AspectJ advices. Maybe those helper methods also need a ProceedingJoinPoint parameter in order to call proceed() upon it if you also want to factor out that part. But think about readability, too. It always depends on your concrete case.

I could answer in a more concrete way (with aspect code) if your code was actually a litte SSCCE.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文