第2章 开始

安装Groovy与安装Ant、Tomcat或Java本身一样简单——解压缩发行版,创建环境变量,并确保二进制文件位于您的路径中。Groovy就绪后,您可以以任何方式运行它——编译或未编译,从shell或GUI控制台,或从命令行或web服务器。如果您有两分钟(或者更少)的时间,那么您就有足够的时间开始尝试Groovy。在您说“下一代Java开发”之前,本章将让您启动并运行。

2.1 安装Groovy

  1. http://groovy.codehaus下载并解压groovy.zip。
  2. 创建GROOVY_HOME环境变量。
  3. $GROOVY_HOME/bin添加到PATH中。

运行Groovy所需的所有东西都包含在一个ZIP文件中—好吧,除了JDK之外的所有东西。Groovy 1.x运行在java 1.4、1.5和1.6的所有现代版本上。如果您正在运行较老版本的Java,可以通过http://java.sun获得更新。如果不知道安装了哪个版本的Java,请在命令提示符中键入java -version:

$ java -version
===>
java version "1.5.0_13"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_13-b05-237)
Java HotSpot(TM) Client VM (build 1.5.0_13-119, mixed mode, sharing)

要利用Java 1.5语言的特性,比如Groovy中的注释和泛型,可能不需要说,您至少需要一个1.5 JDK。

Groovy在每一代JVM上运行的速度都明显更快,因此,除非有其他原因阻碍您,否则我建议您尽可能在最新的、最好的Java版本上运行Groovy。

同样,我建议您尽可能运行Groovy的最新版本。Groovy 1.0于2007年1月发布。下一个主要版本Groovy 1.5于2007年12月发布。稍后您将看到如何确定正在运行的Groovy版本。

Groovy开发团队煞费苦心地确保基本语法和接口在Groovy 1.0和1.5之间保持一致。版本号的增加意味着两件事:Java 5语言特性的增加,以及稳定性和原始性能的巨大飞跃。如果您仍然在运行Groovy 1.0,那么本书中的大多数示例将保持不变。ExpandoMetaClass类是在Groovy 1.5中添加的,但是元编程从一开始就是该语言不可或缺的一部分。在第10章元编程(第181页)中,没有特别使用ExpandoMetaClass类的例子在Groovy的任何一个版本中都将以相同的方式运行。底线是所有的Groovy1.x的版本应该可以合理地互换。打破语法的更改保留给Groovy 2.x。

我已经包含了关于如何安装Groovy的信息,其中有一节是关于Windows的细节,另一节是关于Unix、Linux、Mac OS X家族的细节。

检查Groovy版本

$ groovy -version
Groovy Version: 1.5.0 JVM: 1.5.0_13-119

您可以通过在命令提示符中键入groovy -version来判断已经安装了哪个版本的Groovy。如这里所示,这个命令还显示了Java版本。

在Unix、Linux和Mac OS X上安装Groovy
http://groovy.codehaus下载最新的Groovy ZIP文件。 将其解压缩到您选择的目录。 我更喜欢/opt。 您将最终得到一个groovy目录,该目录的末尾带有版本号,例如groovy-1.5。 我喜欢创建一个不包含特定版本号的符号链接:ln -s groovy-1.5 groovy。 这使我可以轻松便捷地在Groovy的版本之间切换。

由于ZIP文件无法保留Unix文件的权限,因此请确保在bin目录中切换并使其可执行:

$ chmod a+x *

目录到位后,下一步需要创建GROOVY_HOME环境变量。 这样做的步骤因SHELL而异。 对于Bash,您可以在主目录中编辑.bash_profile.bash_rc文件。 添加以下内容:

<a name="10____Groovy"></a>
### Groovy
GROOVY_HOME=/opt/groovy
PATH=$PATH:$GROOVY_HOME/bin
export GROOVY_HOME PATH

为了使这些更改生效,您需要重新启动终端会话。 或者,您可以键入source .bash_profile以将更改加载到当前会话中。 您可以键入echo $GROOVY_HOME确认您的更改已生效:

$ echo $GROOVY_HOME
/opt/groovy

