Scala:围绕advice或Python装饰器实现Java的AspectJ

2024-06-28 20:16:41 发布

您现在位置:Python中文网/ 问答频道 /正文

在我的创业过程中,我一直在大量使用Java+AspectJ。我很想切换到Scala,但我有一个共同的设计模式,我不确定在Scala中实现的最佳方式。在

大量的应用程序使用AspectJ切入点,使用注释作为标记。 这与Python的decorator和blogged about it here非常相似。在

我尝试过在Scala中使用这种技术,但是在AspectJ + Scala上遇到了问题。 即使我真的让它工作了,它看起来像unScala。在

我看到一些项目做了一些所谓的关闭魔术(我认为这是他们正在做的)。在

替换@Transaction的示例:

transaction {
// code in here.
}

我不得不说,虽然我更喜欢注释,因为它看起来更具声明性。 Scala声明性地“装饰”代码块的方式是什么?


Tags: 标记应用程序声明here过程方式设计模式decorator
3条回答

与注释相比,使用事务方法方法还有其他优点。您可以添加catch和finally子句以确保正确的资源清理。把金的例子再延伸一点:

def transaction(f: =>Unit) = {
  println("start transaction")
  try {
    f
    println("end successful transaction")
  } catch {
    case ex => 
      // rollback?
      println("end failed transaction")
  } finally {
      // cleanup?
      println("end cleanup")
  }      
}

transaction {
  println("inside transaction")
}

您还可以在方法体内部调用事务,而不能对方法内部的块进行注释。当然,您可以使用注释对内部块进行另一个方法调用。在

从我的Java时代起,我就知道注释和XML配置文件的吸引力,但是现在,我更喜欢把所有东西都写成“普通”代码,因为它具有统一性和更大的表达能力。我只在调用需要注释的Java库时使用注释。另外,如果你让你的代码尽可能的“功能化”,那么一切都是声明性的!;)

顺便说一下,我在Scala Days 2011 on the same topic做一个演讲。核心思想和金和迪安的例子是一样的。然而,当涉及到所有横切关注点时,相似性和差异性变得更加微妙。在

在这个范围的一端,并没有真正的横切关注点,比如缓存。当宿主语言不支持高阶函数(例如Java)时,将关注点作为一个方面来实现就变得很有吸引力了。例如,使用AspectJ和annotation方法,可以说:

    @Cacheable(keyScript="#account.id")
    public double getNetWorth(Account account) {
       ... expensive computation
    }

但是使用Scala中的高阶函数,您可以:

^{pr2}$

Scala方法要好得多,因为:

  • 缓存不太可能广泛应用。例如,类中的所有方法或包中所有类中的所有公共方法都不可能是可缓存的。即使存在这样的情况,keyScript也不太可能是相同的,也不太容易以泛型形式表达。在
  • AspectJ方法使用注释作为支柱来提供一个像样的实现。利用Scala中的高阶函数,直接表达意图。在
  • AspectJ方法需要使用外部语言(例如OGNL或Spring表达式语言)来计算密钥。使用Scala,您只需使用宿主语言。在

在中间中,存在常见的横切关注点事务管理和安全性。从表面上看,它们看起来很像缓存。然而,我们在实践中发现,将这些功能应用于一个类的所有方法(使用泛型子选择,例如具有公共访问权限的那些方法)或所有类的所有方法(例如@Service)是很常见的。如果是这样的话,AspectJ方法最终会更出色,因为它提供了一种在比高阶函数更高的级别上应用功能的方法。您不再需要用transactional {}secured {}包围每个方法,这时类级别的注释就可以了。对于类似安全性的问题,AspectJ方法允许以更简单的方式执行安全审核。在

在另一端,是横切关注点,如跟踪、分析、监视、策略执行、审计、某些形式的并发控制(如Swing的/SWT/Android UI线程调度)等。这些都很适合由切入点选择(有注释,也经常不带注释)。单独使用高阶函数很难以一致的方式实现相同的结果。在

语义上有更多的细微差别,但底线是,当您发现注释每个方法以应用横切关注点时,高阶函数可能是一种更好的方法。对于其他人来说,将Scala与AspectJ结合使用可能会提供一致且紧凑的解决方案。在

另外,我最近没有在Eclipse中尝试过AspectJ+Scala(因为Eclipse中的Scala最近才开始工作)。但是在修复http://lampsvn.epfl.ch/trac/scala/ticket/4214之后,使用Maven的外部构建工作得很好。在

scala的方式应该是

def transaction(f: =>Unit) = {
  println("start transaction")
  f
  println("end transaction")
}

transaction {
  println("inside transaction")
}

这个指纹

^{pr2}$

相关问题 更多 >