java与Groovy的整合

Groovy是构建在JVM上的一个轻量级却强大的动态语言.因为Groovy就是用Java写的,Groovy可以做到与Java的无缝兼容,可以使用Java强大的类库 而且Groovy最终也会被编译成class文件.

Groovy在1.0版的时候还存在性能问题,因为Groovy的很多实现都是用反射来做的,但是现在Groovy 1.1快推出了,据说快了10x...现在JetBrains也加入了Groovy Team旨在改善Groovy的性能,在Groovy2.0的时候还可能加上JIT,那性能就不成问题了,看来Groovy已经不是小打小闹了.而且随之而来的Grail.等基于Groovy的框架的推出,Groovy前景一片大好啊.

这篇文章不是为了讲Groovy的一些语法,而是说他怎么和Java做整合.

  • 静态使用Groory

1.运行Groovy类.

Groovy最终是会被编译成Java 的Class类的,所以Java是可以直接使用Groovy的类的.

如下,先是一个Groovy类:

package com.test;

class TestGroovyHelloWorld {
def doit(){
println "hello world!"
}
}

此类定义了一个doit方法,打印出hello world!字符串

然后看看Java怎么用这个类:

package com.test;

public class TestHelloWorld {

/**
* @param args
*/
public static void main(String[] args) {
TestGroovyHelloWorld test = new TestGroovyHelloWorld();
test.doit();

}

}

运行一下,果然打出了hello world!

很简单吧,只要直接import就行了.hoho,而且定义一个GroovyBean比定义一个JavaBean要简单的多的多.

2.运行Groovy脚本

实际上和Groovy类差不多,只不过Groovy类是集成自GroovyObject,而Groovy脚本是集成GroovyScript的,实际看看例子吧

Groovy脚本:

package com.test;

println "$test hello world!"

也很简单,就是打出hello world!不同的时候前面加上了$test ,这个有点类似与FreeMarker的格式($test也可以写成${test}),作用也是一样,通过外部将test参数引入,可以将$test替换成一个对象.看看下面Java怎么做的吧:

public class TestMain {

/**
* @param args
*/
public static void main(String[] args) {
Binding b = new Binding();
b.setVariable("test", "Kevin");//向脚本中的$test传入对象"Kevin"
Script test = new TestScript(b);
test.run();
}
}

打印出来一看是Kevin hello world!了..

  • 动态使用Groovy

Groovy是一个动态的脚本语言,如果只是向上面那样静态的使用,那优势就少了一半,既然是动态语言,那就看看怎么动态的去使用Groovy吧

1.通过接口,动态载入并使用Groovy类

(1)、定义Java接口包含在Java中需要调用的Groovy方法


public interface IFoo {
public Object run(Object foo);
}


(2)、创建Groovy类实现该接口

class Foo implements IFoo {
public Object run(Object foo) {
println 'Hello World!'
x = 123
foo * 10
}
}

(3)、动态载入Groovy类,创建接口实例,调用接口中定义的方法

import groovy.lang.GroovyClassLoader;
import java.io.File;
public class InvokeGroovy {
public static void main(String[] args) {
ClassLoader cl = new InvokeGroovy().getClass().getClassLoader();
GroovyClassLoader groovyCl = new GroovyClassLoader(cl);
try {
Class groovyClass = groovyCl.parseClass(new File("src/Foo.groovy"));
IFoo foo = (IFoo) groovyClass.newInstance();
System.out.println(foo.run(new Integer(2)));
} catch (Exception e) {
e.printStackTrace();
}
}
}

上面的方法是通过定义好接口来动态载入,如果没有接口怎么办...办法还是有的,那就是传说中的反射..Groovy也支持反射哦

2.通过反射,动态载入并使用Groovy类

import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;
import java.io.File;
public class DynamicGroovy {
private GroovyObject groovyObject;
public Object getProperty(String name) {
return groovyObject.getProperty(name);
}
public Object invokeScriptMethod(String scriptName, String methodName, Object[] args) {
ClassLoader parent = getClass().getClassLoader();
GroovyClassLoader loader = new GroovyClassLoader(parent);
try {
Class groovyClass = loader.parseClass(new File(scriptName));
groovyObject = (GroovyObject) groovyClass
.newInstance();
return groovyObject.invokeMethod(methodName, args);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
DynamicGroovy dynamicGroovy = new DynamicGroovy();
Object[] params = {new Integer(2)};
Object result = dynamicGroovy.invokeScriptMethod("src/Foo.groovy", "run", params);
System.out.println(result);
System.out.println(dynamicGroovy.getProperty("x"));
}
}

3.动态的载入Groovy脚本

动态载入脚本就更简单了,因为Groovy提供了一个方法evaluate,,和javascript的eval很像吧:

import groovy.lang.Binding;
import groovy.lang.GroovyShell;

public class TestEval {

public Object doit() {
Binding bb = new Binding();
bb.setVariable("test", "hello world!");
GroovyShell gs = new GroovyShell(bb);
return gs.evaluate("println test");
}

/**
* @param args
*/
public static void main(String[] args) {
TestEval te = new TestEval();
te.doit();

}

}

简单吧,通过evaluate一个字符串就行了,evaluate还支持脚本文件和类文件哦....功能很强大的.