要验证Groovy命令是否在路径中,请键入groovy -version。 如果看到类似的消息,则说明您已经成功安装了Groovy:

Groovy Version: 1.5.0 JVM: 1.5.0_13-119

在Windows上安装Groovy
http://groovy.codehaus下载最新的Groovy ZIP文件。 将其解压缩到您选择的目录。 我更喜欢c:\opt。 您将最终得到一个groovy目录,该目录的末尾带有版本号,例如groovy-1.5。 尽管您可以将其重命名为更简单的名称,例如groovy,但我发现将版本号保留在目录名称上有助于减少将来的升级。

目录到位后,下一步需要创建GROOVY_HOME环境变量。 对于Windows XP,请转到“控制面板”,然后双击“系统”。 单击高级选项卡,然后单击窗口底部的环境变量。 在新窗口中,单击“系统变量”下的“新建”。 使用GROOVY_HOME作为变量名称,并使用c:\opt\groovy-1.5作为变量值。

要将Groovy添加到路径,请找到PATH变量,然后双击它。 将;%GROOVY_HOME%\bin添加到变量的末尾。 (不要忘记前导的分号。)单击“确定”以退出所有对话框。 为了使这些更改生效,您需要退出或重新启动已打开的所有命令提示符。 打开一个新的命令提示符,然后键入set以显示所有环境变量的列表。 确保出现GROOVY_HOME

要验证Groovy命令是否在路径中,请键入groovy -version。 如果看到类似的消息,则说明您已经成功安装了Groovy:

Groovy Version: 1.5.0 JVM: 1.5.0_13-119

2.2 运行Groovy脚本

// hello.groovy
println "Hello Groovy World"
$ groovy hello.groovy
$ groovy hello
===> Hello Groovy World

有经验的Java开发人员注意到Groovy的第一件事就是他们可以运行代码而无需先编译。 您只需键入即可—与Java类相比,更像是编写JSP页面。 这可能会使您相信Groovy是一种解释语言。 实际上,Groovy就像Java一样被编译成字节码。 groovy命令既编译又运行您的代码。 但是,您不会在任何地方找到生成的.class文件。 该字节码在内存中创建,并在运行结束时被丢弃。 (如果要保留这些类文件,请参阅下一页的2.3节,编译Groovy(groovyc)。)

动态字节码编译意味着Groovy可以提供交互式shell。 键入命令并立即执行命令是尝试该语言的最快方法。 有关更多信息,请参见下一页第2.4节,运行Groovy Shell(groovysh)。 缺点当然是shell关闭后代码就消失了。 该shell非常适合进行实验,但是如果您想做些除quick-and-dirty快速和肮脏的操作以外的其他方法,则需要创建Groovy脚本。

要创建Groovy脚本,请创建一个名为hello.groovy的新文本文件。 添加以下行:

保存文件,然后在命令提示符下键入groovy hello.groovy。 由于给了它一个.groovy文件扩展名,因此您也可以只键入groovy hello。恭喜! 您现在正式是Groovy开发人员。 欢迎来到俱乐部。

有关运行未编译Groovy的更多信息,请参见第5章,第86页命令行中的Groovy。

2.3 编译Groovy

$ groovyc hello.groovy

// on Unix, Linux, and Mac OS X
$ java -cp $GROOVY_HOME/embeddable/groovy-all-1.5.0.jar:. hello
===> Hello Groovy World

// on Windows
$ java -cp %GROOVY_HOME%/embeddable/groovy-all-1.5.0.jar;. hello
===> Hello Groovy World

如果您只想运行一个快速脚本,让groovy命令动态地编译您的代码是很有意义的。 但是,如果您试图将Groovy类与旧版Java类混合在一起,则groovyc编译器是唯一的选择。 只要Groovy JAR位于类路径上,您的Java类就可以像Groovy类可以调用Java一样容易地调用Groovy。

有关编译Groovy和与Java类集成的更多信息,请参阅第69页第4章,Java和Groovy集成。

2.4 运行Groovy Shell (groovysh)

