update at 6.30
前篇: 在Spring+Hibernate框架下,用动态语言写业务类
前文讲述,在Spring+Hibernate的架构下,因为动态语言所带来的利益,把一部分类改用Groovy/Jython/JRuby编写,最后编译成Java Class文件。
1.虽然只是语法糖,但忽然间一整吨语法糖摆在面前还是很让人感动的。
Groovy完全兼容Java语法,但又提供糖糖选择的方式感觉很贴心。
下面的两种情况里,最能吸引人把某个类从Java 改为用 Groovy实现:
1.字符串操作复杂时。
2.被强类型搞得焦头烂额的框架基类。
另外,隐约觉得因为动态语言的无类型,还有闭包这样带着Lisp式FP的印记,可能会激发更大的变革发生,动态语言这条船,迟早都要上的。
我发现myappfuse里那个拥有众多默认动作的DAO类的基类最适合用Groovy改写。
不过为了demo方便,下面改写的是CustomerDAO,并让它直接继承于HibernateDaoSupport。
先贴一段CustomerDAO类的片断,然后逐条解释:
package com.itorgan.myappfuse.dao;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
public class CustomerDAOGroovy extends HibernateDaoSupport
{
public insert(customer)
{
getHibernateTemplate().save(customer)
}
public List getAllValid(sortColumn)
{
def hql = "from Customer customer
where customer.status='valid'
order by ${sortColumn}"
def query = getSession().createQuery(hql)
return query.list()
}
public boolean isUnique(customer, uniqueColumnNames)
{
def params = []
def hql = "select count(*) from Customer customer where "
def first = true
uniqueColumnNames.tokenize(",").each
{
if (!first)
hql += " or "
else
first = false
hql+="customer.${it}=?"
params << customer.getAt(it)
}
def result = getHibernateTemplate().find(hql,params.toArray())
return ( result.get(0) == 0)
}
}
1.动态类型,参见insert(customer)函数
动态类型在Framework型项目中非常重要,多少设计模式呕心沥血,就是为了和这个类型搏斗。
(虽然可以不写类型,但必须用def关键字)
2.闭包
fp的基础,没有闭包的C++用函数指针,java用匿名内部类,都比他差远了。
3.强大的String类,参见getAllValid(orderColumn)函数中hql的定义
a.可以直接在String中嵌入EL, "orderBy ${sortColumn}",省了好多"和+号。
b.hql 可以多行,不用写N多"和+ , 写sql时特别方便。(但在严格按照JSR标准的JSR2时此项特性消失了)
4.为String,List 等基础类扩展了tokenize()等简便方法,参见最后一个函数
//原来StringTokenizer类的功能被简单的集成到String类中了
names.tokenize(",").each{......}
其他基础类的扩展见Groovy-JDK
5. 集合与循环的语法,参见最后一个函数
for (car in cars) { println car }
或者
car.each{print it}
集合也可以直接定义了,如
Def myList = ["Rod", 3, Date()]
Def myMap = ["Neeta":31, "Eric":34]
6.内建的反射语法,参见最后一个函数
customer.getAt("name") //得到属性name,
customer.invokeMethod("someFunction") //调用方法someFunction
从此不再需要Apache BeanUtils了。
7.运算符重载,参见最后一个函数
//向数组添加对象
params << customer.getAt(it);
还有如C++的向String,InputStream添加对象.
还有集合类相加,如list1+list2
8.省略了每行末尾的分号
既然每行都要的,何必多次一举呢
其他没有反映在这里的语法糖:
9.简化的Bean定义与赋值
//自动生成Getter和Setter
class Customer
{
Integer id;
String name;
}
//简便的对象赋值
customer = new Customer(id:1, name:"calvin");
customer2 = new CUstomer(id:2);
重新使对象的属性public,对java滥用getter,setter是一种修正
10.GPath--内置的XML语法,和Fremarker类似。
JDom和Dom4j可惜安息了
book = new XmlSlurper().parseText("<book writer='calvin'><title>D</title></book>")
println book.title;
println book[@writer];
println book.children.size();
11.简单集成了正则表达式
If ("name"==~ "na.*")
{println "match!"}
12.在String的EL中,避免Null Point Exception
//用"->"而不是".",可以避免NPE.
Customer me = null;
s= "${me->name}";
2.编译
ant的build.xml:
<path id="groovy.classpath">
<pathelement path="${basedir}/ROOT/WEB-INF/classes/"/>
<fileset dir="${basedir}/ROOT/WEB-INF/lib">
<include name="*.jar"/>
</fileset>
</path>
<taskdef name="groovyc" classname="org.codehaus.groovy.ant.Groovyc">
<classpath refid="groovy.classpath"/>
</taskdef>
<target name="groovy">
<groovyc destdir="${project.basedir}/ROOT/WEB-INF/classes" srcdir="${project.basedir}/src"
listfiles="true">
<classpath refid="groovy.classpath"/>
</groovyc>
</target>
3.Groovy现状
Groovy完成了10个Beta版本后,开始转向符合JSR的版本开发。刚刚发布了错误提示与编译器检验都得到了加强的JSR-2版,而正式版预计在这个夏天发布。
另外,主要是本着人有我有的精神,groovy决定抄袭Ruby的Module和Maxin(混入),JDK5的出现,也给保持始终语法兼容的Groovy添了点活,比如静态import。
IDE方面, idea和Eclipse都有语法变色的简陋插件,而真正的基于 IDEA5.0的插件--GroovyJ还没写好,不过据说快了,不过第一版还没有refactor的功能。
4.如何用Java实现动态语言
把GroovyC编译出来的class文件再用jad反编译,可以看到如何用Java去实现一门动态语言。
主要是多了一个MetaClass,不断的反射反射,运行时还非常依赖asm
最简单的例子:
Groovy文件:
public class Customer
{
private String id;
}
编译出来的Java文件
public class Customer implements GroovyObject
{
private String id;
transient MetaClass metaClass;
public Customer()
{
Object obj = ScriptBytecodeAdapter.invokeStaticMethod("org.codehaus.groovy.runtime.ScriptBytecodeAdapter", "getMetaClass", this);
metaclass metaclass = (MetaClass)ScriptBytecodeAdapter.asType(obj, groovy.lang.MetaClass.class);
}
public Object invokeMethod(String s, Object obj)
{...}
public Object getProperty(String s)
{....}
5.参考资料
Groovy网站的文档不多
2.Open Java Project的blog,Groovy文档的中文版