  • Groovy与流行框架的集成

1.与Spring的集成

现在Spring的核心包就提供了与Groovy的集成了,,很好,很强大,这样就可以显示业务逻辑的动态改变了

由于Groovy的代码中也有描述Java代码的机制,因此两者合用非常容易
Spring Bean:


代码
class="org.springframework.beans.factory.groovy.GroovyFactory">
20


下面是groovy的例子:

代码
factory-bean="groovyScriptFactory"
factory-method="create">

SimpleHello.groovy


groovy文件:

代码
package org.springframework.beans.factory.groovy;

class Test implements Hello {

String sayHello() {
"hello world"
}
}

2.与webwork的集成

在WebWork2中,可以使用Groovy实现Action类来简化代码,提高编码效率

例子:

package web

import java.util.Date

import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory

import com.opensymphony.xwork.ActionSupport

class GroovyAction extends ActionSupport {

protected final Log logger = LogFactory.getLog(getClass())

private String now

String execute() {
now = "${new Date()}"
logger.info("returning view with ${now}")

"success"
}

void setNow(String now) {
this.now = now
}

String getNow() {
now
}

}
上面的Action类是Groovy类,同样扩展ActionSupport,这里要注意:

execute()方法没有throws Exception语句,这是因为目前的Groovy还没有这个Java特性,这需要在以后的版本中增加;如果添加,编译会报错

execute()方法返回时,不要使用类似SUCCESS的常量,而是用对应的值(如"success");如果使用SUCCESS,Groovy会把它解析成类的属性,抛异常

当然,在/WEB-INF/lib目录下需要包含运行以依赖的jar文件:Groovy和ASM.

首先强烈遣责water ye同学不负责任的行为,那家伙在blog上贴了一段spring 2.0m2的test代码就了事,居然不测试一下,结果俺的spring groovy test代码折腾半天才过去。

测试代码俺就不贴了,spring的配置就够了

 1 <?xml version="1.0" encoding="GBK"?>
 2 <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
 3     "http://www.springframework.org/dtd/spring-beans.dtd">
 4 <beans>
 5     <bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor" />
 6     <bean id="inlineMessenger" class="org.springframework.scripting.groovy.GroovyScriptFactory">
 7         <constructor-arg>
 8             <value>inline:
 9                     package spring.groovy;
10                     
11                     class GroovyInlineMessenger  implements Messenger{
12                         void sayHello(){
13                             System.err.println("Hello");
14                         }
15                     }
16             </value>
17         </constructor-arg>
18     </bean>
19     <bean id="messenger" class="org.springframework.scripting.groovy.GroovyScriptFactory">
20         <constructor-arg value="classpath:spring/groovy/GroovyMessenger.groovy" />
21         <property name="message" value="Hello World!" />
22     </bean>
23 </beans>


1、第5行的bean定义一定要有,估计是提前编译groovy脚本的(具体的可能啃一下源码就明白了)。
2、inlineMessenger这个bean的定义,inline一定要紧跟着<value>写,我为了美观,弄成下面两种写法都没过去。

 1     <bean id="inlineMessenger" class="org.springframework.scripting.groovy.GroovyScriptFactory">
 2         <constructor-arg>
 3             <value>
 4             inline:
 5                     package spring.groovy;
 6                     
 7                     class GroovyInlineMessenger  implements Messenger{
 8                         void sayHello(){
 9                             System.err.println("Hello");
10                         }
11                     }
12             </value>
13         </constructor-arg>
14     </bean>

1     <bean id="inlineMessenger" class="org.springframework.scripting.groovy.GroovyScriptFactory">
 2         <constructor-arg>
 3             <value>
 4             <![CDATA[inline:
 5                     package spring.groovy;
 6                     
 7                     class GroovyInlineMessenger  implements Messenger{
 8                         void sayHello(){
 9                             System.err.println("Hello");
10                         }
11                     }]]>
12             </value>
13         </constructor-arg>
14     </bean>

写成这样倒是过的

 1     <bean id="inlineMessenger" class="org.springframework.scripting.groovy.GroovyScriptFactory">
 2         <constructor-arg>
 3             <value><![CDATA[inline:
 4                     package spring.groovy;
 5                     
 6                     class GroovyInlineMessenger  implements Messenger{
 7                         void sayHello(){
 8                             System.err.println("Hello");
 9                         }
10                     }]]>
11             </value>
12         </constructor-arg>
13     </bean>

俺平时习惯让myeclipse对xml进行格式化,照这么看来,估计一不小心,按个ctrl+shift+F,好端端的spring groovy代码就过不去了,然后就慢慢找问题吧。

posted @ 2008-06-11 14:09  eafy.ye  阅读(2875)  评论(1编辑  收藏  举报