$ groovysh
Groovy Shell (1.5.0, JVM: 1.5.0_13-119)
Type 'help' or '\h' for help.
----------------------------------------
groovy:000> println "Hello Groovy World"
Hello Groovy World
===> null

Groovy shell允许您交互式地使用Groovy。不需要创建文件或编译任何东西—只需在命令提示符中键入groovysh,并开始键入诸如println "Hello Groovy World"之类的Groovy语句。每次按回车键,结果都会出现。要退出Groovy shell,键入exit

null(空)消息没有什么好担心的。这只是意味着您键入的最后一个命令没有返回值。如果您键入类似于2+2的内容,则消息将是语句4的结果。Groovy中的方法的最后一行是一个隐式的返回语句,Groovy shell的行为也是一样的:

groovy:000> 2+2
===> 4
groovy:000> s = "John"
===> John
groovy:000> s.toUpperCase()
===> JOHN
groovy:000> s.each{println it}
J o h n
===> John

toUpperCase()方法直接来自java.lang.String类。有关每个闭包的更多信息,请参见第59页第3.14节“迭代”。

Groovy shell存储您键入的所有内容的历史记录—即使在您退出shell之后也是如此。您可以使用向上和向下箭头键快速地重新输入命令或纠正胖手指语法错误。

提示符处的:000表示在不运行的情况下输入了多少行Groovy代码。例如,您可以在Groovy shell中动态定义一个类并立即使用它。(当然,一旦您退出shell,类就会消失。)

groovy:000> class Person{
groovy:001> String name
groovy:002> String toString(){
groovy:003> "Hi! My name is ${name}"
groovy:004> }
groovy:005> }
===> true
groovy:000> p = new Person(name:"John")
===> Hi! My name is John

你注意到两次都没有看到null吗?第一次得到true时——这是Groovy shell的一种说法,“好的,我可以为您定义这个类。第二次看到类的toString输出。冒着听起来有点厚颜无耻的风险,您将很快学会只在关心Groovy shell必须要说什么的时候才关注它的结果……

::: alert-info
问题:为什么Groovy Shell会忘记变量?

groovy:000> String s = "Jane"
groovy:000> println s
===>
ERROR groovy.lang.MissingPropertyException:
No such property: s for class: groovysh_evaluate
groovy:000> s = "Jane"
groovy:000> println s
===> Jane

Groovy shell在类型变量方面有一个奇怪的失忆案例。使用数据类型或def声明的变量会立即被忘记。在shell会话期间,将记住一个非类型化变量。当将代码从脚本复制到shell时,这可能会引起很大的混淆——在脚本中代码是正常的,而在shell中代码是错误的。

要理解这种明显的差异,您需要更好地理解Groovy shell是如何实现的。(如果您觉得您的眼睛开始变得呆滞,请将类型声明从shell变量中去掉,然后继续……)

Groovy shell是groovy.lang.Groovyshell的一个交互式实例。这个类还支持第5.10节中讨论的evaluate命令,即第95页上的求值字符串。每个GroovyShell都在groovy.lang.Binding中存储本地声明的变量(比如s=“Jane”)。

这个绑定对象本质上是“天空中的大hashmap”。当您键入println s时,shell会在后台调用binding.getVariable("s")。使用数据类型声明的变量(String s =“Jane”)不会存储在绑定中,因此在您下一次请求它们时将无法找到它们。

有关GroovyShell和绑定对象的更多信息,请参见第188页第10.4节,发现类的方法。
:::
图2.1: Groovy控制台

动态查找类方法

groovy:000> String.methods.each{println it}
public int java.lang.String.hashCode()
public volatile int java.lang.String.compareTo(java.lang.Object)
public int java.lang.String.compareTo(java.lang.String)
public boolean java.lang.String.equals(java.lang.Object)
public int java.lang.String.length()

您可以使用Groovy shell快速发现给定类上的所有方法。例如,假设您想查看所有的String方法。前面的例子很有用。

直接向类询问方法的好处是它始终是最新的-另一方面,Javadocs可能与实时代码不同步。 有关类自省的更多信息,请参阅第181页第10章,元编程。

在本节的开头,我们讨论了null消息,如果命令没有输出,则可以安全地忽略该null消息。 不幸的是,这是shell输出的另一个例子,它的噪声大于信息。

