技术开发 频道

Groovy综述:增强的依赖管理与语言支持

  【IT168 文档】近日Groovy 1.7发布了,该版本对语言本身进行了优化,同时增强了程序库。随后,SpringSource又发布了Groovy Eclipse IDE 2.0,增强了对Groovy的支持,提供了调试、更棒的内容辅助以及强大的编辑功能,此举弥补了之前Eclipse对Groovy差劲的支持。此次发布对Groovy语言本身和程序库都进行了大量的更新。Java使用了匿名内部类,而其他语言则使用了闭包或是方法委托,Groovy就是其中之一。凭借这些新特性,Groovy可以轻松集成Java中使用了匿名内部类的程序库(如果使用闭包的话则无法实现)。相比于每个匿名内部类都要对应一个类的做法来说,这种方式是个极大的改进,同时也使得代码的可读性更好。但官方警告说,从严格意义上讲,该实现并不兼容于Java实现。

  Java中匿名内部类一个令人生厌的地方是如果匿名内部类需要访问外部的某个变量,那么该变量必须为final。Groovy则消除了这种限制,在Groovy中,匿名内部类可以修改外部的变量值。

  为了能更好地说明这一点,让我们通过Java和Groovy分别编写一个示例。该示例来自于Groovy的发布声明。首先看看Java版本的:

int counter = 0 ;
final Timer timer = new Timer();
timer.schedule(
new TimerTask() {
  @Override
  
public void run() {
      counter
+=1;
  }
},
0);

   在该示例中,我们用Java创建了一个Timer对象,然后创建了一个TimerTask,后者将会执行run方法,我们希望run方法执行后会更新counter这个整型变量。然而遗憾的是,该程序无法编译通过,因为counter变量不是final的。编译器不允许run方法访问该变量。那么将其设为final的吧:

final int counter = 0 ;
final Timer timer = new Timer();
timer.schedule(
new TimerTask() {
  @Override
  
public void run() {
      counter
+=1; // compiler error!
  }
},
0);

   现在run方法可以访问counter变量了(仅仅是读取而已),但却无法更新该变量,因为它是final的,这又导致了另一个编译错误!那么采取一些间接的办法吧,比如说将该整型变量包装到一个对象中。我们打算使用java.lang.Integer,但它却是不可变的,由于该变量需要为final,我们就没办法重置该变量了。只能再去尝试其他办法了。我们可以使用java.lang.ThreadLocal存储该Integer并对其进行更新,或者是采用java.util.concurrent.atomic.AtomicInteger。

final AtomicInteger atomicIntegerCounter = new AtomicInteger(0);
final Timer timer = new Timer();
timer.schedule(
new TimerTask() {
    @Override
    
public void run() {
       atomicIntegerCounter.incrementAndGet();
    }
},
0);

   这么做确实可行,但代价实在太大了吧?本来是个很简单的问题,但却被搞成这么复杂:导入了线程相关的类,同时使用这段代码的用户也需要注意线程问题。

  现在,看看如何通过Groovy解决这个问题吧:

int counter = 0
Timer timer
= new Timer()
timer.schedule(
new TimerTask() {
    
void run() {
        counter
+= 1
    }
},
0)

   代码的运行结果与预期一致,没有编译错误,最重要的是这段代码的可读性非常好:其意图是非常清晰的。

  新版Groovy也支持内部类。推荐的做法是如果非要使用内部类的话,请使用静态内部类。在内部类中访问外部变量的方式与Java略有不同。在Java中,内部类可以通过一个隐式引用来访问外部类,该引用是作为构造方法的参数传进去的。这里所说的是实现细节了,我们可以直接访问外部类中的变量,就好像这些变量定义在内部类中一样。在Groovy中,我们必须显式传递该引用,但却无须编写上面所说的构造方法,当在外部类中实例化内部类时尽管使用该构造方法就行了。

  Groovy注解的使用范围比Java还要广。在Java 5注解出来时Groovy就已经提供了对注解的支持,而Groovy 1.7则将这一支持发扬光大:可以对import语句、package声明及变量声明进行注解。

  在import语句上放置注解可能没什么用,除非使用Grape(Groovy Adaptable Packaging Engine或是Groovy Advanced Packaging Engine)。Grape好比一个增强的、Maven或Ivy的代码级实现。其他的构建系统都会将依赖放置到外部的构建文件中(比如Maven的pom.xml或是Ant的build.xml),而借助于Grape则可以通过依赖注解代码。这么做会触发系统下载依赖文件,同时使代码的构建更具可读性。在Groovy的旧版本中,注解处于一种很尴尬的地位:Groovy注解只能用在Java 5注解可以使用的地方(比如说类或是方法)而不是更加自然的地方(比如在import语句上)。

  此次更新包含了更具表达力的断言、借助于语言本身抽象语法树(AST)所实现的编译期元编程特性(这样Java中通过字节码程序库所实现的功能也能在Groovy中实现了),同时还更新了Groovy Sql类以支持批更新和事务。

  Grails 1.2也随着Groovy 1.7一同发布。Grails是个Web框架,使用Groovy语言并基于现有流行的开源组件如Spring MVC和Hibernate所创建出来的快速开发环境,其风格类似于Ruby on Rails。最近几年Grails得到了迅猛的发展。最新发布的Grails首次尝到了SpringSource、Tomcat和SpringSource Tool Suite团队通力合作所带来的好处。

  新版Grails具有如下主要特性:与Spring的集成更加紧密(包括使用Spring MVC @Controller注解)、Groovy Object Relational Mapping(即GORM,构建在Hibernate之上的ORM解决方案)工具对具名查询的支持、可插拔的Web容器(对Jetty与Tomcat开箱即用的支持)、Grails视图层技术(Groovy Server Pages)改进的性能与内存使用量。发布声明提到其吞吐量提高了2——3倍。Grails也支持依赖管理而无论使用的Groovy版本是什么,通过Ivy机制自动下载依赖。该支持是借助于DSL(进行依赖声明)实现的。

  Groovy语言及周边的生态系统从2008年SpringSource收购G2One这一事件中获益良多。虽然语言背后的发展动力始终保持在稳定的状态,但工具支持这一块还是空白,尤其是Eclipse缺乏对Groovy的支持。Groovy Eclipse IDE 2.0的发布改变了这一切。虽然该工具套件还不支持最近发布的Groovy1.7编译器版本,但它已经提供了调试功能且兼容于Eclipse3.5。现在,插件已经能够提供响应迅速的内容辅助特性,支持联合编辑(比如可以在Groovy项目中编写Java代码)机制、跨语言的重构等等。所有这些新特性几乎都建立在完全重写的Eclipse插件的基础之上。请查看SpringSource发布声明以了解关于此次发布的更多信息。

  查看原文

0
相关文章