Scala:围绕建议或 Python 装饰器实现 Java 的 AspectJ
我在创业过程中广泛使用了 Java + AspectJ。我很想切换到 Scala,但我有一个通用的设计模式,我不确定在 Scala 中实现的最佳方式。
我们的应用程序大量使用 AspectJ 切入点,并使用注释作为标记。 这与 Python 的装饰器非常相似,博客介绍了在这里。
我曾尝试在 Scala 中执行此技术,但遇到问题 AspectJ + Scala< /a>. 即使我确实让它工作了,它看起来也不像 Scala。
我见过一些项目做了一些按名称调用关闭魔法(我认为这就是他们正在做的)。
替换 @Transaction 的示例:
transaction {
// code in here.
}
我不得不说,虽然我更喜欢注释,因为它看起来更具声明性。 Scala 声明式“装饰”代码块的方式是什么?
I have been using Java + AspectJ extensively for my startup. I would love to switch to Scala but I have a common design pattern that I am not sure entirely the best way to implement in Scala.
A tremendous amount of our application uses AspectJ pointcuts using annotations as the marker.
This is very similar to Python's decorator and blogged about it here.
I have tried doing this technique in Scala but had problems with AspectJ + Scala.
Even if I did get it to work it seems unScala like.
I have seen some projects do some call-by-name closure magic (I think thats what they are doing).
Example of a replace of @Transaction:
transaction {
// code in here.
}
I have to say though I prefer the annotation more as it seems more declarative.
What is the Scala way of declaratively "decorating" code blocks?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
顺便说一句,我将在 Scala Days 2011 上就同一主题发表演讲。核心思想与 Kim 和 Dean 的例子相同。然而,当涉及到全方位的横切关注点时,相似性和差异性就变得更加微妙。
一方面,存在一些并非真正交叉的问题,例如缓存。当宿主语言不支持高阶函数(例如 Java)时,将关注点实现为一个方面就变得很有吸引力。例如,使用 AspectJ 和注释方法,您可以说:
但是使用 Scala 中的高阶函数,您可以这样做:
Scala 方法要好得多,因为:
keyScript
也不太可能相同或容易以通用形式表达。中间,存在常见的横切关注点事务管理和安全性。从表面上看,它们看起来很像缓存。然而,我们在实践中发现,将这些功能应用于类的所有方法(具有通用子选择,例如具有公共访问权限的方法)或用注释标记的所有类的所有方法(例如
@Service
)很常见。如果是这种情况,AspectJ 方法最终会更优越,因为它提供了一种在比高阶函数更高级别应用功能的方法。当类级注释就可以正常工作时,您不再需要用事务性{}
或安全{}
包围每个方法。对于类似安全的问题,AspectJ 方法提供了一种更简单的方法来执行安全审计。另一端是横切关注点,例如跟踪、分析、监控、策略执行、审计、某些形式的并发控制(例如 Swing 的/SWT/Android UI 线程调度)等。这些非常适合由切入点选择(带注释,通常不带注释)。仅使用高阶函数很难以一致的方式执行相同的操作。
还有更多语义上的细微差别,但最重要的是,当您发现注释每个方法以应用横切关注点时,高阶函数可能是更好的方法。对于其他人来说,将 Scala 与 AspectJ 结合使用可能会提供一致且紧凑的解决方案。
ps 我最近没有在 Eclipse 中尝试过 AspectJ+Scala(因为 Eclipse 中的 Scala 最近才开始工作)。但使用 Maven 的外部构建在 http://lampsvn.epfl.ch/trac/scala 之后工作正常/ticket/4214 已修复。
Incidentally, I am giving a talk at Scala Days 2011 on the same topic. The core idea is the same as Kim's and Dean's example. However, when it comes to the full spectrum of crosscutting concerns, similarity and differences become more nuanced.
On one end of the spectrum, there are not-really-crosscutting concerns such as caching. When the host language doesn't support higher-order functions (for example, Java), implementing the concern as an aspect becomes attractive. For example, with AspectJ and annotation approach, you can say:
But with higher-order function in Scala, you can do:
The Scala approach is much better, because:
keyScript
is unlikely to be the same or easily expressible in a generic form.In the middle, there are common crosscutting concerns transaction management and security. On the surface, they look much like caching. However, we find in practice that applying these functionalities to all methods of a class (with generic sub-selection such as those with public access) or all methods of all classes marked with an annotation (say
@Service
) is common. If such is the case, the AspectJ approach ends up being superior, since it provides a way to apply the functionality at a higher level that higher-order functions. You no longer have to surround each and every method withtransactional {}
orsecured {}
, when a class-level annotation will do just fine. For security-like concerns, AspectJ approach allows an easier way to perform security auditing.On the other end of the spectrum are crosscutting concerns such as tracing, profiling, monitoring, policy enforcement, auditing, some forms of concurrency control (such as Swing's/SWT/Android UI thread dispatching), etc. These lend themselves very well to be selected by a pointcut (with and often without annotations). It is very difficult to do the same in a consistent manner using higher-order functions alone.
There are more semantic nuances, but the bottom line is that when you find annotating every method to have a crosscutting concern applied, higher-order function is likely to be a better approach. For others, using Scala with AspectJ is likely to provide consistent and compact solution.
p.s. I haven't tried AspectJ+Scala in Eclipse lately (since Scala in Eclipse started to work only recently). But external build using Maven worked fine after http://lampsvn.epfl.ch/trac/scala/ticket/4214 was fixed.
scala 方式是
这样打印
The scala way would be
This prints
与注释相比,使用事务方法方法还有其他优点。您可以添加 catch 和finally 子句以确保正确的资源清理。稍微扩展 Kim 的示例:
您还可以调用方法体内的事务,但不能注释方法内部的块。当然,您可以使用注释将该内部块设置为另一个方法调用。
从我的 Java 时代起,我就了解注释和 XML 配置文件的吸引力,但现在,我更喜欢将所有内容编写为“正常”代码,因为这样具有一致性和更强的表达能力。我仅在调用需要注释的 Java 库时才使用注释。另外,如果您使代码尽可能“功能化”,那么一切都是声明性的! ;)
There are other advantages with using the transaction method approach vs. annotations. You can add catch and finally clauses to ensure proper resource cleanup. To extend Kim's example a bit:
You can also make calls to transaction inside method bodies, whereas you can't annotate a block internal to a method. Of course, you could just make that internal block another method call with an annotation.
I understand the attraction of annotations, and XML configuration files for that matter, from my Java days, but these days, I prefer having everything written as "normal" code, because of the uniformity and greater expressive power. I only use annotations when I'm calling a Java library that requires them. Also, if you make your code as "functional" as possible, then everything is declarative! ;)