成功显示类中的所有方法后,命令String.methods.each{println it}返回错误:

groovy:000> String.methods.each{println it}
...
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
ERROR groovy.lang.MissingMethodException:
No signature of method:
org.codehaus.groovy.tools.shell.Groovysh$_closure1.call()
is applicable for argument types:
...

还记得我说过的,只有当您关心Groovy shell的内容时,您才会很快学会关注它的结果吗? 在显示所有方法之后,shell尝试执行String.methods调用的结果(并且可能会失败,我可能会添加)。 由于我已经习惯了,所以这个错误不会让我感到困扰。 我无视它,因为我知道它将要发生,而且毕竟这是临时代码。 如果错误消息使您感到困扰,则可以在调用末尾添加一条语句,该语句可以正确求值,例如String.methods.each{println it}; "DONE"。 您将输入一些额外的字符,但同时也避免了shel的一些杂音。

获取帮助

groovy:000> help
For information about Groovy, visit:
http://groovy.codehaus
Available commands:
help (\h) Display this help message
? (\?) Alias to: help
exit (\x) Exit the shell
quit (\q) Alias to: exit
import (\i) Import a class into the namespace
display (\d) Display the current buffer
clear (\c) Clear the buffer
show (\S) Show variables, classes or imports
inspect (\n) Inspect a variable or the last result
with the GUI object browser
purge (\p) Purge variables, classes, imports or preferences
edit (\e) Edit the current buffer
load (\l) Load a file or URL into the buffer
. (\.) Alias to: load
save (\s) Save the current buffer to a file
record (\r) Record the current session to a file
history (\H) Display, manage and recall edit-line history
alias (\a) Create an alias
set (\=) Set (or list) preferences
For help on a specific command type:
help command

在Groovy shell中键入help时,会显示一些隐藏的好东西。import的行为与它在Java源代码中的行为一样,允许您使用其他包中的类。如果您正在定义一个很长的类,并且搞砸了,clear将返回到一个:000状态。要清除整个会话,输入purge可以使您回到最初启动shell时的状态。record将您键入的所有内容保存到一个文件中,允许您稍后“回放”。history显示了shell记住您输入的内容。

2.5 运行Groovy控制台(groovyConsole)

$ groovyConsole

除了基于文本的Groovy Shell,Groovy还提供了图形控制台。 (请参阅第31页的图2.1。)在窗口的上半部分键入命令。 选择Script > Run,然后在下半部分查找结果。 (选择Script > Run Selection,可以将焦点缩小到突出显示的代码行。)

在第28页运行Groovy Shell (groovysh)的第2.4节中讨论的Groovy Shell吸引了命令行牛仔。 Groovy控制台旨在吸引更精细的GUI用户——那些已经习惯了剪切/复制/粘贴,撤消/重做等细节的用户。 控制台不能替代真正的文本编辑器,但是它比shell提供了更多的便利。例如,如果您有一个现有的Groovy脚本,您可以在控制台中通过选择File > Open来打开它。您还可以通过选择File > Save保存Shell会话。

您甚至有一个图形对象浏览器来更深入地查看给定类上可用的字段和方法。控制台运行的最后一个对象是Person的实例。在下面的页面中,选择Script > Inspect Last to snoop,如图2.2所示。

2.6 在Web服务器上运行Groovy (groovlet)

1. Copy $GROOVY_HOME/embeddable/groovy.jar to WEB-INF/lib.
2. Add groovy.servlet.GroovyServlet to WEB-INF/web.xml.
3. Place your Groovy scripts wherever you'd normally place your JSP files.
4. Create hyperlinks to your Groovy scripts.

在web应用程序中添加一个Groovy servlet可以让您在服务器上运行未编译的Groovy脚本。

图2.2: Groovy对象浏览器

Groovy servlet的行为类似于命令行上的groovy命令-它可以动态编译您的.groovy脚本。

首先,将groovy.jar从$GROOVY_HOME/embedded复制到JEE应用程序的WEB-INF/lib目录中。 Groovy启用了整个Web应用程序。 要动态运行Groovlets,请将groovy.servlet.GroovyServlet条目添加到WEB-INF/web.xml部署描述符中。 您可以映射所需的任何URL模式,但是通常使用*.groovy进行映射。

<web-app version="2.4"
         xmlns="http://java.sun/xml/ns/j2ee"
         xmlns:xsi="http://www.w3/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun/xml/ns/j2ee web-app_2_4.xsd">
  <servlet>
    <servlet-name>Groovy</servlet-name>
    <servlet-class>groovy.servlet.GroovyServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>Groovy</servlet-name>
    <url-pattern>*.groovy</url-pattern>
  </servlet-mapping>
  <!-- The Welcome File List -->
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

图2.3:友好的Groovlet

现在,您可以将任何未编译的Groovy脚本拖放到您的Web目录中,它将运行。 例如,在Web应用程序目录的根目录中创建一个名为hello.groovy的文件。 添加以下行:

println "Hello ${request.getParameter('name')}"

这个Groovlet回显了您通过name参数传递的任何内容。 要进行测试,请在网络浏览器中访问http://localhost:8080/g2/hello.groovy?name=Scott。 友好的Groovlet应该以个性化的方式说“Hello”。(参见图2.3。)

您可以像创建任何其他文件类型一样轻松地创建指向Groovlets的超链接:

<a href="http://localhost:8080/g2/hello.groovy?name=Scott" >Say Hello</a>

Groovlet还可以处理表单提交。注意,表单方法是GET,字段名是name。这将创建您手动输入并在前面放入超链接的相同URL。对于稍微高级一点的Groovlet,请参阅第185页的第10.3节,检查字段是否存在。

<html>
  <body>
    <form method="get" action="hello.groovy">
      Name: <input type="text" name="name" />
      <input type="submit" value="Say Hi" />
    </form>
  </body>
</html>

Web服务器状态检查Groovlet

// stats.groovy
html.h1("Disk Free (df -h)")
html.pre('df -h'.execute().text)
html.hr()
html.h1("IP Config (ifconfig)" )
html.pre('ifconfig'.execute().text)
html.hr()
html.h1("Top (top -l 1)")
html.pre('top -l 1'.execute().text)

这是我已部署到许多Web服务器的常见Groovlet。 它使我一眼就能看到一些关键统计数据,这些统计数据可帮助我判断服务器的运行状况-可用磁盘空间量,网络设置,服务器上正在运行的当前进程等。

通常我会ssh到机器中,并在命令提示符中输入这些不同的命令。相反,我可以访问http://localhost:8080/stats。然后得到相同的结果。 任何通常手工输入的命令都可以用引号括起来,并由Groovy代表我执行。(有关这方面的更多信息,请参见第89页第5.4节,运行Shell命令。)接下来,我可以使用每个Groovlet都可用的名为html 的MarkupBuilder将这些结果封装到HTML片段中。(有关这方面的更多信息,请参见第146页第8.13节,动态创建HTML)。

下面是生成的HTML的样子……

<h1>Disk Free (df -h)</h1>
<pre>Filesystem Size Used Avail Capacity Mounted on
/dev/disk0s2 149Gi 113Gi 36Gi 76% /
devfs 107Ki 107Ki 0Bi 100% /dev
fdesc 1.0Ki 1.0Ki 0Bi 100% /dev
map -hosts 0Bi 0Bi 0Bi 100% /net
map auto_home 0Bi 0Bi 0Bi 100% /home
</pre>
<hr />
<h1>IP Config (ifconfig)</h1>
<pre>lo0: flags=8049&lt;UP,LOOPBACK,RUNNING,MULTICAST&gt; mtu 16384
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
gif0: flags=8010&lt;POINTOPOINT,MULTICAST&gt; mtu 1280
stf0: flags=0&lt;&gt; mtu 1280
en0: flags=8863&lt;UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST&gt; mtu 1500

…但是,更重要的是,在下一页的图2.4中,您可以看到它在浏览器中是什么样子的。

groovlet并不意味着可以替代功能齐全的web框架。它们只是一些脚本,您可以通过命令行在web服务器上轻松地运行它们。有关在web框架中使用Groovy的示例,请参阅Grails和Gorm两章。

图2.4:显示服务器统计信息的Groovlet

2.7 Groovy结合Eclipse

http://groovy.codehaus/Eclipse+Plugin

如果您使用的是Eclipse 3.2或更高版本,则有一个Groovy插件提供与Java相同的IDE支持(代码完成,语法突出显示,调试)。

安装插件

要安装Groovy/Eclipse插件,请遵循以下步骤:

  1. 选择 Help > Software Updates > Find and Install > Search for New Features.
  2. 点击 New Remote Site.
  3. 在名称字段中输入Groovy
  4. 在URL字段中输入http://dist.codehaus/groovy/distributions/update/,然后单击“确定”。
  5. 检查Groovy存储库,然后单击Finish。
  6. 在“选择要安装的功能”下选择Groovy,然后单击“Next”。
  7. 阅读协议,然后单击“Next”。
  8. 设置默认位置,然后单击完成。
  9. 如果您收到有关该插件未签名的警告,请不要担心。 单击安装。

重新启动Eclipse,您应该已经准备好使用Groovy。

开始一个新的Groovy项目
要开始一个新的Groovy项目,请按照下列步骤操作:

  1. 选择 File > New > Project.
  2. 选择 Java Project, 然后点击 Next.
  3. 在项目名称字段中输入您选择的名称。
  4. 选择“Create Separate Source and Output Folders”,然后单击“Finish”。
  5. 在包资源管理器中,右键单击您的项目,然后选择 Groovy > Add Groovy Nature.

最后,您将需要更改已编译的Groovy代码的输出文件夹:

  1. 在包资源管理器中,右键单击您的项目,然后选择 Build Path > Configure Build Path.
  2. 将默认输出文件夹从bin更改为bin-groovy

2.8 Groovy结合IntelliJ IDEA

http://www.jetbrains/idea/

"IntelliJ IDEA 7.x"提供了对Groovy和Grails的本机支持。代码完成、语法突出显示、重构支持等等都是标准特性。(参见下面页面的图2.5)。如果默认情况下没有安装JetGroovy插件,请查找它。

如果你有“IntelliJ IDEA 6.x”。GroovyJ插件至少会给您提供基本的语法高亮显示。要安装它,打开Preferences屏幕,然后单击Plugins按钮。从列表中选择GroovyJ,然后单击OK。

图2.5:IntelliJ IDEA 7.x中的代码完成

2.9 Groovy结合TextMate

http://macromates/
http://macromates/wiki/Main/SubversionCheckout
http://groovy.codehaus/TextMate
http://www.e-texteditor/

TextMate是Mac上流行的文本编辑器。 它通过其插件系统提供可插拔语言支持。

从Macromates Subversion存储库中检出Groovy包(Groovy.tmbundle)。将文件复制到~/Library/Application Support/TextMate/bundle。重启TextMate, Groovy应该出现在Bundles菜单下。

Groovy TextMate wiki页面列出了其他与Groovy相关的包,包括Grails和GANT (Ant的Groovy实现)的包。

您还可以使用Bundle Editor从零开始创建自己的包。选择Bundle > Bundle Editor > Show Bundle Editor。(参见下一页的图2.6)。

Windows用户可能想要签出 E Text Editor。它承诺“TextMate在Windows上的强大功能”。TextMate捆绑包也应该在 E Text Editor中工作。

图2.6:TextMate的套件编辑器

2.10 Groovy在此处插入您的IDE或文本编辑器

http://groovy.codehaus/Other+Plugins

几乎所有现代IDE和文本编辑器都具有Groovy支持。 有关NetBeans,XCode,TextPad,SubEthaEdit,Vim,Emacs等的详细信息,请查看Groovy Wiki上的Other Plugins页面。

另一个很好的信息来源是您友好的社区搜索引擎。 例如,在搜索引擎中输入groovy xcodegroovy vigroovy [您的IDE]会产生很多来自成功博客(当然,也包括失败)的人们的点击量。

更多推荐

Groovy食谱: 第2章 开始