2005年8月17日
摘要: 最近都实在憋不出什么花团锦簇的大块文章,还是安心在微博里碎碎念算了。
地址: http://t.sina.com.cn/calvin1978 ,大家互相关注一下哦。 阅读全文
摘要: 大众搬屋版里, 不断将工作项目中的代码片段移植过来,而且这种搬运的幸福感估计还会下面的几个版本中延续。 阅读全文
摘要: 现在的书都好厉害,《高效程序员的45个习惯》,《软件架构师应该知道的97件事》.....但总觉得自己就是个FIFO的管道,看完后基本没记住什么。
或许这个喧嚣而碎片化的年代,惟有屈指可数的东西,才能可能真正被时时记起,践行吧。在公车上强迫着自己从十多年轻轻重重的实践中,砍剩最后的几样非如此不可,且无处不可的实践:
阅读全文
摘要: Hmm...居然还差半个月就有半年没发新版了,long time no see 啊。 至于原因嘛,与Tim讲的 有点相似。
好在公司的新项目选型都与SS接近,所以新代码里其实有很多是亲爱的同事们的手笔, 不再是一个人在战斗了。
BTW. 回头一看,这里好像只剩下SpringSide的更新记录,其余的连草都没有了。
现在工作稳定,是时候出宫了。 阅读全文
摘要: 最近国内的开源项目非常生猛,与Play!Framework有些相近的斗鱼,也是要替代SSH的Nutz, 已经支持Spring 3.0与iBatis 3的Rapid framework 3.0, 在这个好像特别寒冷的年末,俨然一道鲜亮的风景。
SpringSide也发新版了,相比之下创新性有点欠奉,更像是一本日记,将这两三个月里遇到的代码记录下来与大家分享。 阅读全文
摘要: 作为3.1系列的最后一个版本,3.1.8版的代码质量在 Hudson + Sonar 双塔控制下,慢慢开始好转了. 阅读全文
摘要: SSO方案中太多平行对称的分支选择,就像博而赫斯那小径分岔的花园。刚手写完一个超迷你劲袖珍的SSO,顺着 SAML2.0和OpenID的规范,记录一下这些分岔点。 阅读全文
摘要: 又过一年了,更新一次自己的ESB笔记,内容实在,枯燥无味,浓缩即精华....年度最大发现应该是Fuse ESB 4.0吧。 阅读全文
摘要: 背景音乐:《要不要就一起加入GCD》,唱:陈珊妮,词:夏宇。
JDK5是一个巨大的转折点(泛型,Annotation,并发...),而JDK6就是一个可安全升级的加强版,对新项目是不升白不升,白升谁不升,而对旧项目就是升了也白升,不升也没啥损失吧。 阅读全文
摘要: 年又过年,去年在写在译的书又长出了一茬,又是时候订一份今年的读书计划。 阅读全文
摘要: 3.1.2是连跳了3.1.0和3.1.1两个版本后的GA版本,一边忙着Mini-Example这一亩三分地的升级,一边开始Showcase的演示...... 阅读全文
摘要: 没人知道多如牛毛的传统MVC框架中哪个是最好的,但就像硬件界买IBM不会犯错一样,Struts2.1也应该是未来一段时间里安全的选择,特别是企业里有N多开发团队和开发人员的时候。
阅读全文
摘要: 年末最后一天,昭事上帝 ,聿怀多福,祈望来年的Java社区争气一点,实现偶们小小的愿望... 阅读全文
摘要: 对于演示原型 ,上午要下午给的快速交付,或者某些不知道到底一年有多少个人点进去的网站角落,或者极少数管理人员才用到的管理功能,在恨不能php,ror的时候,你会想起jsp+jdbc的温暖。
又或者你请到了只会写jsp和sql的极品,又想让他明天开始干活.....
所以另做了这个extreme-web风格示例 , 在简化到no config file的jsp+jdbc同时,仍然是个可堪一观的MVC,仍然基于亲爱的Spring.
阅读全文
摘要: 怀胎十八个月的SpringSide 3.0 终于低调的发布了。
这个版本里的SpringSide,终于放弃梦想,不再奢望做一个框架,或者一个像RoR/Gails那样极简的、创新的封装,唯余对如何用不轻也不重的主流选型、编程实践来开发JavaEE企业应用的老老实实的总结。 阅读全文
摘要: GC调优是个很实验很伽利略的活儿,最后服务的处理速度从1180 tps 上升到1380 tps,调整两个参数提升17%的性能还是笔很划算的买卖..... 阅读全文
摘要: 与Mule 2.0抵死缠绵了两周,喜忧掺半。但只在2.0之后,Mule才算真正站到了ESB的起跑线上。
完整的笔记见我的Wiki: http://wiki.springside.org.cn/display/calvin/Mule , 这里主要列一下实际的升级感受。
阅读全文
摘要: 江湖上多的是功能华丽的项目原型/骨架生成工具,但最后,反而是功能简单的Maven Archetypes渐渐有了一统的希望。
无它,先把自己收拾得简单易用,然后作为一个江湖大佬(maven)的"官方"小弟,再有另一些江湖大佬(appfuse,strust2,cxf)使用示范一下,就是现在的上位秘诀。
阅读全文
摘要: ICP的审查员们都严查谣言去了么?最艰难的一次ICP注册,让SpringSide关站至今。4月份里填错了两次接入商,而5月份就一直静止在"待管局审核"的阶段。
6月份,终于通过了。
http://svn.javascud.org/svn/springside/springside3/trunk 阅读全文
摘要: TerraCotta 通过将POJO对象在群集内下的共享,让POJO不再局限于SNA(Share Nothing Architect)的架构,比较透明的支持了集群模式,可谓POJO开发模型的最后一块拼图。 阅读全文
摘要: 为了2007年的目标,列了下面待读或重读的书单。
不在书单里的,小部分是我漏掉的,大部分是我觉得对于架构师不太重要,或者不够好的。
奇怪国外真正的好书来来去去也就那么几本,emule加上国内出版社的努力,我们看的东西和老外已差不多,为什么老外看完就那么生猛,我们看完就还是半桶水呢。 阅读全文
[摘要]Spring发了2.0,Struts发了2.0,SS也来凑凑2.0的热闹。下载地址:http://www.springside.org.cn/download.php![](http://wiki.springside.org.cn/images/icons/linkext7.gif)
SpringSide 2.0改用了Pragmatic版的Struts作为MVC主打框架,重写了所有的代码,增加了新项目生成的命令和构件化的开源栈,还增加了方便新手入门的Helloworld示例。
随着Java开源社区的日日进步,SpringSide升级了包括Spring 2.0的AOP事务配置, Hibernate3.2的annotation模式,XFire1.2.2的最新简约配置及JSR181模式,以及ActiveMQ4.1 的Message Driven POJO新模式。
另外,还增加了iBatis数据访问模式和一系列Ajax Widgets,并全面推行了Selenium集成测试。
全文地址:http://blog.csdn.net/calvinxiu/archive/2006/11/28/1417730.aspx
这篇文档是专门写给那些编程狂热者,在Ant里编程时要留意的重要Task。
不知为何,老外的各种脚本都写得格外漂亮。从Appfuse里学到很多,在编写SpringSide2.0 的构件安装脚本时又被迫自学了不少,这里作下总结。
![](http://writeblog.csdn.net/fckeditor/editor/images/spacer.gif)
全文地址: http://blog.csdn.net/calvinxiu/archive/2006/09/07/1187329.aspx
摘要: 虽然现在已是Web Server, Web Service的天下,但偶然还是会因为性能苛刻,或者需要自定义协议的原因,很无辜的要自己做一个Multi-Thread,Multi-Client的Tcp Server。 超简单的QuickServer,让你专心编写自己的业务代码, 不用编写一行Tcp代码。[阅读全文] 阅读全文
摘要: Nutch是一个基于Lucene,类似Google的完整网络搜索引擎解决方案,基于Hadoop的分布式处理模型保证了系统的性能,类似Eclipse的插件机制保证了系统的可客户化,而且很容易集成到自己的应用之中。
Nutch 0.8 完全使用Hadoop重写了骨干代码,另外很多地方作了合理化修正,非常值得升级。[阅读全文]
阅读全文
摘要: 这个版本将是SpringSide1.0范围内最后一个跑马圈地,开疆拓土的版本。从下一个版本开始,将会把主要精力放在代码的细化,文档与测试用例的补充,以及在实际项目中的应用。
这个版本除了继续跑马圈地外,也对代码结构作了很多遍重构,终于使复杂的项目以比较顺眼的方式组织起来了。
阅读全文
SpringSide是一个以Spring Framework为核心,Pragmatic风格的企业应用开发基础和最佳实践展示。 为使用Spring框架的开发者提供一个非Demo版的复杂、正式且体现最佳使用实践的参照系统。为JavaEEer必须面对的问题提供合乎Pragmatic原则的解决方案。
当然,要等待大家拍砖过后,上述表述才会成立。
SpringSide主要包含四个部分--
-
BookStore-Sample: 一个Full Feature的书店示例,兼有有书店前台和后台管理,作为典型企业应用的微缩版。
-
SpringSide-Base:SpringSide的核心封装代码与构建一个CRUD管理后台所必需的full-stack代码库。用户在其基础上能快速搭建出自己的管理后台及安全管理程序。 (建设中)
-
SpringSide-Modules: 以modules形式提供了其他的企业特征如XFire WebService,JBoss Rule engine,BIRT report,用户可以快速复制应用到自己的项目。 (建设中)
-
Rails-Generator: 自动整合SpringSide-Base/Modules生成项目,生成CRUD代码的Eclipse Plugins 和Ant 脚本。 (建设中)
官方站点: http://www.springside.org.cn 下载地址: http://www.springside.org.cn/download.php 演示站点: http://demo.springside.org.cn:8080/springside/ 升级概述:终于从春天走到了夏天第二版,上一个版本的发布比较匆忙,Bug一堆,1.0 M2版作了大量补救的工作,改进了JBoss Rules ,Compass, Acegi部分使它们贴近了一点"best practice demo"的目标。另外还有很多很多的文档补全与Bug修正。
尽管代码里还是有Bug,但为了把SpringSide用于实际项目的1.0M3计划的开始,先把1.0M2发布出来,希望大家能帮忙数数bug,提提建议,更欢迎大家加入到SpringSide的开发团队 。
主要更新:
-
Compass更新: 使用简单的Annotation代替复杂的xml映射文件,再换上Compass提供的默认的Index和Search Controller,使得Lucene的使用成本降到平民团队的程度。另外还加上了复杂查询的Demo,完整的文档,So Cool。
-
JBoss Rules更新:JBoss Rules出到正式版3.0.1,官方文档也已经补全。在读完官方文档后,改进了之前的封装和Demo。
不过JBoss Rules的Road Map告诉我们,它还在升级规则存储管理的模块,暂时不用自行扩展。
-
Acegi 更新: Acegi出到正式版1.0,在订单管理部分初步加入ACL控制,还有JCaptcha验证码的加入及登陆超时,Logout Filter等特征的使用。
-
其他实用性改进:比如可用Propertity修改的Base Constants;增加了一个查询属性如图书名有没有重复的通用函数;增加一个historyable接口,BindObject函数会自动为实现了该接口的ceate/modify user 和create/modify time,并用Hibernate Event Listener侦听修改记录;增加了前台Ajax分页的简单演示。
其他修改:见 团队开发日志
其他依赖包升级:
-
extreme components 1.0.1 看半天,收获就是每个<ec:table> 里不需要再定义imagePath了,在properties文件里定义即可,ec会自动为其加上contextPath 如/springside。
-
Commons-Validator 1.3 + SpringModules-validation 0.4 使用hotfix的springmodules版本,两者的最新版终于走在一起了。
本期开发人员介绍:
-
差沙:本期MVP队员,为SpringSide加入了JCaptcha验证码和订单管理的Acegi ACL实现,ACL的实现侧显了差沙强劲的编码爆发力,而JCaptcha的引入过程暴露了差沙无物不破的Fix Issue能力。最后差沙已正式升级为SpirngSide核心开发团员。
-
地狱男爵:接过nkoffee的棒,把Compass的Feature表现得简单而强大。
-
cac(陈俊):SpringSide的大内总管,承担了SpringSide大部分的代码改进,Bug修正和页面优化的工作,尤其在1.0M2的最后发布阶段,每天熬过半夜连续挑掉了无数问题。
-
李李:补充了WebWork的文档,简化了Webwork的应用,bba96框架也升级到bba96-tiger1.0-beta3。
-
schweigen:补充了JBoss Rules的文档。
-
江南白衣:咳。
重要的1.0 M3 开发计划见http://jira.javascud.org/browse/SPRINGSIDE 共23个任务,其中核心任务有SpringSide-Base建设、Acegi应用的再次升级、BIRT应用的再次升级、JBpm的加入、dojo和Sun的Html widgets 集成taglib大加入、Spring 2.0RC1的升级。 欢迎大家加入SpringSide开发团队,凑个热闹,共襄盛举。
最后特别感谢scud的JavaScud开源服务平台(http://www.javascud.org) 为 SpringSide提供的系列服务.
摘要: Prototype.js 是Javascript编写者的一把小军刀,提供了很多Ruby风格简写语法和实效的函数,更难得的是完全跨浏览器,让大家舒舒服服写出又精简又不用愁心兼容的的JS代码,springside 已经离不开它了。 阅读全文
1.TheServerside.com 依然是地位无可动摇的CCTV1。
2.InfoQ.com Floyd Marinescu 在离开 TSS 后另起炉灶,2006年中最重要推荐。视野不再局限于Java 而是包括Java,.Net, Ruby ,SOA, Agile方法等热门话题。
3.JDJ的电子杂志 在JDJ首页的最底处订阅,文章质量不低于5-7的传统三强。
4.SWik.net 收集了大量OpenSource Project的资源聚合。其中如Spring,Hibernate的更新度非常高,出现什么和Spring有关的blog,article,project都会马上被聚合。
5.IBM DeveloperWorks 传统、稳定的Java文章来源地。
6.JavaWorld 传统、稳定的Java文章来源地。
7.OnJava 传统、稳定的Java文章来源地。
8.Artima.com 类似于TSS而略逊,其中Spotlight 文章值得关注,而Java News是聚合了所有其他Java站点的大聚合。
9.JavaLobby 站内的Announcements 是大大小小Java Project的发布声明区,Trips and Tricks 有很多的Tips。
10. No Fluff Just Stuff 的Blogs 聚合 一直缺一个所有优秀Java Blogger的rss总聚合,NFJS这里勉强算一个。
摘要: 作为一个架构设计师,只应该上述的第2,3项特征,一是在框架类里配合使用反射和泛型,使框架的能力更强; 二是采用收敛特征,本着对人民负责的精神,用泛型使框架更加类型安全,更少强制类型转换。
同时,老被人骂的擦拭法其实避免了Java的流血分裂。 阅读全文
摘要: 因为Retrotranslator的出现,SpringSide 1.0终于放心升到JDK5.0,并保证仍然100%可以运行在JDK1.4的服务器上。
和Retroweaver一样,大家直接用JDK5开发,最后通过ASM转换到JDK1.4的字节码,部署到JDK1.4的运行环境。但它不仅支持JDK5的语法,还支持JDK5的新增API。 阅读全文
摘要: 当王家卫遇到杜可风,Spring遇到Ruby。想出这个题目的Crraig Walls 绝对也是个八卦种子,宣传的是Spring 2.0m2集成动态语言的feature。 阅读全文
摘要: 《Effecitve Enterprise Java》的一个实践。 阅读全文
摘要: 看着log4j-2.13.jar被每个项目每个版本里一次又一次无限下载,你就会觉得用Maven2 管理Library实在很环保。
而且,Java的类库也急需摆脱这种无身份无地位一个jar包随处摆放的境况。Maven给Jar以名份是一个好方向。
阅读全文
摘要: 有个地方恰似美好未来,就是被赶鸭子上架的springside了。
阅读全文
摘要: SourceForge用了许多年,最近才靠springside混进了它的后台。八卦一把去sf混个房间有什么好处,还有它以什么规则,维持这么大一间善堂的运作。 阅读全文
摘要: 似乎老外有这个习惯,逢年过节都会推荐一些书大家在家里充电。 阅读全文
作者: 江南白衣 JDBC有够慢的,出到了3.0了才有个Rowset能类似于windows下ADO的概念,却还是达不到ADO.net的水平。幸亏Java里ORM这块比较争气,趁着C#的ObjectSpace跳票,可以继续耀武扬威。
Rowset对比于ResultSet,除了不用保持Connecton外,更重要特点是能够类似于ADO的编程方式,直接对Row赋值来进行Insert与Update, 而不用写SQL语句。 在windows编程中经常可见这种模式,特别是ADO.net用的好时,ORM也只能算是锦上添花....
在oracle的sample代码中,rowset02.java完整demo了RowSet的ADO模式。 简化后的代码如下:
public class RowSet02 { public static void main (String []args) { try { OracleCachedRowSet crowset = new OracleCachedRowSet (); crowset.setUrl (java:oracle:oci8:@); crowset.setUsername ("hr"); crowset.setPassword ("hr"); /*Select*/ crowset.setCommand ("SELECT seatno, tdate, name, class FROM reservation"); crowset.execute (); System.out.println ("Seat no Travel Date Name Class"); while (crowset.next ()) { printRow (crowset); } crowset.setReadOnly (false); /*Update*/ crowset.beforeFirst (); if (crowset.absolute (2)) { crowset.updateString (4, "Business"); crowset.updateRow (); }
/*Insert*/ crowset.beforeFirst (); crowset.moveToInsertRow (); crowset.updateInt (1, 107); crowset.updateDate (2, new Date (975915381774L)); crowset.updateString (3, "Pluto"); crowset.insertRow ();
/*Delete*/ crowset.beforeFirst (); if (crowset.absolute (6)) { crowset.deleteRow (); } crowset.acceptChanges (); crowset.close (); } catch (SQLException ea) { ea.printStackTrace (); } } }
作者: 江南白衣 上次FB的吹水摘录: 除JDBC外的数据访问技术包括EJB,Hibernate,JDO,iBatis等,但凡是ORM的总要面对相同的困境,如果透明持久化的,苦恼就更多 --Java数据访问技术依然在缓慢跨越鸿沟,.Net社区的同学用不着眼热心跳: 1.查询语言--纷纷重回原来极想摆脱的sql,但实现得又不如SQL成熟。 因为QueryObject,Criteria API的可读性太差,最后所有技术方案都回到它们原来一力想摆脱的SQL的路上。而且,因为是重新仓促设计,都不如sql 的成熟,总有很多做不到的地方。像刚开始的EJB QL,几乎什么都做不了,而hibernate 3.0 HQL把h2的代码抛弃了重新实现才达到相对满意的水平。 2.积极载入和懒惰载入--不能如sql般每次随需定制
ORM与jdbc访问的区别,就是以包含关联对象的对象,而不是以sql自由定制的ResultSet,作为数据载入的主体。 积极载入策略在载入订单对象时,会接着载入顾客对象、产品对象,而如果产品对象又包含类别对象时.....整个数据库被拖了一小半出来。即使不玩连连看,clob对象的胡乱载入就够头痛了。 与此对应的就是懒惰载入策略,比如EJB的初始版本,据闻每个属性查询一次数据库,数据库往返次数多得吓人。 ORM方案会让用户自行定义这两种策略来达到平衡。一般默认采用积极载入,在一对多关联上定义lazy load,还有统一定义积极载入的层数。到了hibernate 3,更可以在列级别上定义lazy load。 问题是,上述的定义都在hbm文件, 每种对象的载入策略只能定义一次。而不能像jdbc那样, 根据不同的情况select不同的结果列。 顺带一个问题是那些信息不完全对象,比如产品只有序号和名字,不带其他信息时,在一个纯面向对象环境里不好表示,hibernate提供的component方案也不是太好。 3.透明持久化--对POJO的一些临时操作也会被持久化 因为持久化是透明的,很容易就会误用,对POJO进行的一些临时操作,一不小心就被保存进数据库中。再加上Session,事务的混乱,远远没有用jdbc跑DML语句那么容易搞清楚发生的事情。 而且,不是每个程序员都能习惯新的透明持久化环境,都对所用ORM系统的持久化策略理解深刻。何况这些策略以及整合它们的框架如Spring,还经常毫无提示的在升级时发生改动!!! 所以,每个使用ORM的团队,在项目过程里总会有闹鬼的几天......
从晚上六点开始聊到十一点,一群恐怖的聊天动物,隔壁桌的三姑妈六姨婆都无奈先撤了。
记忆力超强的david.turing记得的Topic包括:Hibernate,Spring,iBitas,Strut,SOA,BEA产品(Wls, Wlp, Liquid Data),JDK1.5,设计模式,泛型,数据库事务,Java控件,RichClient,XML,WebService,反编译技术,代码重构,比较.Net和Java在开发过程中的区别,UML,代码控制,反射机制,Oracle/SQLServer,手谈的AI设计,Web数据窃取...... 一群gay birds包括:Sparkle,Yok,WaterYe,江南白衣,Cyt,timiil,Char,Alex,瀚海,oo豆豆猪。
PS.英文不好的同学用词霸查一下gay bird,切勿自误。
作者:江南白衣
SpringSide--Pragmatic Enterprise Application KickStart and Common Library Stack,这么长的一个名字下来,不用解释大家都知道是做什么的了----以Spring Framework为core,提供一个Pragmatic的企业应用开发基础和最佳实践展示。
定位:为使用Spring框架的开发者提供一个非Demo版的复杂、正式而体现最佳使用实践的参照系统。
目标:囊括JavaEE必须面对的所有问题的合理的、合乎实践标准的解决方案,采用Plugins形式组织,使开发者可快速定位所需的参考方案并做加法到自己的系统。 项目网站:http://www.springside.org.cn or http://springside.sourceforge.net 1. Featrue List
-
Spring 2 - J2EE Framework.
-
Hibernate 3 - ORM, support EJB3/JPA1.0 in future.
-
Spring MVC /WebWork - Multi-Action Web framework.
-
JSP2.0 - View Template.
-
XFire - Web Service.
-
Acegi - Security, RBAC ana ACL.(doing)
-
Eclipse BIRT 2 - Report Engine.(doing)
-
Drools 3 - Business Rule engine.(doing)
-
ActiveMQ ,Jencks - JMS Message Driven POJO.
-
Quartz - Enterprise job scheduler.
-
DWR 2 , Prototype.js , TrimPath JSTemplate - Ajax
-
Compass - Search engine use Luecene .(doing)
-
Groovy - Dynamic script language.(doing)
-
Openi - BI web application for OLAP Report.(doing)
-
ServiceMix - ESB(Enterprise Service Bus) and JBI.(doing)
-
Commons Validator - client and server side validation.
-
SiteMesh web-page layout and decoration framework.
-
OSCache - Web cache solution.
-
ExtremeTable - JSP Tag Libraries.
-
Log4j - Logging tool.
-
Ant , Maven2 , JUnit, EasyMock - Build and Test tools.
- UTF-8 and I18N.
- Intergrate with Weblogic , Tomcat , JBoss , Geronimo.
- And we are choising the Workflow solution.
2. SpringSide与Appfuse有什么不同? 1.SpringSide较完整的演示了企业应用的各个主题,而Appfuse只有简单的登陆界面和用户管理。
2.SpringSide是深受Ruby on Rails影响的Pragmatic型的方案。
3.Appfuse主要目的是展示各式mvc、orm方案与Spring的结合,有些技术属于高手玩具,而SpringSide展示的是一个国内项目的实际形态,并带中文手册与大量中文代码注释
4. 脚本细节 SpringSide的基本结构是JDK1.4 + Spring 2.0 + hibernate3 + Spring MVC multi-action + JSP2.0。
使用 XFire提供WebService订书的服务端接口和 Java版/.Net版的客户端示范代码。
店员是个兼职的学生,所以系统会为每张订单发一封通知邮件给店员。为了不影响顾客下单的速度,发信的动作由jms异步进行。 系统还会用 Quartz定时扫描缺货的图书,用邮件通知店员。 老板只负责看一些色彩丰富,带图的报表。Eclipse Birt2.0提供日常报表 , Openi提供BI OLAP的。
基于Lucene的 Compass做的图书全文搜索。
基于 Drools规则引擎的订单满100元免运费,会员积分制等。
店面演示Ajax效果与 OSCache的Web Cache,SiteMesh的渲染效果使用。
一些非关键业务,用 Groovy动态语言来快速开发。
log4j系统将重要操作员日志异步写入数据库,使它们可管理。
综合的Acegi i安全权限管理。
utf-8, i18n的国际化项目。
ServiceMix ,WorkFlow的故事设计中。
5. RoadMap Road Map in JIRA Issue Checker ,欢迎大家提出更多Topic . 6. 团队成员列表 (排名按加入顺序) 欢迎朋友们加入。人多速度快是很重要的事情。
参加方式有3种 1.帮忙codereview提意见 2.到JIRA里面领任务 3.到JIRA 提出新任务
真正贡献了力量的同志自然会成为开发人员.
Team Worker: 江南白衣,cac,@_@,wuyu,charlse, efa,yimlin Contributor: water ye ,totodo,david.turing,pesome,oofrank 长老供奉: 庄表伟,Robbin
(排名按加入时间)
7. 交流区
演示站点
开发RoadMap
Spring中文论坛专区
团队开发日志
开发者QQ群:15690287 (only for Springside developer) 用户QQ群: 21601442
作者:江南白衣
Spring再强大,也要面对降临的问题--因为Spring不是Weblogic、Tomcat般的顶层容器,Servlet和EJB对象不由它创建,所以它必须要降临到Weblogic、Tomcat所在的位面。 初学者一般不用管那么多,照着Spring+hibernate+Struts之类的Sample就做了,但慢慢的,也许就要开始在jsp+javabean体系,土制框架,singleton类等环境下使用Spring了。 《Professional Java Development with the Spring Framework》第3章有"Managing the Containe"一节讲这个问题。一般可以分为直接召唤系与IoC fashion两类。
1.直接召唤系--Singleton的Application Context 最简单的,就像在UnitTest里那样,直接构造Application Context:
ApplicationContext ctx = new ClasspathXmlApplicationContext("ApplicationContext.xml"); 在Web环境里,会使用ContextLoader构造ApplicationContext后,压进Servlet Context。 由ContextLoaderListener或ContextLoaderServlet,在Web应用启动时完成。 然后在Jsp/Servelet中,可以通过Servlet Context取得ApplicationContext:
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(application); 但像singleton类或者EJB中,就没有Servlet Context可用了。 如果全部像UnitTest那样直接构造,速度就会很不堪。自然的,就想到把ApplicationContext做成单例。 Spring提供了 ContextSingletonBeanFactoryLocator这样的物体。
先搞一个beanRefFactory.xml,里面写上所有的applcationContext-*.xml文件名,并把Context命名为"default-context":
<beans> <bean id="default-context" class="org.springframework.context.support.ClassPathXmlApplicationContext"> <constructor-arg> <list> <value>applicationContext.xml</value></list> </constructor-arg> </bean> </beans> 然后让loactor去找它,但代码有点长:
BeanFactoryReference bfr = DefaultLocatorFactory.getInstance().useBeanFactory("default-context"); BeanFactory factory = bfr.getFactory(); MyService myService = factory.getBean("myService"); bfr.release(); // now use myService 上面的代码实在是太灵活,太麻烦了。 还不如自己实现一个简单的Singleton,扩展ContextLoaderListener类,在Web系统启动时压入Singleton。
新的ContextLoaderListener类重载如下,ContextUtil中包含一个静态的ApplicationContext变量:
public void contextInitialized(ServletContextEvent event) { super.contextInitialized(event);
ServletContext context = event.getServletContext(); ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(context); ContextUtil.setContext(ctx); } 用家可直接取用:
ApplicationContext context = ContextUtil.getContext(); 2.IoC fashion 如果所有地方都使用直接召唤系,那就反而是在打Rod的耳光了。因为他一直都反对代码与框架深耦合的。 所以,更好的方法是写一些glue code、base class来完成Spring的降临,而不让应用代码察觉Spring Application Context的存在。 不过,因为各个框架的结构不同,Rod也没办法讲出一个通用的整合方法,所以建议大家尽量学习已整合的各种框架,如Spring MVC、Struts的种种方式,写出自己的简单整合代码来。 只有不确定的调用某些Singleton类,不适合过早ioc的情况,可以使用直接召唤系。
作者: 江南白衣 每年的全球四大Java研讨会,它们的agenda,给大家提供了一个捉摸Java时尚风向的便利。 每年花几天看一遍它们的报道和share出来的slides,是CTO该做的事情。 PS. 如果你被邀在哪里做讲演,又想不到给下面那些似睡似醒的猪头说什么的,可以从中参考一二。 PS2.在迷宫一样的网站中翻滚了半个小时,把agenda和slides的链接都整理了出来,便人便己。 TheServerSide Symposium 对很多人来说,TheServerSide才是真正的Java官方社区-- 06年的agenda。 JavaPoils 欧洲最大的Java研讨会-- 05年报道, 04年完整Slides, 05年(1)pdf陆续补全中, 05年(2)pdf, 04年的talk (需简单注册)。 Java One 官方,官方.....-- 05年报道, 05,04年的ppt。 No Fluff Just Stuff tour 简称NFJS的大马戏团,最近的 Spring Experience也是和它一起搞的 -- 05年某次的报道, 过往的Agenda, Spearker的blog聚合。
作者:江南白衣
俗话说得好,没吃过猪肉不要紧,没见过猪跑路就很没面子了。新公司上班一周,主要就是看猪跑路,2005年末,一个典型的Java EE项目,场景是这样的:
1.一台内存强得变态的Sparc呼哧呼哧的在跑Oracle 10g。
2.它的一个兄弟,共享T3阵列,静静的跑vcs 为它做着双机热备份。
3.两台Weblogic 9做群集负责后台管理。 编程模式是最老土的struts+spring+hibernate,再蹭一点Ajax。
4.四台Weblogic 9做群集负责前台门户。 最直接的jsp + javabean,用weblogic的tag作了页面Cache。 weblogic还发布了一堆Web Service接口,也不时调用一下合作伙伴提供的WS。 最后还有一伙定时Task在奔跑,有些是自动改变帐单状态,有些是自动把数据导出,ftp到合作伙伴那。
5. 一台Crystal Reports XI 的报表服务器。 逻辑都用PL/SQL封装在SP和中间表里,设计报表时直接取用便是,不沾一丝Java代码的烟火。 PS. 这台也是唯一的Windows Server,
6. 还有一些跑Tomcat(省钱)的独立小应用,一些C写的任务,零散的分布在上面9台服务器的角落。
作者: 江南白衣 今天CSDN的头条是微软DSL 对决 UML,虽然不是什么新闻了,但还是很开心。因为我实在很不喜欢基于UML2.0的所谓MDA。 某人说,世界上没有无缘无故的爱,却有无缘无故的恨,尤其在网络上。 所以我很不喜欢UML三友。 因为( 非鱼批:不是说无缘无故么?) UML中除了Class图、顺序图、交互图,其他如部署图之类的,根本就是急就章,估计也就花了三友宝贵的十分钟设计出来的,也没多大用处。而Class图和顺序图,换作诸位看官,回家憋几天也能设计出个八九不离十的式样出来。就这么点东西,值得捧到高高的神坛上坐这么久不下来么? 第二不喜欢基于UML的MDA。UML作为沟通工具还好,但想用tagged value表达整个系统作为代码生成的依据,就像想拿XML来描述整个商业系统、商业逻辑一样。看这些年来,工具开发商浪费了这么多人月,除了实际帮了不少研究生的毕业论文外,再没多少成果了。(那些有限的生成效果,随便一个xml文件或者PowerDesigner放开手脚做一下也不差多少) 但就是这个三友和UML,把业界向更高一级语言迈进的希望死死绑在一辆战车上一绑就是好几年, 现在终于有一个出来搞局的了,而且还是手臂足够粗大的微软,就象Spring 搞了EJB2的局一样,怎不叫我这种蛮夷拍手叫好? 甚至不用管微软的设计最后是否成功(不过开发领域,微软还没有过完全失败的产品),只要把局搞乱,我就很高兴。何况,我也是个DSL爱好者。
作者: 江南白衣 昨天看J2EE 5规范的时候,八卦看了下如果自己要组装一个Application Server需符合的规范: EJB容器:
Enterprise JavaBeans (EJB) 3.0 (JSR-220)
Java Message Service (JMS) 1.1 Java Transaction API (JTA) 1.1 Java Authorization Service Provider Contract for Containers (JACC) 1.1 Java Platform, Enterprise Edition Management API 1.1 (JSR-77)Java Platform, Enterprise Edition Deployment API 1.2 Java EE Connector Architecture 1.5 Web:JavaServer Faces 1.2 (JSR-252)Servlet 2.5 JavaServer Pages (JSP) 2.1 Standard Tag Library for JavaServer Page (JSTL) 1.2 (JSR-52)Web Services:JavaAPI for XML Web Services (JAX-WS) 2.0 JavaArchitecture for XML Binding (JAXB) 2.0 (JSR-222)Web Services Metadata for the Java Platform 1.1 (JSR-181)Web Services for Java EE 1.2 (JSR-109)Java API for XML-based RPC (JAX-RPC) 1.1 SOAP with Attachments API for Java (SAAJ) 1.3 Java API for XML Registries (JAXR) 1.0 Other:JavaMail 1.4 JavaBeans Activation Framework 1.1 Streaming API for XML (StAX) 1.0 (JSR-173)
Common Annotations for the Java Platform 1.0 (JSR-250)Debugging Support for Other Languages (JSR-45) 再看 Geronimo的做法,不由觉得好好笑,它居然玩票式的组了一队开源软件来应付这些规范(不过止应付到J2EE1.4): 1. Tomcat/ Jetty ,应付了Web方面的Servlet 2.5 、JSP、JSTL。 2. Axis包了WebService方面的所有东西, Apache scout包JAXR。 3. OpenEJB 应付 EJB2.1,这是整个链条里最勉强的部分。另外它也准备EJB3的开发了。 4. ActiveMQ管JMS, MX4J管JMX, JOTM管事务, HOWL作事务日志。 5. WADI - a clustering, load-balancing and fail-over solution 具体请看 《 Geronimo!第 2 部分: 驯服 J2EE 1.4 这匹野马》 除了上述规范, Geronimo还整合了 Spring和支持JBI的 ServiceMix,一共用到了50多个开源项目,几乎把 Apache, CodeHaus上的项目一网打尽,伯乐过而北群空了。这样拉大旗建AppServer的方式,的确打破了某种市场状态,模糊了Application Server的界限,好好玩。 Geronimo这种疯狂整合靠的是它的GBean架构,具体看《 将第三方组件集成到 Geronimo 中》,而GBean之间的引用和交互,则靠 cglib生成的动态代理。有时间要具体学习一下这种全包容的架构,不知是先进还是落后。 PS . TSS 最近两天的三条消息1. Terracotta announces Clustered Spring Runtime --Terracotta 为Spring加入了集群能力。 2. JBoss adds Arjuna transaction engine -- Jboss整合了原来HP旗下BlueStone AppServer的事务技术,支持WebService事务。 3. jManage 1.0, JMX client, released-- 一个有Web版(这点比Mx4J好啊)和Console版的JMX client。 传统Applicaton Server供应商的日子越来越不好过了。
作者: 江南白衣 2005就这样完了, ONJava的年终总结: 2005 Year in Review。 TSS年初开会时讲得专家们自己都开始有点厌倦的EJB3,JSF1.2,Ajax,AOP的三宗合一,SOA和ESB,Groovy,还是没有一个stable的东西出来。 眼看2006,又是继续将这些话题变成产品的一年,让我们继续讨论厌烦: *Full stack Application Framework: Spring 2.0 Spring 2.0吹风会兼FB大会刚刚开过。夜观星象,Spring气数未尽,开源社区里也只它有资格不断整合别人。 另一个Stack名曰 RIFE,不过比较独。 另外,JBoss搜刮的JEMS (JBoss Enterprise Middleware)和JSF+EJB3的 Seam也会继续发音。 * Web Framework:JSF 1.2 最怕别人问现在开项目用哪个Framework好,选来选去暂时还是投靠标准好了。 不知道 Struts Ti, Struts Shale,Spring MVC的2006会怎样。 而Continuations这个名词明年也许会闪亮一下。 * Persist Framework: Hibernate 3.1 (EJB3/JPA1) 在 RoR的Active Record刺激下,annotaion 和default mapping终究要替代xml描述文件。 另外,除了麻烦的ORM,也很希望有一个极简的JDBC Framework,不知道JDBC4.0和Spring跑JDK1.5的SimpleJdbcTemplate什么样子。 *Web Service Framework:XFire (JAX-WS2.0、JAXB 2.0) SOA 风潮下的next-generation SOAP Framework,支持JavaEE 5的JAX-WS2.0、JAXB 2.0与annotation,还拖上了 Spring的手。 Axis的事实标准地位该不保了吧。 *JBI-ESB:ServiceMix
2006年的新大热名词--JBI(Java Business Intergrade)与ESB(Enterprise Service Bus)。 *Java Rule Engine与JDM 2.0:Drools Rule Engine和Data Mining 已经说了很久,不知道明年又如何。但Drools则演绎了一条标准的成名路: 1.先入CodeHaus再入Jboss 2.(号称)集成Spring 3. 提供Eclipse的插件 *动态语言嵌入:Groovy 期待在Ruby的不断刺激下,1.0正式版发布后的正式用家。 *some Ajax Framework Buffalo, Prototype, Dojo, MochiKit, DWR 混战之下总该有脱颖而出者吧? *AOP三宗归一 虽然大家还很少在应用中使用它,AOP在Spring 中的作用却非常明显。不知道Spring2.0是否可以三宗归一,给出一个框架设计时使用的简单方案。
作者: 江南白衣 今天的一条八卦,在Asp.net 2.0与 Rails系 RoR/ DJango/ Turbogears的两面夹击下,Java Web Framework的大佬们终于看到狼来了,坐下来,吃个包,开始商量合作。 消息在TSS主编 Dion Almaer的Blog上看到,再看这个 Java Web Alignment Group ,果然阵容鼎盛,36个Member,江湖上大部分大佬都到齐了。 Yahoo Group免费参观,不过他从2005.11.10号开始就已经没有贴子---歇菜了。
Framework |
Group Members |
Beehive |
Rich Feit |
AppFuse |
Matt Raible |
JavaServerFaces |
Ed Burns, Kito Mann, Craig McClanahan, Roger Kitain, Jacob Hookom, James Mitchell, Adam Winer |
MyFaces |
Bill Dudney, Ted Husted, James Mitchell, Travis Reeder |
Seam |
Gavin King, Jacob Hookom |
RIFE |
Geert Bevin, JR Boyens, Keith Lea |
Spring MVC and Web Flow |
Alef Arendsen, Keith Donald |
Stripes |
Tim Fennell |
Struts Classic |
Don Brown, Ted Husted, James Mitchell, Hubert Rabago, Niall Pemberton |
Struts Shale |
Craig McClanahan |
Struts Ti |
Don?, Rick?, Patrick?, James? |
WebWork |
Patrick Lightbody |
Wicket |
Eelco Hillenius | 上面的名单已成历史,唯一有趣的是Tapestry并不在列。 这个Group的最后成果就是Struts和Webwork上演了一出你的名字我的名字的 Struts Ti 。---"以Struts为名字,Webwork为核心,加上Beehive的annotataion和pageflow,再提升与JSF的集成能力"。可惜Spring MVC暂时不会加入,而JSF系如何合并还未知。最期待的,是它的Phase 2--zero congfig file。
作者:江南白衣
一年前,RIA新浪潮。 1.以新的Web控件代替复杂dhtml对控件的模拟; 2.以重返C/S的用户体验代替传统http的提交-返回模式,开发模式上甚至可以直接调用商业对象。 RIA一出现就尽获民心。但,Flex因为收费,XUL因为终端,XAML因为无期,OpenLaszlo因为出身与性能.......渐渐退出了大家的嘴边,他们也的确不争气,又一年过去了,都没再弄出大的声响。
这一年大家做什么呢,是忽然走红的ajax,来实现RIA中不刷新页面的承诺,还有高级如DWR,JSON-RPC,同样实现RIA中对商业对象的直接调用。 之前有ECHO2,而最近出现的一个框架叫ZK1,开发人员用XUL来开发,然后臂大力雄的框架会把XUL渲染成dhtml+ajax,算是一种有趣的思路。 但我还是觉得,浏览器应该升级,而不是靠复杂的dhtml+ajax来模拟,我是革命派,不是改良派,相对于全体民众花在模拟上的成本,浏览器的升级要简单得多。
前几天因为想在blog上弄点小花样,去了基于OpenLaszlo的blogbox。再回头,发现OpenLaszlo已经发布到3.1版本。
OpenLaszlo 3.1版本升级良多,已解决性能与中文问题。 *新版本可以编译为Flash 6、7、8的格式,性能上突飞猛进,不再是以前吃资源的巨怪。 *支持Unicode,支持中文了。 *支持SOLO deploy了,也就是不再要求Servlet Container,也可以deploy到IIS和Apache。 其他还有Drawing API,Charting Components,Dynamic Libraries,Ajax API等一系列升级。
OpenLaszlo3.1的编程体验 1.不愧曾是.com的产物,在Windows 下点了两下next就装完了,而且已有了整套的开发环境,10秒钟之后,我开始在my-apps目录写我的helloworld.lzx,然后刷新页面看结果。 2.XML格式的控件定义,JavaScript作为脚本语言,再加上完备的tutorial、reference文档和demo code,又和wxWidgets那样,基本上没什么特别要学的东西,直接可以开始编码了。
3.为什么RIA要比模拟RIA要好? 开篇两点之外,OpenLaszlo还可以自由定义控件的layout,比用table、div的做法自由。 另外,OpenLaszlo还可以简单的利用现有控件,定义新的控件和式样。
对OpenLaszlo有不满意吗? 有阿,用户社群太少。还有控件的默认式样也比Flex的差一截,虽说可以自己customize,但不是每个人都那么有空的呀。还有那个IBM友情客串的IDE,啥时候才弄得像个样嘛。
Flex ,XUL又在做什么? Flex2 摆出的阵仗显然胜于OpenLaszlo: Flex Framework 2, Flex Builder 2,Flex Enterprise Services 2,Flex Charting Components 2 但,公无收费,公竟收费,&*(^%,当奈公何。
XUL呢,新出的Firefox1.5只是Firefox1.0的补完,看不出FF2.0的痕迹,一年了。
作者: 江南白衣 反射、Proxy和元数据是Java最强的三个特征,再加上 CGLib (Code Generation Library)和ASM,使得Java虽然没有Ruby,Python般后生可畏,一样能做出强悍的框架。 Proxy可以看作是微型的AOP,明白提供了在继承和委托之外的第三个代码封装途径,只要有足够的想象力,可以做得非常好玩,Spring的源码里用Proxy就用得很随便,看得我非常眼红。可惜Proxy必须基于接口。因此Spring的做法,基于接口的用proxy,否则就用cglib。AOP么,一般小事非compoent一级的就不麻烦AspectJ出手了。 cglib的Enhancer说起来神奇,用起来一页纸不到就讲完了。 它的原理就是用Enhancer生成一个原有类的子类,并且设置好callback到proxy, 则原有类的每个方法调用都会转为调用实现了MethodInterceptor接口的proxy的intercept() 函数: public Object intercept(Object o,Method method,Object[] args,MethodProxy proxy) 在intercept()函数里,你可以在执行Object result=proxy.invokeSuper(o,args);来执行原有函数,在执行前后加入自己的东西,改变它的参数值,也可以瞒天过海,完全干别的。说白了,就是AOP中的around advice。 AOP没有出现以前,该领域经典的设计模式是Decorator,像Java IO Stream的设计就是如此.不过,如果为每个DAO, 每个方法的写Decorator函数会写死人的,所以用上cglib的好处是一次过拦截所有方法。
另外,cglib除了Enhancer之外,还有BulkBean和Transform,都是Hibernate持久化的基础,但文档贫乏,一时还没去看怎么用。
1.AOP里讲了一百遍阿一百遍的log aspect在cglib是这样做的:
public class LogDAOProxy implements MethodInterceptor { private Logger log=Logger.getLogger(LogDAOProxy.class); private Enhancer enhancer=new Enhancer(); //返回DAO的子类 public Object getDAO(Class clz) { enhancer.setSuperclass(clz); enhancer.setCallback(this); return enhancer.create(); } //默认的拦截方法 public Object intercept(Object o,Method method,Object[] args,MethodProxy proxy) throws Throwable { log.info("调用日志方法"+method.getName()); Object result=proxy.invokeSuper(o,args); return result; } }
应用的代码: LogDAOProxy proxy = new LogDAOProxy(); GoodsDAO dao = (GoodsDAO)proxy.getDAO(GoodsDAO.class); dao.insert(goods); 2.而在Spring的管理下应该略加修改的高级Decorator
上面的例子用 return enhancer.create();创建子类实例,但在Spring管理下,一些Bean的实例必须由Spring来创建和管理,而不由enhancer来创建的。所以我对上述用法略加修改,使它真正当一个Proxy的角色,请对比黑体字的部分
public class LogDAOProxy implements MethodInterceptor { private Logger log=Logger.getLogger(LogDAOProxy.class); private Object dao=null; private Enhancer enhancer=new Enhancer(); //返回DAO的子类 public Object getDAO(Class clz,Object dao) { this.dao = dao; enhancer.setSuperclass(clz); enhancer.setCallback(this); return enhancer.create(); } //默认的拦截方法 public Object intercept(Object o,Method method,Object[] args,MethodProxy proxy) throws Throwable { log.info("调用日志方法"+method.getName()); Object result=proxy.invoke(dao, args); return result; } } 可见,原来模式里在getDao()时由enhancer创建dao,而 调用intercept时则将enhancer创建的dao以Object o参数传回。 而新模式里,dao在getDao()时从外面传入,enhancer.create()返回的是一个proxy. 而调用intercept时,实际会用之前传入的dao进行操作,而忽略Object o参数传入的proxy. 有点遗憾, intercept函数里MethodProxy的Signature是固定的 , 即客户如果调用foo(String),你不可以用proxy.invoke偷换成foo(String,String); 系列文章: Java下的框架编写(1)--序Java下的框架编程(2)-对泛型的无聊用法和为擦拭法站台 Java下的框架编程(3)--关于反射的碎话 Java下的框架编程(4)--Annotation vs XML vs Interface 最新一Round Java下的框架编程(5)--cglib应用Java下的框架编程(6)--asm(待写)
作者: 江南白衣 1.因为两者的用途不同,所以Annotation与XML应该并存
Anootation vs XML 到了现在,在Spring和EJB3各占一边的持续演示下,各自的用途已清晰。 虽然两者之间完全可以相互替代,没有绝对不能做的事情,但却存在好不好的问题,两者的用途不同,应该并用: "size=10,db_user=ito"这样的参数,仍然适合放在XML,YAML(ruby),properties,ini文件里。 而Annotation中所放,是真正程序的一部分,是旧编程体系中所缺的那一块东西。 看看编程语言的发展: 一开始只是函数的封装; 到了OO语言,对象有了自己的属性和方法; 到了框架满天飞的年代,这些属性和方法又有了自己的属性,来告诉框架如何为自己提供服务。比如Spring和EJB3,POJO就用配置信息来告诉框架无侵入的提供服务。整个进化的过程非常自然。 因为这些信息本来就是程序的一部分,所以应该仍然放在Code里头,Spring把它割裂到XML明显影响了代码的阅读。 2.Anotation/XML PK Interface,Spring 无侵入性的基础 切尔斯基的Blog讲了Annotation/XML 对Interface的PK。这次PK,也可以认为是Spring 对 EJB2.1在框架无侵入性上的一次PK。 在EJB2.1时代,POJO必须通过接口来向框架声明一些东西,这就造成了框架的侵入性,强迫POJO实现一堆接口。而Spring,把这些元信息搬到了XML配置文件。 在Spring里随便就可以举个例子。比如一个POJO,在Spring为它进行依赖注入A和B后,需要根据A和B来装配一个内部属性C,这样就需要再跑一个init()函数。Spring提供两种方式,一种侵入性的,实现InitializingBean接口的afterPropertiesSet()函数供Spring调用。 而另一种是无侵入性的,在Bean的xml节点里面自行定义init函数的名字。 3.Annotation目前的弱点
一是Hibernate、Struts、三姑妈、四姨婆的annotation如果一股脑儿的全堆在可怜的POJO上很没人道,如果三姑六婆都抢Transation这个Anontation就更惨了。 二是annoation的表达能力有限,不如XML的强。 4.JSR250 - Common Annotations for the Java Final Draft已经发布,八卦回来一看,也只是多定义了几个Common Annotation而已。 1.Generated 自动生成的代码要用此声明,而且必须说明工具的名称,如@Generated(“com.sun.xml.rpc.AProcessor”) 2. Resource/Resources 就是EJB3里面用的资源引用。 3.PostConstruct / PreDestroy 声明那些如题的函数。 还有一些安全方面的annotation,不关心。 文章:Java下的框架编写(1)--序Java下的框架编程(2)-对泛型的无聊用法和为擦拭法站台 Java下的框架编程(3)--关于反射的碎话 Java下的框架编程(4)--Annotation vs XML vs Interface 最新一Round Java下的框架编程(5)--cglib应用Java下的框架编程(6)--asm(待写)
作者: 江南白衣 不知道明年今日,会不会出现一队只会用Ruby On Rails的毕业生,像当年的asp、jsp、php迅速剿了C++/perl的CGI那样,把我们给剿了。同好们劝我,根据大公司经济学,这基本不会发生。 在茫茫的框架之海认出一个Rails框架,基本上靠四个特征 1.一门动态语言 2.一个extreme simple to use的ORM框架 3.一个extreme simple to use的MVC框架 4.一些自动生成代码的命令、模版 其余ajax、web service、i18n等特性自由扩展 1.Ruby: Ruby on Rails Rails系的旗手,一己之力搞得J2EE阵营鸡飞蛋打。 旗手的作用表现在: *最接近1.0的版本,目前已出到最后一个RC版 1.0 rc4(0.14.3) *拥有一本amazon超级畅销的《Agile Web Development with Rails》,而且这本书的组织也好,part I是一个渐进的sample application 让你快速入门,partII是几个重要领域的深入介绍。 *拥有自己的IDE: RadRails ,基于Eclipse但独立成军,目前出到0.5。(是不是怕惨了Eclipse的多变,现在这些IDE的发行版本开始反包含了Eclipse在内。) 2.Python: DJango、turbogears 认识不深,所以 DJango请看 limodou的blog, turbogears看 xlp123的。 3.Groovy: grails 如果能顺产,绝对是J2EE阵营里感情分最高涨的项目。因为它语言用Groovy,ORM用annotation版Hibernate,MVC用Spring。不用担心它换汤不换药,因为经过extreme的封装,再结合Groovy,绝对不再是原来的Spring+Hibernate,而是和RoR差不多的一样东西了。不信可以看看他的Sample。 不过这个项目的源码目录树非一般的乱,也还没有0.1版释出。还有一样奇怪的事情,这个Groovy项目,大多数的class代码都是Java写的。 4.Php: symfony ,cake 据说 cake比 symfony弱非常多,所以没看。 symfonys是基于php5的项目,成功整合了 Propel(ORM)、 Mojavi3(MVC),再配合自动生成的脚本打造而成。看他的sample,最后整合出来的东西也很Rails了,除了ORM层的xml文件。 还有一个发现是Php项目现在可以用pear来安装,很像Ruby的gem,Java的Maven要努力了。
C:/>pear channel-discover pear.symfony-project.com C:/>pear install symfony/symfony 这样就装完了symfonys和propel&croel, mojavi3,还有用来运行脚本命令的pake(php make),PHing(php ant?),一大堆东西。
佩服 david turing,独自张罗了 BEA广州User Group这台一百二十人的大戏。 如果有什么意见,就是这一百二十对目光,太严肃了。所以今天能顶住这么多眼镜反射,站到讲台上的都是好兄弟(姊妹)。 而我期望的UG有一种更relex的style,一面喝酒一面听歌一面看日落,超过千人鸦雀无声的呆望咸蛋黄般的落日悄然没入大海,当最后的阳光消失时,全场千人竟然一齐拍手喝彩,有如目击欧洲杯黄金入球,场面好鬼"娘"...... 很明显,刚才说的是Cafe del Mar。转回现场实况报道:今天群里出现了cyt、rayman、pqf、ytam、GTM、小小强、yok、sparkle、瀚海、翱翔和我,刚好够一桌。 讲演报道 去得比较晚,没看到Bea工程师的讲演。看到身为Promgrammer粉粉团家嫂的shallon讲Spring(由于彭羚同学惯称商台家嫂,所以cyt偶像的shallon亲爱也可称为...照片在 dev2dev),讲稿是一份非常Professional的内部培训材料,力挺之下,被david.turing误报为too simple,特此勘误:( 另一位是Hongsoft同志,不过隔行与隔山,工作流方面完全不懂,ppt上都是一堆不认识的名词,遂十分钦佩之(如果你在演讲过程中不要老点我名字我会更钦佩你,下次轮到我讲的时候,嘿嘿....),并理解为是在讲软件命名风水学,哪个旺,哪个不旺,最后是BPEL胜出。(但cyt偶像隔完又隔了几行之后,仍然觉得像是为了兼顾到场领导的科普教育,too simple,这就是当偶像的资本) 全场笑位 全场最大的笑位hongsoft刚上来,很谦虚的讲,“本来想趁刚才的时间复习一下讲稿的,但因为前面的演讲太精彩,所以我... ” ,“睡着了...” ytam忽然接了一句。方圆几米内笑倒一片。这个故事告诉我们,当下面有ytam这么恐怖的存在时,有话一定要一次说完。 其余八卦 茶会开始的时候,GTM说,明白为什么有的同志坐到山顶了,原来那里才是上菜位。我们这些坐一二排握手位的反而......于是一帮人又接着去澳门街FB,而且消灭的速度一流。 还有,因为GTM上次偷拍的失手,今天大家看到GTM的手机都像见到鬼似的..... 还还有,今天cyt偶像拿到了ytam那本绝版的《C++ Template Complete Guide》 中文版,我也想要阿。以后大家可以多点利用聚会的机会交换东西。
作者: 江南白衣 充分体验到知识循环再用的好处,原本对 Python、 wxWidgets没有接触的,天黑天亮之间,已经作了一个半成品的桌面程序出来。 1.选型 通常选型之后,都会迫切的告诉别人自认为正确的原因,这时候路过的人就比较不幸了。 我选Python和wxWidgets,是因为....... 因为是发布到网上的小程序,要它很小,Java和.Net这两个还算当红但要装虚拟机的笨家伙最先out了,而Python在 py2exe之后压成rar才3M,如果有心思还可以弄得更小。 选 wxWidgets是因为它可以通行于Windows,Linux两个位面,另外 Fox也能通用,不过wxWidgets是像SWT一样用Native Widgets的,在WinXP上比较好看。 用Python而不是C++,是为了快速开发。当然,心底里其实是贪好玩。本来喜欢Ruby的语法更纯洁一些,可惜 wxRuby已经太久没更新了。 2.wxWidgets 所谓GUI框架,万变不离下面几点: 1.框架结构 拿个HelloWorld一看就懂,又是Application->Frame->Menu 的标准架构。 2.wxWidgets用法 来来去去还是Text框,选择框,按钮几个老面孔,在 wxPython上把wxPython2.6-win32-docs-demos-2.6.1.0.exe档下载回来,就有C++版本的API手册与python版本的每个widgets的Demo Code。 3.控件与页面的Layout 一种方式是C# Winform和Swing那样在程序里生成组件和layout,经历过SWT手写代码画页面的折磨,再看到一层又一层的Container代码(wxWidgets里是Sizer)已经不觉得麻烦了。也有所见即所得的工具如 BOA,不过毕竟没有Visual Studio for WinForm那么好,难以真正使用。 一种是像Delphi, VC或未来的XAML那样把控件和layout记在XML文件里。但我没有用。 4.事件分发机制 像 EVT_BUTTON(self,ID_UPLOAD, self.onUpload)这样的代码,挺简单的。 可见,只要有过GUI编程的经验,再学wxWidgets 很容易。 参考书:《Cross-Platform GUI Programming with wxWidgets》 《wxPython in Action》 3. Python 手边放一本Python的参考书,只要对动态语言有点感性认识,对着Sample Code能能猜就猜,猜不到就拿chm版的参考书来索引,也很容易入门。 最难的地方发生在遍历目录,那时候已经有点困了:
for root, dirs, files in os.walk('C:/projects/'):
print sum(getsize(join(root, name)) for name in files) 这是什么见鬼语法阿!! 原来os.walk('C:/projects") 的返回值是一个tuple。在 C++ Boost库中接触过这个概念,平常函数都只能返回一个值,而tuple可以让你返回多个(这样就不用利用传址的参数来返回啦),所以就有了for root,dir,files in os.walk()这样的句子。 还有 print join(root,name) for name in files,原来python还有这种把闭包写在for的前面的简写法。 IDE最后还是用了Eclipse的插件 PyDev,毕竟Eclipse看着比较舒服,其他编辑器做得那么难看,怎么还好意思收钱。 4.美化界面 因为wxWidgets用的是native widgets,不像Delphi,C# 和Swing有专门的look and feel 美化控件,所以美化的主要方式是为Toolbar和Button配上好看的图标,还有修饰整个软件的配色。 推荐Tango一个图标库: http://tango-project.org/ to make open source software beautiful...说出了我的心声啊,"顶尖儿的程序员必有完美主义艺术家之倾向。",目前的图标还不多,迅速更新中。
作者:江南白衣
记者:你最讨厌记者问什么问题? 黄伟文:嗯,那些问题里面带最字的.....
所以,题目里面那个"最"字可以完全忽略不计,本文是用来记录那些自己喜欢,但名声没有Spring、Hibernate般响亮的项目:
Xfire:http://xfire.codehaus.org Next-generation SOAP Framework,使用Stax,支持JavaEE 5一系列最新标准,支持各种Binding和自己最简单的Aegis Binding,还拖上了Spring的手做到非常简单的发布。Axis的事实标准地位该不保了吧。
Grails: http://grails.codehaus.org Groovy On Rails,底层使用封装过的Hibernate和Spring,Javaer们最最亲切的Rails--见 各系Rails大点兵
Drools:
http://labs.jboss.com/portal/jbossrules
开源规则引擎里最好的了,虽然比不上死要钱的ILog。但加入了JBoss阵营已经很强悍,有IDE,有很流氓的DSL写法,语法也已非常贴近ILog. 找个好靠山,支持Spring,增加IDE Plug-in,这几乎成了每个开源方案的成名之路。
ExtremeTable: http://www.extremecomponents.org DisplayTag 的Killer。没想到TagLib日渐式微的时候,还有Extreme Table这么设计优良,身光颈靓的尤物 new born,实在鼓舞人心。目前的功能已经强了DisplayTag好多个马位,但站长依然雄心勃勃的继续着RoadMap。
Pentaho: www.pentaho.org 商业智能方案,最核心还是基于Mondrain+JProvit的经典穷人OLAP通用方案,但在整个流程和工具上花了很多功夫。 Compass: http://www.compassframework.org/ 基于已成事实标准的Lucene,又和Spring,Hibernate搞在一起的全文搜索方案,是集成方案,not only 引擎。
Daffodil Replicator: http://www.daffodildb.com/replicator/ 通用的多数据库synchronization方案,能够通过配置策略解决数据库异构和数据冲突。
LifeType: http://www.lifetype.net/ php的成熟多用户Blog应用,原名Plog,有着很好的插件机制,对php的OO、模板、adodb应用都非常成熟,是个学习php应用的蓝本。Javaer整天忙着换框架,根本没时间沉淀出这样成熟的应用。
Joomla: http://www.joomla.org/ php的CMS 方案 Mambo的开源分裂版,基础的MVC架构比XOOPS弱,但长得好看就是她的资本。
随时更新中.....
反射,所有教科书都正儿八经的讲了,这里只能再随便讲两句。 反射是一种让框架能够根据 "以字符串形式存在的信息" 来调用对象的属性和函数的技术,是Java对C++最大的进步之一---让框架编程真正走向平民化。MFC年代,无论侯捷如何深入浅出,还在念大学的我就是搞不懂那些注册"消息--函数映射"的魔法宏。 不过Java的反射也就是对着C++比较自豪而以,因为C#,Ruby,Python甚至php都标配了反射的功能。而且,人家的反射语法都是内嵌在基础Object类的,拿最弱的php来看:
$func_name="helloworld"; $foo->$func_name; 而Java,却搞出了Class,Methed, Field,Constructor这么一大堆类出来。本来这是Java设计师很严谨,很cool的体现,问题是它居然不提供一种集成的简便的写法......相同的情形还出现在Java的I/O 类库里。 微软这方面就做得好些,懂得讨好开发人员。 因为Java的无情,就搞得大家的项目里要自制BeanUtils了。幸亏 Apache Jakarta Commons 已经做了一个比较好的,可以直接使用-- 以前写的介绍文章。 另外Spring也做了一个。 闲得没事做的,还可以emule一本〈Relection in action〉回来看。 而C++下面的"反射",见 我偶像di文章。另还有一个比较BT的C++框架叫 ACDK的,把自己整得和Java很像,有反射和垃圾收集,甚至和JSDK差不多的线程,Unicode,I/O,网络,XML API。可惜的是,即使到了C++0x, B大叔还是不准备在语言级支持反射。 系列文章: Java下的框架编写(1)--序Java下的框架编程(2)-对泛型的无聊用法和为擦拭法站台 Java下的框架编程(3)--关于反射的碎话 Java下的框架编程(4)--Annotation vs XML vs Interface 最新一Round Java下的框架编程(5)--cglib应用Java下的框架编程(6)--asm(待写)
作者:江南白衣 从8i到10g,Oracle不断进化自己的SQL Tuning智能,一些秘籍级的优化口诀已经失效。 但我喜欢失效,不用记口诀,操个Toad for Oracle Xpert ,按照大方向舒舒服服的调优才是爱做的事情。
1.Excution Plan Excution Plan是最基本的调优概念,不管你的调优吹得如何天花乱堕,结果还是要由Excution plan来显示Oracle 最终用什么索引、按什么顺序连接各表,Full Table Scan还是Access by Rowid Index,瓶颈在什么地方。如果没有它的指导,一切调优都是蒙的。
2.Toad for Oracle Xpert 用它来调优在真的好舒服。Quest 吞并了Lecco后,将它整合到了Toad 的SQL Tunning里面:最清晰的执行计划显示,自动生成N条等价SQL、给出优化建议,不同SQL执行计划的对比,还有实际执行的逻辑读、物理读数据等等一目了然。
3.索引 大部分的性能问题其实都是索引应用的问题,Where子句、Order By、Group By 都要用到索引。 一般开发人员认为将索引建全了就可以下班回家了,实则还有颇多的思量和陷阱。
3.1 索引列上不要进行计算 这是最最普遍的失效陷阱,比如where trunc(order_date)=trunc(sysdate), i+2>4。索引失效的原因也简单,索引是针对原值建的二叉树,你将列值*3/4+2折腾一番后,原来的二叉树当然就用不上了。解决的方法: 1. 换成等价语法,比如trunc(order_date) 换成
where order_date>trunc(sysdate)-1 and order_date<trunc(sysdate)+1
2. 特别为计算建立函数索引
create index I_XXXX on shop_order(trunc(order_date))
3. 将计算从等号左边移到右边 这是针对某些无心之失的纠正,把a*2>4 改为a>4/2;把TO_CHAR(zip) = '94002' 改为zip = TO_NUMBER('94002');
3.2 CBO与索引选择性 建了索引也不一定会被Oracle用的,就像个挑食的孩子。基于成本的优化器(CBO, Cost-Based Optimizer),会先看看表的大小,还有索引的重复度,再决定用还是不用。表中有100 条记录而其中有80 个不重复的索引键值. 这个索引的选择性就是80/100 = 0.8,留意Toad里显示索引的Selective和Cardinailty。实在不听话时,就要用hints来调教。 另外,where语句存在多条索引可用时,只会选择其中一条。所以索引也不是越多越好:)
3.3 索引重建 传说中数据更新频繁导致有20%的碎片时,Oracle就会放弃这个索引。宁可信其有之下,应该时常alter index <INDEXNAME> rebuild一下。
3.4 其他要注意的地方 不要使用Not,如goods_no != 2,要改为
where goods_no>2 or goods_no<2
不要使用is null , 如WHERE DEPT_CODE IS NOT NULL 要改为
WHERE DEPT_CODE >=0;
3.5 select 的列如果全是索引列时 又如果没有where 条件,或者where条件全部是索引列时,Oracle 将直接从索引里获取数据而不去读真实的数据表,这样子理论上会快很多,比如
select order_no,order_time from shop_order where shop_no=4
当order_no,order_time,shop_no 这三列全为索引列时,你将看到一个和平时完全不同的执行计划。
3.6 位图索引 传说中当数据值较少,比如某些表示分类、状态的列,应该建位图索引而不是普通的二叉树索引,否则效率低下。不过看执行计划,这些位图索引鲜有被Oracle临幸的。
4.减少查询往返和查询的表 这也是很简单的大道理,程序与Oracle交互的成本极高,所以一个查询能完成的不要分开两次查,如果一个循环执行1万条查询的,怎么都快不到哪里去了。
4.1 封装PL/SQL存储过程 最高级的做法是把循环的操作封装到PL/SQL写的存储过程里,因为存储过程都在服务端执行,所以没有数据往返的消耗。
4.2 封装PL/SQL内部函数 有机会,将一些查询封装到函数里,而在普通SQL里使用这些函数,同样是很有效的优化。
4.3 Decode/Case 但存储过程也麻烦,所以有case/decode把几条条件基本相同的重复查询合并为一条的用法:
SELECT COUNT(CASE WHEN price < 13 THEN 1 ELSE null END) low, COUNT(CASE WHEN price BETWEEN 13 AND 15 THEN 1 ELSE null END) med, COUNT(CASE WHEN price > 15 THEN 1 ELSE null END) high FROM products;
4.4 一种Where/Update语法
SELECT TAB_NAME FROM TABLES WHERE (TAB_NAME,DB_VER) = (( SELECT TAB_NAME,DB_VER) FROM TAB_COLUMNS WHERE VERSION = 604)
UPDATE EMP SET (EMP_CAT, SAL_RANGE) = (SELECT MAX(CATEGORY)FROM EMP_CATEGORIES)
5.其他优化 5.1RowID和ROWNUM 连Hibernate 新版也支持ROWID了,证明它非常有用。比如号称删除重复数据的最快写法:
DELETE FROM EMP E WHERE E.ROWID > (SELECT MIN(X.ROWID) FROM EMP X WHERE X.EMP_NO = E.EMP_NO);
6.终极秘技 - Hints 这是Oracle DBA的玩具,也是终极武器,比如Oracle在CBO,RBO中所做的选择总不合自己心水时,可以用它来强力调教一下Oracle,结果经常让人喜出望外。 如果开发人员没那么多时间来专门学习它,可以依靠Toad SQL opmitzer 来自动生成这些提示,然后对比一下各种提示的实际效果。不过随着10g智能的进化,hints的惊喜少了。
7. 找出要优化的Top SQL 磨了这么久的枪,如果找不到敌人是件郁闷的事情。 幸亏10g这方面做得非常好。进入Web管理界面,就能看到当前或者任意一天的SQL列表,按性能排序。 有了它,SQL Trace和TKPROF都可以不用了。
作者: 江南白衣 除开五大或者ThoughtWorks这种要什么有什么,进去做打字也能光耀门楣的不谈。如果是嫁到一个普通软件公司,怎样的环境才能最快的成长呢? 首先基本的 公司项目管理水平是必要的;其次是稳健而不保守的公司技术选型和一班能沟通的同事。 更重要的,是要有一个严苛的环境,那些古训说的都没错,越是严苛,成长越快。 然后有些引导与助力,让你在严寒中节省体力,过得好些的,就是最佳的成长环境了。 一,最复杂多变的业务规则,最难侍候的客户
大多数人碰上这两样东西都是愁眉苦脸,天天抱怨。其实应该把它视为入门锻炼的: 第一阶是努力用细密的编码迎合复杂的业务,以金牌服务的态度接受客户的善变和每样需求都要24小时有取的bt。充分打磨过的眼耳口心,才是个合格的IT人。如果业务规则都清的像水,项目时时都是以我为主的,反是在做toy application,不算入了IT的门。 打磨之后,如果肯静下心来总结,设计架构如何适应改变,流程如何做到快速更新部署,就是第二阶段的进步了。 一直做ERP,自问有足够复杂的业务(因为不熟悉业务,有些不复杂的也变复杂了)和麻烦的客户(自己不是大公司,麻烦的客户就会很多),但在第二阶段还是不很静得下心。 二,最严格的性能要求,准确性要求,错误恢复要求 最好是那种每天N万人访问,几亿条数据。还有准确性很严格,分分钟几十万上下,如果崩机又要迅速完全恢复状态的项目。 每天几万人访问的项目没做过,遗憾。 几千万条数据的项目倒是每天面对,优化学了一点,但没有充分利用严格的环境去追求改进,遗憾。 ERP的报表倒是经常会搞到几十万上下的差额,但一直重视不足。 崩机恢复是最近的项目要求,更爽是这个项目澳国政府居然有一份规范,我说的助力就是指这些了,不用自己慢慢摸索而且经常摸错地方。 三,最底层的编码 不要老是高高在上的搞ERP搞.com,偶然尝试一下用到起码C一级的语言,和硬件打打交道,直接写IO口阿,中断阿,都是有就不要放过的锻炼。 没做过底层编码,只会纯软件的IT人的感觉是不完整的。 刚好公司最近的项目有要求,捧一本 〈Linux Device Driver〉看看。
四,最高层的设计 设计、框架--技术人一听就眼红的字眼。但不是每个公司都搞很产品化的项目,或者在项目里自写类库重做轮子。所以,除了刚入行的那段疯狂日子,很高阶的设计其实我也没做多少,多数时间都是应用层的开发。
虽然自己不写,但却经常都要进行框架选型,也算是蒸发智力的一个地方。Pragmatic Programmer里说的critical的态度很重要,Spring好么?一定要想清楚它好在哪里,不要糊里糊涂的看着quick start就入局了,浑忘了without Spring的世界是怎样的。
另外,因为有时候开源软件有bug,或者要增强它来吻合项目需求,或者有错了不明就里时直接读源码会更快找到错误。这样就接触到不少优秀开源项目的源码,比如Spring,无形中也会学到他的设计。 如果说Java盛产框架型的项目,php的项目则多是熟透了的Web应用。最近发现php不是以前的php了,应该算入python,ruby一类的动态OO语言,它的那些著名项目一样有着很好的MVC框架。细看之下学到应用设计方面的不少东西。 一阵发呆打了这篇字,其实也是提醒自己,目前的环境可以,应该以更好的心态接受更严苛的历练,那些古训说的都没错。
作者: 江南白衣 《Modern C++ Design》里的Policy-Base Class是Cpper得意的一样事情; Spring 式IoC container 的依赖注入是Javaer得意的一样事情; Ruby的Mixin特性是Rubyer得意的一样事情。 有趣的是,各自得意的事情,指向的是同一个问题:多重行为的组合。 1 .Policy-Base是混合使用模板与C++的多重继承达成的: 最终类多重继承模版类,由模版传入实际的行为类(Policy Class)。
template <class CheckingPolicy> class SmartPtr : public CheckingPolicy {...};
typedef SmartPtr<NoChecking> noCheckPtr; 上段代码,在编译期把NoChecking类传入到SmartPtr中,组合成noCheckPtr类。而实战中,还会用到"template template parameter".... 2 .Java则紧守最古老的委托模式来达成: 最终类拥有实际施行各种行为的行为类的指针。所有最终类的方法都将委托给行为类来执行。如果行为多样时,采用基于接口编程。同时利用Java的反射特质,用IOC Container根据配置实现注入的自动化。 3. Ruby则倚仗自己的动态特性,直接在语言中内建了Mixin特性。
module Greetable def greet puts "Your age is, " + self.age end end
class Person include Greetable def initialize(name, age) @name=name @age=age end attr_reader :age end
person=Person.new("Bruce",40) person.greet
Your age is 40. 此段代码将Greetable类Minxin进了Person类里头,让其拥有了greet方法。 也多亏了Ruby的动态性,让Greetable可以打印一个自身毫不知情的,其实属于Person的属性age. 就因为同一样事情还有着C++模板、传统Delegate和新兴动态Minxin的选择,让我们这些工蚁,还觉得有些许的自由和左顾右盼的乐趣。
作者: 江南白衣 昨天翻翻《程序设计实践》的Debug一章,里面用C写的例子早已被风吹的没了颜色,不随语言流转的就只有结尾那几句经验谈。但大学里向来是连这几句话也懒得教的,一定要大家从“put print statements in the program to find the bug” 开始,和bugs共同生活几年后,自个养成条件反射式的debug习惯。 面对Bug,正确的生理反射应当是找线索而不是直接跳到Step 2蛮干: 一、找熟悉的模式。人应该了解自己当然也包括自己常犯的错误,还有是检查那些经常犯事的代码模块。 二、最近改过的代码。 三、如果错误是由特定数据和操作引起的,思考这些输入的特征。 四、如果是系统模块输出的错误,第一时间拷下来google。(不过也要提防有些系统的输出信息完全不靠谱) 找没找到线索,然后都要开始定位错误。 定位的方法,是经典不过的--分而治之:注释一些代码,减少、hardcode一些输入值和中间值,函数返回值等等。 如果没有明显的线索,可单步执行,同时察看多个变量的debug工具就要及早出场,它能让你看到程序实际的执行情况而不是你思想里早就预设的误区。 不过,断点设在哪里,先注释、hardcode哪些代码这种深刻决定debug效率的抉择,就很讲经验和最近的运势了! 如果埋头苦干都没有结果,那可能是思维有了误区,就该拉个人过来和你聊一下天气和这个bug啦(但是注意别拉到太笨的,鸡和鸭讲的)。又或者,再回头看看是不是一些极低级的错误,比如链接库的版本错啦,根本没有重编译啦.... 改完bug后,好习惯是再看一眼别的地方中会不会还有同类的虫虫没杀掉。 ----延伸阅读《Code Complete 2nd》中Debugging 一章。
按照 SWIG的思路, C/C++是很优秀的library级代码语言,而写界面等方面则是Java、C#、Python们占优。所以,swig让你可以在高阶语言里调用C/C++写的类库,并且不是简单的跨语言调用,而是把类库编译为宿主语言里 Class这样的一等公民。 原本担心这个项目有点边缘化,一看原来Ruby和Python早就靠它从C/C++里溜东西出来了。对于python, ruby这些家底不厚的新生代来说,C/C++的类库很有魅惑力。即使是富得不行的Java,也靠swig为 SDL搞了个 java版。 cyt偶像说,"做产品的时候好呀:有丰富的API接口,支持java、python、php、perl、ruby…… 多好吹…… " 1. 实现原理: 比如Java吧,有一个JNI机制可以直接调用C代码,但要求C代码需如是:
JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld(JNIEnv *env, jobject obj) { printf("Hello world!\n"); return; } SWIG(Simplified Wrapper and Interface Generator) 为你自动生成了这个冗长的wrapper文件和相应的Java类,其中还妥善完成了类型转换,函数指针、模板这些C++功能在其他语言中的转换等诸般工作,善举阿。 2.操作过程: 很简单,特别在VC里dsp文件都写好了,把选项设为Release,rebuild一下就搞定。 如果要拆成慢动作,在一个Java项目里是这样的: 1.编写interface文件example.i 如果api有头文件就更简单了,下面的代码定义一个example类
%module example %{ #include "example.h" %} %include "example.h" 2. swig -java example.i 生成符合JNI语法(见上)的C文件: example_wrap.c 生成Java类文件:exampleJNI.java,example.java 3.VC把example_wrap.c 和example.c 打包成dll. 4.在普通java程序里使用example.java
System.loadLibrary("example"); int i = new Example().add(42,105);
3.总结 当你山穷水尽,准备要重新发明轮子的时候,总该想起有个swig,可以把C/C++的轮子,换装到你的语言上。
当GM向我拍下一张使用Linux与C的游戏单子时,眼前顿时冒出了兰波的名篇....... 幸好,一切堕落都有一个美好的开始: 1.另类唯美的SuSe Linux 10 Windows与Linux的百年大战中,桌面系统这块向来是Windows最高枕无忧的铁桶江山。不过这次,另类的Suse 在上面轻轻的撬了一块砖。 首先是界面,选了KDE、Suse-default的外观主题后,在我这样的美学形式主义者看来,Suse PK WinXP丝毫不落下风,对上Win2000就是稳胜。 更重要是Suse的易用性也做得很足。每次点右键总有贴心的功能出现,WinXP可能得装上Power Toys之类插件才能相若,还有美丽的Yast控制面板,还有所有软件包的自动在线更新。 而且,Suse带的一系列K字头的软件也不含糊,写字板Kate可以匹敌UltraEdit,Konsole是很好用的console,KDE 即时通信能同时连通MSN等im软件.....虽然应用的数量还是不够,但现在google和它代表的主义横行,越来越多应用移到了互联网上,只要FireFox持续更新,微软在桌面应用上的优势就会被稀释。 不过,Suse Linux 应该算是Linux中的一个另类。看一下Redhat的fedora core 4,就能发现丫还很忠实的保留着Linux桌面难看难用的传统。不过这个另类唯美者可没兼有低调的美德,google一下就能看到"Novell扬言Suse 9.3要让Windows下课" 的宣传。我觉得,那至少先要解决桌面程序的运行速度问题。 2. 万年不变,诡异莫测的make
虽然Suse很好,但很快又要面对make这个家伙。在我经历里,能够顺顺利利输完下面这三行指令,然后安装完毕的程序太稀有了。
>./configure >make >make install 这次要装一个使用SDL库的游戏,果然又是如此。 首先报找不到libSDL_image.so,结果发现原来/usr/lib里这个so带了版本号:libSDL_image_1.2.so,加link搞定。然后又报找不到SDL_image.h,跑去SDL主站下了源码补上... 都2005年了,问题还是这样层出不穷,飘忽不定,团队里如果没有久经摔打的老将,经常会被搞得手足无措,目光呆滞。 3.复杂化的趋势让人很害怕的内核模块HelloWorld
因为要直接操控IO口,所以稍稍看一下内核模块的东西。天降一本〈Linux 设备驱动程序 2nd〉中文版,hello.c 很简单,而且gcc -c hello.c 就能完成编译。 但轮到我gcc的时候,却出来两屏的错误。没想到自己的人品值急降到这个程度,愣了好一阵,才发现这本"中文版"讲的是linux kernel 2.4的事情,到2.6已经变天了。只好重新emule一本讲kernel2.6的第3版,再配合google,才明白2.6里hello.c变了,还需要预装kernel-devel,更需要使用新鲜kbuild系统来编译: 首先写一个不明所以的不完整Makefile:
obj-m := hell.o 然后用这条指令来编译,才得出新的hello.ko 文件:
make -C /lib/modules/`uname -r`/build M=`pwd` modules 更倒霉的是我一开始用的Suse 9.3居然没带kernel-devel.rpm,搞得我又要用kernel-source,配置、编译一遍内核.... 都一把年纪了,还要为了个helloword被这样拖着满场飞奔,实在是糟糕透顶的经历,而且,2.4->2.6里复杂化的趋势更让我还在门外就觉得有点凉意。 如果程序世界不是越来越简单,而是越来越复杂;越来越多东西不能靠过去的经验发挥同理可证的作用而需要完全重新学习,那我们这些老家伙的饭碗不是很危险吗???
作者:江南白衣 序 以Ruby为助力的Ruby on Rails 横空出世,又刷新了一次人们对Framework的认识:Closures、Maxin、Continuations、Metaprogramming、Reflection,又一堆名词砸得人悴不及防。 Java 虽然没有动态语言般暴起,但仍然天连天,水接水的生出好多框架技术---反射(reflection),泛型(generics),元数据(annotation),proxies(proxy/cglib),代码动态生成(asm),AOP(aspectJ),动态语言嵌入(groovy/javascript/beanshell)。面对着这些,我们像一夜暴富的农企,有点手足无措的样子。
第一感觉,应该出现新的Design Pattern书籍了。 多年前基于纯C++语法写就的那本经典,很多模式都可以被更优雅的实现,还有更多的新模式,会随着这些技术的推广而出现。
第二感觉,新的框架模式出现了。 不断升级自己的Spring,综合运用了除泛型外的大部分技术,把编程界的想像力MFC/ EJB2.0 Container这样传统的template模式/钩子函数的思路,向完全无侵入的标准过渡。 当你不顾性能狂用反射时,C++下的遗憾感开始越来越远。 第三感觉,自己应该重新充电了。 从C++下编写框架的经历到尽用“反射,泛型,元数据,proxy,代码动态生成,AOP,动态语言嵌入”是一条明显的分界线,自己应该调度足够的业余时间,沉实的学习一遍。
这个系列开始一个个介绍上述的积木。
系列文章: 系列文章: Java下的框架编程(1)--序 Java下的框架编程(2)-对泛型的无聊用法和为擦拭法站台 Java下的框架编程(3)--关于反射的碎话 Java下的框架编程(4)--Annotation vs XML vs Interface 最新一Round Java下的框架编程(5)--cglib应用 Java下的框架编程(6)--asm(待写)
作者: 江南白衣 2006年JOLT大奖(http://www.sdmagazine.com)的得奖名单: 企业项目管理:WelcomRisk 2.6(Welcom) 缺陷跟踪、变更与配置管理:Perforce SCM 2005(Perforce) 设计与建模:Lattix LDM 2.0(Lattix) 项目质量管理:Rally 5.6(Rally Software Development) 测试工具: VMTN Subscription 2005(VMware) 不知道他们长什么样子吗?没所谓了,工具从来就乱花迷眼,但花哨的工具未必适合自己的团队。总要洗净铅华的总结出一些最必要的,能提供最大辅力加持的工具。 参见《死亡中旅》2nd 第x章--最小工具集. 1.版本管理工具
有没有版本管理,可以作为项目到底有没有推行软件工程管理的一条华丽的分隔线。 因为现在是2006年了,我们选的是Subversion。 客户端工具:小海龟(http://tortoisesvn.tigris.org/)。这个CVS版的姊妹工具以前就号称WinCVS杀手了,与Window Explorer右键的整合,摒弃了必须专门跑一个Client的传统。 文本比较与合并工具:小海龟里集成的TortoiseMerge。除了Update和Commit外,查看历史版本差异,合并版本冲突是大家最常做的事情了,所以工具也一定要用适合的。 Web浏览代码:Trac(http://www.edgewall.com/trac/),完全合乎让人Pleasure标准的Web版代码展示工具。能够方便的查看,Search代码,观察仓库的提交日志。
如果团队里依然用CVS的话,相对应的推荐套件就是: l 客户端:小海龟(www.tortoisecvs.org) l 差异比较工具:WinMerge l Web代码浏览工具:Fisheye l 帐号管理工具:CVSTrac
2.项目计划,任务分配,需求变更管理,Bug管理工具 偶然的,我发现自己把这些都交给了JIRA完成。
项目计划,任务分配,进度跟踪,需求变更管理,Bug管理几乎就是PM的全部工作了。 以前总有很多软件分开来管理这些问题,同一问题经常要Copy Paste好几个软件。 但如果你的团队的项目计划是XP plan风格 而不是MS Project。 那恭喜了,一个JIRA就可以完成所有任务。 但MS Project实在深得各位老板厚爱,所以我们会做一个粒度很粗的Project来应付老板、开会和监理,让他们大概了解项目的计划和进度。而采用敏捷编程的计划风格,灵活的向团员分配具体任务。 看Jolt的奖项设置,也可以看到这种把N种项目管理工具组合归并的趋势,去年的“Change and Configuration Management Tools”和“Test-Defect Tracking Tool”,已经合并成“Defect Tracking, Change and Configuration Management” 3. 设计建模工具
虽然程序员都不太喜欢代码以外的任何东西,当然也包括UML图。但实践证明敏捷编程也不能完全抛弃设计,如果将UML图用于纯粹的交流工具而不是MDA一类宏伟愿望的话还是挺有用的,比如静态Class图和顺序图是我最经常画的东西。 有很多明星级的工具可以画这些图,但我某天发现,一个很小巧的工具Jude(http://jude.change-vision.com/jude-web/index.html)已经可以把这两种图画得很好。大家都可以在使用内存怪兽般的设计建模工具时,寻找属于自己的袖珍玲珑版工具。 另外,如果要画流程图。我喜欢SmartDraw多过Visio。因为SmartDraw有很多色彩鲜艳,配色好看的模板,现成又好看的东西才是第一选择。
4.开发环境 曾几何时,Visaul C++6.0是我认为最完美的开发环境,而随着IDEA和Eclipse的不断升级,我们的个人品味与懒惰程度也在共同提高。同时,Eclipse也依靠它无敌的Plugin编队,将自己的风格逐一推向Java、C++、PHP、Python和Ruby等领域,有一统江湖的趋势。
重构(二级) 即使团队用得最多的只是Rename、Move、Extract Method等几个基本动作,Java EE架构里牵一发动全身的事情也太多了,重构会帮你把所有事情做干净,所以我现在已形成依赖,如果不用重构,随便改一样东西,肯定造成一堆东西编译不过或者Web应用启动失败。IntelliJ IDEA作为第一个支持重构的工具,已经一路高歌把重构的概念深入到JSP、XML、JavaScript和CSS等,实在是相当聪明。 Flying Error提示和自动修正(二级) Flying Error提示在Java IDE里已经逐渐成了标准配置,有错了马上提示就地更正,不需要积了一堆错误等到编译时才慢慢查看Error Message排错。又是IDEA,不但提示错误,还会提出几种可选的修正方案,你点一下就会帮你自动修正。比如一个函数会抛出必须进行处理的checked异常,你如果调用了这个函数,IDEA就会提示你“是在调用的地方进行Try Catch呢,还是在外层函数声明Throws这个Exception?”你选择之后就会帮你自动完成,感觉非常贴心。 Smart Complete(二级) 比如现在要输入myFirstBook.setPublishDate(publishDate)这句代码,上一代的IDE在输入myBook.后,会弹出下拉菜单显示Book类的所有函数让你选择。 而新一代的IDE,AI都高得吓人,总能通过变量类型与上下文的名字猜出你想输入的内容,比如“my+热键”就能生成myFirstBook,“(+热键”就能生成publishDate。如此Smart的结果,就是我编码的过程中热键不断,成了彻底的懒人。 Debug Java EE应用(二级) Web开发者一般用System.out或者Log4j来显示调试信息,但对于曾经桌面编程的程序员来说,直接进入调试模式,单步跟踪程序执行路径,想看哪个变量就看哪个变量,才是天经地义的事情。慢慢的,这一代的IDE也已经觉醒,通过与Application Server的集成,可以在JSP,甚至第三方类库的源代码如Spring Framework的HibernateDAOTemplate里设置断点,然后单步执行,察看变量的变化。 如果左看右看,其他语言的IDE都很难符合上面的要求,不妨等待Eclipse的强大平台,一个个插件的慢慢统一。
5.团队IM工具和共享文件夹 关于交流工具,从前是言必称Email的。而随着社会的进步,现在更提倡交流的即时性,因此,“Face to Face”的交流被作为首选,早上15分钟的短会, IM工具被作为与Email同等重要的手段。 说起IM工具,很多公司都会选择严肃的MSN而不喜欢QQ。但我还是喜欢QQ的群功能,而且虽然提倡交流的即时,但避免打扰对于开发者也很重要,QQ 新版的“来消息时只显示消息条数”能起到同样的免干扰作用。 最后是知识库,Wiki有一个曾经是优点的缺点——Wiki语法。它的简单只是对于那种用写字板写网页的高手来说的,大部分人写文档的时候还是喜欢所见即所得的编辑。而且,Wiki语法与html不兼容,造成了知识库与互联网世界的鸿沟。不过好在Cofluence 2.0终于有了所见所得的编辑器,也可以弃用Wiki语法而直接使用html编辑了。 其他项目工具包括纸,笔,足够大的白板,随时可用的会议室。还缺了什么? 代码自动生成工具中也没有最趁手的。
注:本文的全文已经发表在《程序员》杂志2006年第5期,更详细的内容请购买杂志,哈哈--泰稳过午不食 说。
作者:江南白衣
关键是把C++当作Java的sister,无关C事。 所以不要买〈C/C++.....〉为名的书,入门推荐〈Essential C++〉的中文版之类,开篇就讲C++/STL。 如果不幸学校里已经学了C,想办法忘掉它。
1. 用STL的 string ,不用char* 和strcpy() 辅以Boost的Tokenizer实现Java的Tokenizer conversion/lexcial_cast实现字符串<->数值转换。 Regex实现正则表达式。
#include #include void main() { string str="haha,hehe"; tokenizer<> tok(str); for(tokenizer<>::iterator beg=tok.begin(); beg!=tok.end();++beg) { cout << *beg << endl; } int i = lexical_cast<int>("123"); string s = lexical_cast<string>(123); }
需要调用C API时,const char* cs = str.c_str() 转换。 2. 用STL的vector,不用 C式的array vector在STL容器里也是首选的容器。 如果需要批量给vector赋初始值时,使用Boost的Assign. 如果容器内需要装载多种数据类型,使用Boost的Any.
#include <boost/any.hpp> #include <boost/assign.hpp> void main() { vector<any> vec; vec+=1,"hello"; }
需要调用C API时,&vec[0] 指向第一个元素
3.用Boost 的smart pointer,尽量少用普通指针 统一使用Boost的shared_ptr,解决诸如两个对象同时拥有第3个对象,异常处理和忘记delete的问题。当然,如果refrence可用的时候,就连指针都不要用了,可怜java下用惯了new。
shared_ptr<string> p2 ( new string("Use shared_ptr "));
4.使用STL 异常机制,不用C式的Return Error Code 机制 抛出标准的exception ,不要抛int,string等,一如Java。 何时用返回值,何时用Excetpion的判断,亦一如Java。
try { throw exception("error"); } catch (exception e) { cout<<e.what()<<endl; }
5. Keep it simple 不使用C式的特性如#define。 尽量不要运算符重载。 为了整个团队和日后的维护,更加尽量不用Template、STL、Boost 中复杂陌生的东西,如type traits, Typelist, mpl,lambda,bind.... STL 似乎是个分水岭,从此C++ 不断的向学院派,复杂化发展--TR1、TR2到0x。而Java,C#们则始终保留基本语言的特征,通过不断的制定更多实用的类库、规范,抢占越来越多的市场。
6. 必备读物 2006年入行的C++程序员是幸福的,因为又多了两本实用读物的中文版,〈C++必知必会C++ Common Knowledge )〉和两位老怪返璞归真之作〈C++ Coding Standard〉,两本都是2005年新鲜写好的书,可以用来淘汰掉上一代的一大堆所谓必备书籍。 7. 益智读物 某人说过,决定学一门新语言,需其能给自己的思维模式带来冲击。 所以,推荐下面三本能带来冲击的益智读物: 〈Modern C++ Design - Generic Programming and Design Patterns 〉 〈C++ Templates - The Complete Guide〉 〈C++ Template Metaprogramming Concepts,Tools and Techniques from Boost and Beyond 〉 上面的书虽然不赞成其复杂性而限制在大团队中运用,但对个人智力来讲就大有裨益,比那些在语言规范、编译器下绕来绕去的Effective系列Exceptional系列有趣得多。
作者: 江南白衣 像工匠一样进行重构, 让重构成为一门手艺.
Martin Fowler的《Refactoring》其实更适合做一本关于重构的洗脑,宣言式的书,就像Kent Beck的《XP Explain》一样薄薄的就可以了。只可惜他却非常的厚,后面的重构名录都是写给小白看的。所以我更喜欢《Refacoring WorkBook》,以一个工匠的语气(沉默寡言而实要)传授重构的手艺。
1.重构 Between Classes
〈Design pattern〉有半数篇幅教育大家不能只靠继承,要善用组合/委托。重构里面其实也有很多事情靠把继承变成委托来解决。
1.1继承 1.1.1 并行继承体系,组合爆炸 这在以前是个头痛的问题,现在都已习惯用委托。 另外java还有个不是很让人满意的接口机制解决并行继承。 1.1.2 父子类的关系
比如过于亲密,子类会乱修改父类的方法,访问父类的变量,这时候可以定义final的Template方法。
还有拒绝的馈赠,我暂时还没有在这上面遇到问题,作者也建议如果没事就由他,如果有事,就要费劲的move method ;或者子类不继承父类,而只是组合父类。
1.2职责 经过很多次重构之后,我发现,其实哪个方法应该放在哪个类其实很主观的,你每天醒来都能想到一个理由让一个方法搬一下家,所以我现在已经放弃追求一种“对”的职责分配了,看着顺眼就行。
1.3散弹式修改 作一个修改就要改N个类时,也没什么特别好方法,就是找找看,有没有能为这个修改负责的统管全局的类。 但现在的很多散弹式修改是分层做成的。
1.4库类 OpenSource的类库,总有些时候会想要扩展 1.如果只是一两个方法,直接在客户代码里扩展, 2.否则自己多一个类库的子类 3.最费劲就是引入一个新的层
题外话,重构其实很依赖工具,和对全部代码的拥有度,哗一下就来个全项目的rename。当你设计库类时,你并不一定拥有使用这些库类的客户代码了,因此一开始就要认真设计,不能依赖重构,改接口会让人K死的。
2.重构 Within Classes
2.1 大是罪 Long Method、Large Class、Long Parameter List, 一般通过度量工具找出来,还可以自己设定一个触发器,当度量值超过某个限度时就报警。 PMD可以实现这个功能,但度量工具我更喜欢Metrics Reload,一个IDEA的插件,给出的度量信息很全面。 但是也切忌为了度量的数值而重构。 Long Method当然是尝试Extract Method。 Large Class就要把类的职能分开几个域,尝试拆出另一个Class或者SubClass。 Long Parameter List 可以通过在方法内的变量用查询获得而不用由参数传入; 或者把某些参数组成一个对象。
1.2 重复也是罪 重复在30年前就被认为是不好的一样东西,表现在1.代码类似,2.代码、接口不同而作用相近。 去除重复的方法也没什么特别,无非就是 Extract Method(同一个类)。有差异时,通过参数化达到共用。 Pull Up Method到父类(同一个父类)。有差异时,通过模板机制达到共用。 Class A调用Class B 或者 Extract Class C (两个完全无相干的类)
1.3 命名 中国程序员的英文本来就差,要多参考Ofbiz、Comperie的命名, 尽快建立团队的项目字典、领域术语字典。
也幸亏,现在在工具辅助下,代码的rename是最容易的重构。
1.4复杂条件表达式 作者认为,即使现在Program最关注的是对象,以及对象间的关系了,但优质的内部代码依然重要,推荐《编程珠玑》和《Elements of Programing style》。 化简复杂条件的基本有三个方法 1.通过!(A&B)==(!A)||(!B)化简 2.通过有意义的变量,函数代替条件表达式,比如 boolean isMidScore = (X>1000)&&(X<3000); 3.通过把一个if拆分开来执行,把guard clause放在前面 比如if(A||B) do(); ->if(A) do(); if(B) do(); 又可以把2、3灵活组合,比如根据2,Extract出一个isRight()函数,根据3 isRight() { if(A) return true; if(B) return true; return false; } 1.5 其他 没用的死代码,通过IDE工具探知并移除。小心有些框架代码是不能删除的。 Magic Number,当然是改为常量。如果Magic Number很多,可以用Map、枚举类来存放。 除臭剂式的注释,为方法,变量改一个更适合的名字。如果注释是针对一个代码段的,可以Extract Method。当然,代码只能说明how, 不能说明why,更不能说明why not,这才是注释存在的地方。
Ilog JRules 是最有名的商用BRMS,刚拿了JOLT; Drools 是最活跃的开源规则引擎,一路高歌猛进; Jess 是Clips的java实现,就如JRuby之于Ruby,是AI系的代表。
今天对比了一下这三个颇有代表性的规则引擎的规则语言。其中Ilog是商业产品,没有机会实战。
作者:江南白衣
1.一样的If--Then 句式与Rete引擎
三者都会把原来混乱不堪的if---else---elseif----else谜团, 拆成N条带优先级的"If 条件语句 then 执行语句" 的句式。 三者都主要使用foreward-chaining的Rete引擎,按优先级匹配条件语句,执行规则语句。 规则执行后会引发事实的变化,引擎又会重新进行条件匹配,直到不能再匹配为止,Rete的算法保证了效率的最高。
2.开发人员使用的规则语言
2.1 Drools的XML框架+Java/Groovy/Python嵌入语言
Drools的用XML的<Conditons>、<Consequence> 节点表达If--Then句式,而里面可以嵌入上述语言的代码作为判断语句和执行语句。 其中Java代码会使用Antlr进行解释,而Groovy和Python本身就是脚本语言,可以直接调用。 Drools的聪明之处在于,用XML节点来规范If--Then句式和事实的定义,使引擎干起活来很舒服。 而使用Java,Groovy等原生语言来做判断和执行语句,让程序员很容易过渡、移植,学习曲线很低。
<java:condition> hello.equals("Hello") </java:condition>
<java:consequence> helloWorld( hello ); </java:consequence>
2.2 ILog的IRL(ILog Rule Language)
IRL用When{}Then{}表达 If--Then句式
When { ?customer: Customer(totalTime >=1000); } Then { execute {?customer.setAmount(getAmount()-20.00); }
文档称IRL的语法是Java Syntax-like的,但我怎么也看不出两者是相同的。不过他因为是商业产品,有很强大的编辑器和管理工具,编写规则的速度应该不坏。
2.3 Jess的CLIPS jess用 => 表达 If-Then句式。 这CLIPS是真正的程序员专用语言,而且还要是很专业的程序员才习惯的东西。但这种本来就是用来做专家系统的AI语言,对规则的表达能力也应该是最强的。 讲解一下下面这段代码,airplane有一个属性--name,有两个子类--喷气式和螺旋桨飞机,其中螺旋桨飞机可以使用任意跑道,而喷气式飞机不能使用Grass跑道。
; Fact templates (deftemplate airplane (slot name)) (deftemplate jet extends airplane) (deftemplate prop extends airplane) ;
Rules (defrule can-use-grass-runway (prop (name ?n)) => (printout t "Aircraft can use grass - " ?n crlf)) (defrule can-use-asphalt-runway (airplane (name ?n)) => (printout t "Aircraft can use asphalt - " ?n crlf)) |
3.客户使用的规则语言
如果客户可以自己任意编写规则,无疑是产品一个很大的卖点。大部分客户都会喜欢这样一个玩具。而且也只有把规则编写交给客户,才能达到规则引擎的全部意义。
3.1 Drools的 DSL Drools的最新版Drools2.0Rc2里,House和Conways game of Live两个例子有DSL的版本 对比一下Java版本,效果如下:
<house:condition> <house:room name="calvin"> <house:温度> <house:greater-than scale="摄氏">20</house:greater-than> </house:温度> </house:room> </house:condition>
vs
<java:condition> room.getName( ).equals( "calvin" ) <java:condition> <java:condition> convertToCelsius( room.getTemperature() ) > 20 <java:condition>
但这种XML Base的DSL语法其实好不了多少,而且实现的代价一点不少,要自己实现Conditons和Consequence Factory类,自行解释那段XML,基本上没有什么便利的底层支持。 其实,一不做二不休,干脆用Antlr来定义真正的DSL,同样是实现Conditons和Consequence Factory类可能更好。只不过解释XML人人都会,Antlr就比较少人用而已。
3.2 ILog的BAL(Business Action Language)--最完美的王者? 没有实际用过,只能看文档过过瘾。从文档来看,配合Ilog的编辑器,的确就是很完美的规则语言了。
If the call destination number is the preferred number Then apply the preferred number rate
JetBrains的MPS出来了,Martin Fowler也大力捣鼓出一篇《Language Workbenches: The Killer-App for Domain Specific Languages?》,成为有志于LOP、DSL领域的总领性文章。
首先,了解Martin Fowler的立场很重要。但似乎为了保证阅读率,MF把立场摆到了最后。
1. LOP带来的两个最大优点是 a. 通过新的封装及思维模式,提高程序员的生产率。 b. 改变程序员与领域专家的关系,最理想情况是领域专家直接用DSL编程。 MF认为第2点比第1点带来的效果大得多,但也困难得多。COBOL刚出来的时候已经有人提领域专家直接编程了,结果呢? 2.现在大家对DSL应该是什么样子的还知之甚少,文本语言?图形语言?一切都还在假设。 3.现在的LOP工具还在非常初始的阶段。
4.但MF同时认为LOP是目前最有趣的想法,不论它日后成不成功,都会激发出大量有趣的思想与实践,留意一下LOP是绝不会吃亏的事情。
是不是热情骤减?本来MPS的发布使LOP看起来像是明天就可以开始动手的事情,现在又变成了虽然很有趣,但还远没到下山摘果子时候。 从头读一遍文章 1.开头 A Simple example of LOP Martin举的这个例子占了全文1/3的篇幅,又长又不刺激神经,看得大家频频起身吃零食,上厕所.... 2.传统的LOP MDA不是什么新概念,DSL当然也用不着是,DSL其实早就在我们身边,包括 1.Unix下用yacc打造的微型DSL 2.Lisp,fp用自身来构造DSL 3.XML配置文件 4.GUI描述文件(VB, Delphi....) 5.Adaptive Object Models and Active Data Models? (没完全理解) (注:SQL也算吧)
3.External DSL和Internal DSL DSL分内外两种,像yacc这种把DSL parser后translate成base语言的属于External DSL。 而Lisp这种用语言本身来构造新的语言的称为Internal DSL。
External DSL的好处是它可以是任何样子的,不受Base语言的制约。另外它也通常是运行时解释的。 不好的地方: 第一, 它需要花很多时间去设计语言,写Parser,写Generator,写IDE。 第二, 不能直接使用Base语言的IDE,在后IntelliJ时代这让人很不爽. 第三, 需要学太多语言和思维方式,不是指if-else语法的不同,而是在java里我们已经习惯了用Object和Method来表达想法,但在其他DSL里则可能要运用完全不同的概念,比如文章开头的例子。
而Internal DSL和External DSL的优缺点很多地方正好调转。而且Lisp,Smalltalk的语法和我们平常的Java,C#差别很大。还有,最近Ruby们好像也有可能用来写Internal DSL了。
正是因为两种DSL都缺点明确,所以DSL在今天这么不普及。Language workbeanch,正是为了使External DSL变得容易而出现的。
4.今天的Language Workbeanch 有Intentional Software的IP, JetBrains的MPS和微软的软件工厂。
1.一段DSL将有一个Editble reprensentation,一个storage reprentsentation,一个编译后的excuteble reprentsentation,一个在editor中的AST-Astraction reprensentation。其中editble和storage reprensentation可以合一,也可以分开。 2.定义一个新DSL的三个步骤: a.定义语言的schema b.定义编辑器 c.定义Generator 一个DSL可以拥有多种编辑器和代码生成器。 5.Language WorkBench的优缺点 优点: 1.省却了写Parser,直接定义抽象语法。 2.省却了写IDE。 3.IDE的语法提示与语法检查,给领域专家直接编写提供了可能,这是COBOL时代没有的。 4.DSL与项目的良好集成,可以项目与DSL语法一起refactor,可以一边设计语言一边使用语言。
缺点: 1.Vendor专属,用了MPS,就不可能再转到IP或者微软,因为他们之间根本没有标准可言。 2.但Generator并没有比以前简单(要命阿)。 3.现在代码以astraction reprensention为中心,版本管理,AST支持diff/merge的问题。
6.我的立场 试用了一下MPS,因为Generator还没有革命性的突破,MPS还没到真正可用的时候。 不过几个月间,MPS EAP已经从初始的150版本升级到220,让人无法忽略它的进度。
作者:江南白衣
注重实效的TDD的确能加快,而不是拖慢开发的进度(片面的追求覆盖率的全面UnitTest不在此列) 一,可以实现真正分层开发。 二,不需要依赖和频繁重启Web Container。 三,手工测试总不免改动数据库,如何把数据库恢复到测试前的状态是件伤脑筋的事情。而Unit Test可以使用自动Rollback机制,巧妙的解决了这件事情。
Spring 下的Unit Test主要关注三个方面: 1. bean的依赖注入 2. 事务控制,Open Session in Test 及默认回滚 3. 脱离WebContainer对控制层的测试
1.bean的依赖注入 能不依靠WebContainer来完成ApplicationContext的建立与POJO的依赖注入一向是Spring的得意之处。
String[] paths = { "classpath:applicationContext*.xml" }; ApplicationContext ctx =new ClassPathXmlApplicationContext(paths); UserDAO dao = (UserDAO) ctx.getBean("userDAO");
如果你连这也觉得麻烦,那么只要你的testCase继承于Spring-mock.jar里的AbstractDependencyInjectionSpringContextTests,实现public String[] getConfigLocations()函数, 并显式写一些需要注入的变量的setter函数。 注:因为是AutoWire的,变量名必须等于Spring context文件里bean的id。
2.Open Session in Test 及自动Rollback 又是来自Spring这个神奇国度的东西,加入下面几句,就可以做到Open Session in Test ,解决Hibernate的lazy-load问题;而且接管原来的DAO里的事务控制定义,随意定义测试结束时是提交还是回滚,如果默认为回滚,则测试产生数据变动不会影响数据库内数据。 你可以让testCase继承于AbstractTransactionalDataSourceSpringContextTests,通过setDefaultRollback(boolean)方法控制最后回滚还是提交。 如果自己编写,代码是这样的:
protected PlatformTransactionManager transactionManager; protected TransactionStatus transactionStatus; protected boolean defaultRollback = true; public void setUp() { transactionManager = (PlatformTransactionManager) ctx.getBean("transactionManager"); transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition()); } public void tearDown() { if (defaultRollback) transactionManager.rollback(this.transactionStatus); else transactionManager.commit(this.transactionStatus); }
(注,hibernate太奸诈了,如果全部默认回滚,只会在session里干活,一点不写数据库,达不到完全的测试效果。)
3.Controller层的Unit Test
controller层靠Spring提供的MockHttpServletRequest和Response来模拟真实的servlet环境,并且spring 2.0了加了一个AbstractModelAndViewTests,提供一些检测返回值的utils函数。
protected XmlWebApplicationContext ctx; protected MockHttpServletRequest request = new MockHttpServletRequest("GET", ""); protected MockHttpServletResponse response = new MockHttpServletResponse(); protected Controller controller = null; protected ModelAndView mv = null; public void setUp() { String[] paths = {"applicationContext*.xml","myappfuse-servlet.xml"}; ctx = new XmlWebApplicationContext(); ctx.setConfigLocations(paths); ctx.setServletContext(new MockServletContext("")); ctx.refresh(); controller = (CustomerController) ctx.getBean("customerController"); // 再加上前文的事务控制的代码 } public void testCustomerList() throws Exception { request.setRequestURI("/customer.do"); request.addParameter("action", "listView"); mv = controller.handleRequest(request, response); assertModelAttributeAvailable(mv, "customers"); }
4.进一步简化 一来这两个基类的名字都太长了。 二来有一些公共的context文件的定义。
所以可以再抽象了几个基类,分别是DAOTestCase,ControllerTestCase。
5. EasyMock MockObject是一样彻底分层开发的好东西,而且使用上没什么难度。而且已不再存在只支持接口不支持Class的限制。
//设定BookManager MockObject bookManagerMockControl = MockClassControl.createControl(BookManager.class); bookManagerMock = (BookManager) bookManagerMockControl.getMock(); controller.setBookManager(bookManagerMock); //录制getAllBook()和getCategorys方法的期望值 bookManagerMock.getAllBook(); bookManagerMockControl.setReturnValue(new ArrayList()); bookManagerMockControl.replay(); //执行操作 mv = controller.handleRequest(request, response); //验证结果 assertModelAttributeAvailable(mv, "books");
Easy Mock VS JMock:
JMock 要求TestCase继承于MockObjectTestCase太霸道了。妨碍了我继承于Spring2.0的ModelAndViewTestCase和使用MockDao,RealDao并行的继承体系。因此采用没那么霸道的easyMock。
另外,easyMock的脚本录制虽不如jmock那么优美,但胜在简短易读。jmock那句太长了 。
6. 显示层测试 还有,显示层至今没有什么好的UnitTest方法,无论是不成才的httpUnit们还是笨重的GUI test工具。Appfuse一直用的那个ThoughtWork那个Selenium和J3Unit的效果不知如何, 其中J3Unit号称支持prototype。
作者: 江南白衣 之前用Groovy的嵌入式xml语法时, 发现遍历DOM只有children()函数而没有parent(),就帮它修改了一下,连UnitTest一起提交到Groovy的JIRA上。 今天看到开发组接纳了我的改动。 > [patch] add parent() implement to XmlSlurper > Key: GROOVY-1010 > The XmlSlurper only have the children() method to explore DOM. > But in our project, it's so offten to use parent(). > i had patch it with unit test . John Wilson resolved GROOVY-1010: ------------------------------ ---
Resolution: Fixed
Patch added - thanks Calvin!
现在很多开源项目都有了Issue Tracker的渠道,方便大家参与测试和修改。 大家在消费别人的开源努力时,也应该习惯把自己改过的东西提交回去。
作者:江南白衣
以Spring为代表的提供依赖注入的IOC Container风头越盛,比起IOC的原本意义,DI逐渐有妹仔大过主人婆的姿势,所以Martin Fowler同学忍不住写了篇blog,提醒一下大家IOC的本原--一种作为"所有Framework与API Library最根本的区别点"的Design Principle。 当年侯捷同志是以VC下的MFC作例子,马同学与时俱进,换了Ruby、Junit、SWT来教育时下的新新人类。 IOC原理是老生常谈了,可以看马同学的blog。当应用复杂时,都应该考虑把封装从线性调用的API级,提升到奉行IOC的Framework级。
我更关心如何把自己的代码交给IOC框架调用。 1.闭包,匿名内部类,函数指针 如果仅仅把一段代码plug给框架,Groovy、Ruby的闭包是最简单快捷的,再看Java中匿名内部类的做法,比如SWT的事件绑定,Spring的JDBC Template,代码之难看令人心酸,很无妄的的要多一个接口名,一个方法名和两层嵌套,见Martin Fowler的<闭包>的中文版.
2.Template模式,策略模式 如果要把一组关联的代码绑定给Framework,则通常会定义出一个接口。这里的接口是广义的。GOF里有两种模式: 一种是模版(Template)模式,几种最简单、最古老的模式之一。在父类里面定义Control flow,留下钩子程序的位置。而在子类里实现这些钩子程序,Junit的setup()和tearDown()就属于这种类型。
另一种是策略模式。Template的一个重要制约为两者必须是父子关系,这对于单根继承的java有点不便。另外,策略模式在灵活性上显然更胜一筹。策略类只需要实现某个接口,容器就可以在适当时进行调度。比如EJB,和Swing都是这种模式。
3.消息绑定 最后,MS家还有个更高明的消息机制,可以实现更灵活的绑定。
4.AOP, cglib和Annotaton 另外,马同学没有讲的,因为AOP和元数据的出现,框架本身又有了新的封装方式。 框架可以用AOP更隐式,无侵入的提供服务,Annotation可以更简洁的告诉框架如何提供服务。
比如Spring 的JDBC Framework ,封装了连接,事务,异常的管理,让你可以专心的写SQL查询。但那些个匿名内部类让你怎么看怎么不爽,而Java又的确没有闭包......这时你可以用Spring的声明式事务管理机制,你只要把业务代码写成普通函数,而Spring会利用AOP隐式的包裹你的代码提供连接、事务的管理。
如果你不喜欢用xml配置文件声明事务,可以自己用cglib+annotation简单实现一下。甚至,如果你连 annotation也不喜欢,还可以学习rails, 用纯命名约定搞定,只在必要时采用annotation辅助。
潮流兴用Ruby写Sample Code. 还有一样事情,就是马同学开始喜欢用Ruby来写sample code。发现Ruby写sample code的确好,读的时候像伪代码一样清晰简单,写的时候也可以一气呵成,没有太多无聊定义与制约,也不用怕别人投诉代码编译不了....
作者: 江南白衣 一个Appfuse式的项目,会通过项目里最典型的几个场景,demo团队目前的体系框架和设计模式。
它的好处有一打,比如为所有项目提供共同的Library Stack,提供最可靠的代码蓝本,保证大家的模式和代码风格一致,加快知识在团队的传播,方便新人的融入,还有为试验代码提供一个稳定简洁的环境。
所以,一个长期合作的团队,需要这样一个MyAppfuse。
但还要有三条铁的纪律,才能保证辛苦做出来的MyAppFuse不是个寂寞的芭比。 一是强制更新,所有团队approval的最新模式都要refactor到MyAppfuse中。 二是规范更新,每次更新都要严格测试并编写更新记录、移植文档。 三是强制Copy Start,所有代码都必须从MyAppFuse里Copy而不是随自己喜欢找任意项目的代码。
现在开始规划一个Appfuse式项目。我觉得包含如下Content: 1.设计典型的应用情景。 我平时的ERP项目,最典型的情景莫过于: *基础资料管理(如产品资料的CRUD) *单据管理(如订单的录入与管理) *典型报表
每个场景应该有简单与复杂两种模式,方便Developer选用。 场景要仔细设计,尽量演示到所有重要的技术要点。 但场景又要尽量的少,尽量简洁,减少每次模式升级的成本。
2.挑选出其他比较重要的特性。 如Quartz、ClickStream,也一并放入MyAppFuse中。
3.把所有用到的框架、类库、瓶瓶罐罐统统打包。 并附上索引和说明作为团队公用的Library Stack,每次library升级都要认真检测。
4.编写文档。 类似Appfuse的Tutorial,编写文档说明各个场景用到的技术要点与模式,说明如何二次开发。 类似Appfuse的Migrate,详细说明如何升级到MyAppfuse新的版本,促进新模式的传播。
5.简单代码生成工具。 类似Appfuse的AppGen,用Groovy Template或FreeMarker编写简单的代码生成模版。
6.核心的测试用例
后记:这个MyAppfuse终于开源成http://www.springside.org.cn
作者: 江南白衣 扩展Spring系列(1)--Spring 的微内核与FactoryBean扩展机制DreamHead在 《思考微内核》十分激赏 Spring的微内核与扩展机制:
“Spring的微内核在哪里呢?便是DI容器。而通过FactoryBean,我们可以定制自己的组件组装过程,对一个普通的JavaBean做手脚,像Spring AOP中常用的ProxyFactoryBean做的那样。如此,我们就不必把所有功能都做到Spring的DI容器中去,而是以一个FactoryBean来对DI容器的功能进行扩展。除了Spring自身之外,现在已经有一些项目开始利用这个特性扩展Spring,比如,Acegi Security和Spring Modules。” 这确是框架容器界应该贯彻的范式,微内核提供最少的功能,而由扩展接口去增强框架的能力。下面看看Spring怎么设计,明白之后就可以开始为Spring捐献精力了:) 1、微内核的功能1.1 DI(依赖注入)与Singleton管理 利用POJO setter的DI机制,估计每位同学随手都能写一个简单版本,不多说了。 Singleton管理说白了就是先到一个map中按id找找看有没有已存在的实例。 1.2 BeanName与BeanFactory注入 除了DI注入的属性,微内核还有什么能卖给POJO呢?就是Bean在xml 定义里的id和BeanFactory自己了。 卖的机制是让POJO 实现 BeanNameAware和BeanFactoryAware接口。BeanFactory用 if(pojo instance of BeanFactoryAware)判断到POJO需要注入BeanFactory,就调用setBeanFactory(this)将自己注入。 这种框架中 基于接口的注入和调用机制在Java下挺标准的,Spring的功能多是基于这种模式提供。遗憾就是Java不支持多重继承,作为替代的接口里不能提供默认的实现,导致每一个Pojo都要很无聊的实现一遍setBeanFactory()。 1.3 DI后的初始化函数调用 比如属性A,B注入之后,需要同时根据A和B来对A,B进行加工或者装配一个内部属性C,这样就需要在所有属性注入后再跑一个init()函数。 Spring提供两种方式,一种是和上面的原理一样,实现InitializingBean接口的afterPropertiesSet()函数供Spring调用。 一种是在xml定义文件里面自行定义init函数名。 懒得每次在xml文件里定义的就采用第1种方式,不想与spring耦合的pojo就采用第2种方式。本来就是为了扩展Spring而存在的FactoryBean多采用第一种。 所谓微内核,就是仅提供以上三种功能的DI容器。 但作为轻量级容器,还需要以下两种方式,向容器内的POJO 附加各种服务。2.FactoryBean扩展机制Spring的AOP、ORM、事务管理、JMX、Quartz、Remoting、Freemarker、Velocity,都靠FacotryBean的扩展,FacotryBean几乎遍布地上:
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"/>
![](/Images/OutliningIndicators/None.gif)
<bean id="baseDAOService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"/> 只不过当年对这类factoryBean比较麻木不仁,不问原理的照搬照用了。 不过这原理说出来也好简单,所有FactoryBean 实现FactoryBean接口的getObject()函数。Spring容器getBean(id)时见到bean的定义是普通class时,就会构造该class的实例来获得bean,而如果发现是FacotryBean接口的实例时,就通过调用它的getObject()函数来获得bean,仅此而以.......可见,很重要的思想,可以用很简单的设计来实现。 考察一个典型的FactoryBean:
一般会有两个变量,三个接口: 一个setter函数注入需要改装的pojo,一个内部变量保持装配后的对象returnOjbect。 implements三个接口 :FactoryBean,InitializingBean和BeanFactoryAware 。 各接口的意义之前都讲过了。factoryBean会在afterPropertiesSet()里把pojo改装成returnObject,需要用到beanfactory进行天马行空的动作时就靠BeanFactoryAware注入。最后在getObject()里把returnObject返回。 Rod说:IoC principles, combined with the factory bean, afford a powerful means to abstract the act of obtaining or accessing services and resources 3. Bean Post-Processor扩展机制 如果说FactoryBean 是一种Factory、Wrapper式的扩展,Bean Post-Processor就是另一种AOP、visitor式的机制,所以也多用于spring的AOP架构。 Post-Processor的原理就是BeanFactory在前文里的调用afterPropertiesSet()/init-method前后,调用在工厂里注册了的post-processor的postProcessBeforeInitialization()和postProcessAfterInitialization()。 那怎么注册登记呢?又分请不请礼仪公司两类。如果是ApplicationContext,你把继承BeanPostProcessor 的bean往xml里一搁就行了,application context自会打理。如果是BeanFacotry,就要显式的注册,代码大概像:
XmlBeanFactory factory = new XmlBeanFactory("C:/beans.xml"); BeanPostLogger logger = new BeanPostLogger(); factory.addBeanPostProcessor(logger); Rod说:"Post-processors add the ability to customize bean and container behavior in a flexible, externalized fashion. " 对比Factory Bean那段,可见两种机制在他心目中的不同作用。 系列文章:Spring 的微内核与FactoryBean扩展机制 扩展Spring(2)--Spring对各种数据访问框架的集成机制
作者:江南白衣
ANTLR(ANother Tool for Language Recognition)风头正盛,经常可以看到用它做语法解释器的项目,比如Hibernate就在3.0换上它来解释HQL,加强了HQL的语法。 因为Antlr是EBNF-AST语法解释系的代表,而自己总是心思思想搞一下DSL(领域语言),所以从Hibernate来学习一下Antlr的应用。
Hibernate HQL translator作者Joshua Davis的两个Blog Hibernate3 Query Translator Design - Part One : The Basics Hibernate3 Query Translator Design - Part Two : Parsing HQL
Antlr最好的介绍文章是那篇,在《程序员》2004年3月有中文的版本。 不过,那个计算器的例子太简单了。深刻一点的有。 另外,SlickEdit 支持Antlr的语法,是一定要用的编辑器,在 ttdown.com上有破解。
一,Antlr引擎的工作过程大概是这样的: 1.Lexer类--词法分析器。 定义语言中的各种Token(单词),如 From 、Where、=、<>....... Lexer负责把读入的普通文本流识别成Token串。
2.Parser类--语法分析器。 使用BNF语法,递归定义句子的Pattern,如whereStatement、FromStatement、SelectStatement。 Parser负责把读入的Token串匹配成句子,翻译出AST(抽象语法树)。 有些简单的应用,也可以在本层现炒现卖,完成所有动作,属于Single Pass Builder。
3.TreeParser类--抽象语法树遍历器。 根据Parser类分析出来的AST(抽象语法树)进行动作。 用Parser把AST抽取出来,再用TreeParser进行动作的Double Pass Builder模式,解耦了Parser和Generation,再配合Template 生成代码,是Antlr推荐的最佳模式。
二,开发人员的实际步骤
1.按照Antlr的简单语法定义前面讲的3个类,文件的后缀名为g。
2.使用java antlr.Tool xxx.g 命令,把grammar文件编译成java文件。
3.编写应用程序,如:
import antlr.*; import antlr.collections.*; public class Main { public static void main(String[] args) throws Exception { ExprLexer lexer = new ExprLexer(System.in); ExprParser parser = new ExprParser(lexer); parser.expr(); AST ast = parser.getAST(); ExprTreeParser treeParser = new ExprTreeParser(); int x = treeParser.expr(ast); } }
三,Hibernate对Antlr的应用 看过Antlr对HQL的解释,觉得EBNF系的方法要解释Java这样的编程语言还好些,如果要解释类自然语言的DSL就比较痛苦,所以情绪不是很高涨,挑一条最容易的"Delete from goods where ....." 匆匆走过场
Joel的一句话对我的影响比较大:"如果为了证明一个微不足道的问题需要花三个小时写下几黑板的证明步骤,那么这种机制不可能用来证明任何有趣的东西" 。对于我这个层次的程序员,antlr在我手中造不出有趣的DSL来。
Hibernate的HQL Grammar文件一共有三个,在/grammar目录下: 1.hql.g 定义Token类和Parser类,将HQL解释成hql的抽象语法树(AST) 2.hql-sql.g 定义Tree Walker ,将HQL AST转化为SQL AST,将生成模块与Hibernate解耦。 3.sql-gen.g 定义Tree Walker,从SQL AST生成sql
下面看 DELETE FROM GOODS的翻译过程
1.HqlBaseLexer extends Lexer 定义EQ: '='; LT: '<'; GT: '>';PLUS: '+';等符号 及IDENT: ( 'a' .. 'z' | '_' ) ( 'a' .. 'z' | '0' .. '9' | '_' | '$' )*
2.HqlBaseParser extends Parser 先定义DELETE="delete"; FROM="from"; MIN="min"; 等字符串 再定义:
statement : ( updateStatement | deleteStatement | selectStatement ) ; 三种Statement之一
deleteStatement : DELETE^ (optionalFromTokenFromClause) (whereClause)? ;DELETE为叶子,(whereClause)可选
optionalFromTokenFromClause! : (FROM!)? f:path { AST #range = #([RANGE, "RANGE"], #f); #optionalFromTokenFromClause = #([FROM, "FROM"], #range); } ;不是很好懂对吧,我也这样觉得,whereClause就更加不要看了。
3. HqlSqlBaseWalker extends TreeParser hql与sql的delete语句基本上是一样的,没什么转换。
4.SqlGeneratorBase extends TreeParser 根据SQL AST, 生成SQL语句
private StringBuffer buf = new StringBuffer(); protected void out(String s) { buf.append(s); }
statement : selectStatement | updateStatement | deleteStatement ; deleteStatement : #(DELETE { out("delete"); } from (whereClause)? ) ;输出"delete" from : #(f:FROM { out(" from "); } (fromTable)* ) fromTable : #( a:FROM_FRAGMENT { out(a); } (tableJoin [ a ])* { fromFragmentSeparator(a); } ) | #( b:JOIN_FRAGMENT { out(b); } (tableJoin [ b ])* { fromFragmentSeparator(b); } ) ; tableJoin [ AST parent ] : #( c:JOIN_FRAGMENT { out(" "); out(c); } (tableJoin [ c ] )* ) | #( d:FROM_FRAGMENT { nestedFromFragment(d,parent); } (tableJoin [ d ] )* ) ;
![](/Images/dot.gif) ![](/Images/dot.gif) ![](/Images/dot.gif) ![](/Images/dot.gif) .晕了吧 ~~~~~ whereClause : #(WHERE { out(" where "); } ( conditionList | booleanExpr[ false ] ) ) ;
扩展Spring(2) ---Spring对各种数据访问框架的集成机制 何为数据框架集成。
数据访问框架原本好好的,Spring都干了什么呢? 一是用template类封装了数据框架那些资源获取和异常事务处理的废话代码,而且按照自己的意见给出一些增强函数。 二是将其纳入了Spring的声明式事务管理中。 对比Spring对Hibernate、JDBC的集成,还有 Spring Modules对 O/R Broker的集成,发现Spring的DAO框架主要有六个类: 1.Template 著名的Template类,用callback机制封装了除业务代码外的所有必要但废话的代码,重新封装了数据框架的API,并再附送一些增强版。 2.TransactionManager
实现PlatformTransactionManager接口,数据访问框架就能与Spring的事务机制(TransactionTemplate或AOP声明式事务)结合。 重要的类仅以上两个,以下的类都只有少量标准代码,完全可以忽略。 3.DAOSupport
实际DAO类的基类,负责保持template变量。如果你觉得它破坏了你的类层次结构,完全可以不用。 4.Accessor
template类的基类,defining common properties like DataSource and exception translator,也没大用。 5.Operations
template所实现的接口,定义template支持的数据访问函数和增强函数,template有多个实现时才有用。 6.Exception Translate的相关类和函数
异常翻译,Spring DAO很重视的一个功能。 Template类的代码
因为Hibernate本身很复杂,所以HibernateTemplate也不适合畏高晕车的人士如我观看。JDBC简单很多,但JDBCTemplate又忙着增强JDBC的功能,多出好多代码。所以我选O/R broker的集成代码来看,代码一共才280行。 注:如果不熟O/R broker,可以简单的认为broker=connection, executable = statement ,其余一切同Jdbc。 1.1主干函数 Execute(BrokerCallback action) step1. 获得Connection-- connecton = datasource.getConn(); step2. 准备Statement -- statement = new Statement(connection); step3. 执行Action的回调函数doInBroker(Statement)。这个doInBroker()方法由客户定义,会拿着传入的statement,执行种种操作。
try { action.doInBroker(statement ); } catch( ) { // 翻译异常 }
1.2 template的API函数 虽然理论上大家可以直接使用execute(),在匿名内部类里调用数据访问框架的任何API。但java的匿名内部类不比闭包,代码难看无比,所以除了Robbin还没见到其他兄弟提倡直接用execute方法的。 因此,template也对数据框架的API进行了wrap,封装了用execute(StatementCallback action)来执行这些API的函数,如下段就是wrap 了O/R Broker的execute(String statementID.....)方法:
public int execute(final String statementID, final String[] paramNames, final Object[] values) throws DataAccessException { return executeWithIntResult(new BrokerCallback() { public Object doInBroker(Executable executable) throws BrokerException { applyNamedParamsToExecutable(executable, paramNames, values); return new Integer(executable.execute(statementID)); } }); } 另外还提供一些增强型、便利型的API(如selectOne() ,selectMany()),在参数、返回值上极尽变化。 TransactionManager的代码
比较复杂,一下说不清。但JDBC的DatasourceTransactionManager和Hibernate的HibernateTransactionManager的代码都很相近,说明这个TransactionManager其实也比较固定埋头狂抄就是了。 有兴趣的同学,可以响应某大老号召,实现ofbiz与spring的集成:) 系列文章: Spring 的微内核与FactoryBean扩展机制 扩展Spring(2)--Spring对各种数据访问框架的集成机制
作者: 江南白衣 人生像个舞台,请良家少女离开。 同样的,Freemarker和Velocity爱好者请跳过本篇。与弃用webwork而单用Spring MVC Controller接口的理由一样, Freemarker本来是一样好东西,还跨界支持jsp 的taglib,而且得到了WebWork的全力支持,但为了它的非标准化,用户数量与IDE的缺乏,在View层我们还是使用了 保守但人人会用,IDE友好的JSP2.0 配合JSTL。
对于B/S结构的企业应用软件来说,基本的页面不外两种,一种是填Form的,一种是DataGrid 数据列表管理的,再配合一些css, js, ajax的效果,就是View层要关注的东西了。 1. JSP 2.0的EL代替<c:out>JSP2.0可以直接把EL写在html部分,而不必动用<c:out>节点后,老实说,JSP2.0+JSTL达到的页面效果,已不比Velocity相差多少了。
<p>{goods.name}</p> 代替 <p><c:out value="{goods.name}"/></p>
(除了EL里面不能调用goods的函数,sun那帮老顽固始终坚持JSTL只能用于数据显示,不能进行数据操作,所以不能调用bean的get/set外的方法)
2. 最懒的form 数据绑定
Spring少得可怜的几个tag基本上是鸡肋,完全可以不要。 而Spring开发中的那些Simple Form tag又还没有发布。Spring的Tag主要用来把VO的值绑到input框上。但是,和Struts一样,需要逐个Input框绑定,而且语法极度冗长,遇到select框还要自己进行处理.....典型的Spring Sample页面让人一阵头晕.
而jodd的form tag给了我们懒人一个懒得多的方法,只要在<form>两头用<jodd:form bean="myVO"></jodd:form>包住,里面的所有input框,select框,checkBox...统统自动被绑定了,这么简单的事情,真不明白struts,spring为什么不用,为了不必要的灵活性么?
<form> <jodd:form bean="human"> <input type="text" name="name"> <input type="radiobox" name="sex" value="man"> <select name="age"> <option value="20">20</option> <option value="30">30</option> </select> </jodd:form> </form>
不过,jodd有个致命弱点是不能绑定内嵌对象的值。比如Order(订单)对象里有个Customer(顾客)对象,jodd就不能像 struts,spring一样用如下语法绑定:
<input name="customer.customerNo">
这是因为它的beanUtils比Jakata Common弱,用了一个错误的思路的缘故。 动用beanUtils修改一下就可以了,修改后的源码可以在这里下载。
3. DataGrid数据列表
DisplayTag和ValueList都属于这种形式的Tag Library。但最近出现的Extreme Table是真正的killer,他本身功能强大不说,而且从一开始就想着如何让别人进行扩展重载,比如Extend Attributes机制就是DisplayTag这样的让千人一面者不会预留。
4.css, javascript, ajax 天下纷扰,没有什么特别想讲想推荐的,爱谁谁吧。Buffalo, DWR, Scriptaculous, Prototype, AjaxTags, AjaxAnywhere, Rico, Dojo, JSON-RPC,看着名字就头痛。
相关文章 简化Spring(1)--配置文件 简化Spring(2)--Model层 简化Spring(3)--Controller层 简化Spring(4)--View层
作者: 江南白衣 Struts与Webwork的扇子请跳过本篇。 MVC不就是把M、V、C分开么?至唯物朴素的做法是两个JSP一个负责View,一个负责Controller,再加一个负责Model的Java Bean,已经可以工作得很好,那时候一切都很简单。 而现在为了一些不是本质的功能,冒出这么多非标准的Web框架,实在让人一阵郁闷。像Ruby On Rails那样简捷开发,可用可不用,而且没有太多的限制需要学习的,比如 Webwork这型还可以考虑。但像Struts那样越用框架越麻烦,或者像Tapestry那样有严重自闭倾向,额上凿着"高手专用玩具"的,用在团队里就是不负责任的行为了。
so,我的MVC方案是使用Spring MVC的Controller接口,写最普通的JavaBean作为Controller,本质就和当年拿JSP作Controller差不多,但拥有了Spring IOC的特性。
之所以用这么消极的选择标准,是因为觉得这一代MVC框架离重回RAD时代的标准还很远,注定了只是一段短暂的,过渡的技术,不值得投资太多精力和团队学习成本。
1. 原理
Spring MVC按植物分类学属于Martin Flower〈企业应用模式〉里的静态配置型Front Controler,使用DispatchServlet截获所有*.do的请求,按照xml文件的配置,调用对应的Command对象的handleRequest(request,response)函数,同时进行依赖对象的注入。 我们的Controller层,就是实现handleRequest(request,response)函数的普通JavaBean。
2. 优势 Spring MVC与struts相比的优势:
一是它的Controller有着从松到紧的类层次结构,用户可以选择实现只有一个HandleRequest()函数的接口,也可以使用它有很多回调函数的SimpleFormController类。
二是不需要Form Bean,也不需要Tapestry那所谓面向对象的页面对象,对于深怕类膨胀,改一个东西要动N个地方的人最适合不过。
三是不需要强XML配置文件,宣告式编程是好的,但如果强制成框架,什么都要在xml里面宣告,写的时候繁琐,看的时候也要代码配置两边看才能明白就比较麻烦了。
那Webwork呢?没有实战过,不过因为对MVC框架所求就不多,单用Spring MVC的Controller已经可以满足需求,就不多搞一套Webwork来给团队设坎,还有给日后维护,spring,ww2之间的版本升级添麻烦了。真有什么需要添加的,Spring MVC源代码量很少,很容易掌控和扩展。
3.化简
3.1. 直接implement Controller,实现handleRequest()函数
首先,simple form controller非我所好,一点都不simple。所以有时我会直接implement Controller接口。这个接口的唯一函数是供Front Controller调用的handleRequest(request,response)。 如果需要application对象,比如想用application.getRealPath()时,就要extends webApplicationObjectSupport。
3.2.每个Controler负责一组相关的action
我是坚决支持一个Controler负责多个action的,一个Controler一个action就像一个function一个类一样无聊。所以我用最传统的方式,用URL参数如msg="insert"把一组相关action交给一个Controler控制。ROR与制作中的Groovy On Rails都是这种模式,Spring也有MultiActionController支持。 以上三者都是把URL参数直接反射为Controller的函数,而 Stripes的设计可用annotation标注url action到响应函数的映射。
我的取舍很简单,反正Spring没有任何强制,我只在可能需要不重新编译而改变某些东西的时候,才把东西放在xml里动态注入。jsp路径之类的就统统收回到controller里面定义.
3.4.Data Binder
Data Binder是Controller的必有环节,对于Spring提供的DataBinder,照理完全可用,唯一不爽是对象如果有内嵌对象,如订单对象里面包含了Customer对象,Spring需要你先自行创建了Customer对象并把它赋给了Order对象,才可能实现order.customer.customer_no这样的绑定。我偷懒,又拿Jakarta BeanUtils出来自己做了一个Binder。
3.5.提取基类
作者: 江南白衣 因为Spring自带的sample离我们的实际项目很远,所以官方一点的model层模式展现就靠Appfuse了。 但Appfuse的model层总共有一个DAO接口、一个DAOImpl类、一个Service接口、一个ServiceImpl类、一个DataObject.....大概只有受惯了虐待的人才会欣然接受吧。 另外,Domain-Driven逢初一、十五也会被拿出来讨论一遍。 其实无论什么模式,都不过是一种人为的划分、抽象和封装。只要在团队里理解一致,自我感觉优雅就行了。 我的建议是,一开始DO和Manager一生一旦包演全场,DO作为纯数据载体,而Manager类放置商业方法,用getHibernateTemplate()直接访问数据库,不强制基于接口编程。当某天系统复杂到你直觉上需要将DAO层和Service层分开时,再分开就好了。 1.DataObject类 好听点也可以叫Domain Object。Domain Driven Development虽然诱人,但因为Java下的ORM框架都是基于Data Mapper模式的,没有Ruby On Rails中那种Active Recorder的模式。所以,还是压下了这个欲望,Data Object纯粹作一个数据载体,而把数据库访问与商业逻辑操作统一放到Manager类中。 2.Manager类 我的Manager类是Appfuse中DAO类与Service类的结合体,因为: 2.1 不想使用纯DAO 以往的DAO是为了透明不同数据库间的差异,而现在Hibernate已经做的很好。所以目前纯DAO的更大作用是为了将来可以切换到别的ORM方案比如iBatis,但一个Pragmaic的程序员显然不会无聊到为了这个机会不大的理由,现在就去做一个纯DAO层,项目又不是Appfuse那样为了demo各种ORM方案而存在。 2.2 也不想使用Service层来为Dao解耦
在JPetStore里有一个很薄的Service层,Fascade了一堆DAO类,把这些DAO类的所有方法都僵硬的重复了一遍。理论上一个Manager类可以管理数个Dao类,可以避免Dao之间直接耦合。但既然有Manager的情况下,商业逻辑都是写在Manager类的,那样子Manager似乎还是调用另一个Manager比较妥当,调用裸Dao可能存在忽略了某些逻辑。所以,耦合又从Dao层升到Service层了。 所以,除非你做的是超薄的不带逻辑的Service层,否则没有解耦的意义。 何况,对一个不是死搬书的Designer来说,组件边界之内的类之间的耦合并不是耦合。 3.去除不必要的基于接口编程
众所周知,Spring是提倡基于接口编程的。 但有些Manager类,比如SaleOrderManager ,只有5%的机会再有另一个Impl实现。95%时间里这两兄弟站一起,就像C++里的.h和.cpp,徒增维护的繁琐(经常要同步两个文件的函数声明),和代码浏览跳转时的不便(比如从Controler类跟踪到Service类时,只能跳转到接口类的相应函数,还要再按一次复杂的热键才跳转到实现类) 连Martin Flower都说,强制每个类都分离接口和实现是过犹不及。只在有多个独立实现,或者需要消除对实现类的依赖时,才需要分离接口。 3.1 DAO被强制用接口的原因 Spring IOC本身是不会强制基于接口的,但DAO类一般要使用Spring的声明式事务机制,而声明式的事务机制是使用Spring AOP来实现的。Spring AOP的实现机制包括动态代理和Cgilib2,其中Spring AOP默认使用的Java动态代理是必须基于接口,所以就要求基于接口了。 3.2 解决方法 那就让Spring AOP改用CGLib2,生成目标类的子类吧,我们只要指定使用声明式事务的FactoryBean使用CGLib的方式来实现AOP,就可以不基于接口编程了。 指定的方式为 设置proxyTargetClass为true。如下:
<bean class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
id="baseService" abstract="true">
<property name="transactionManager" ref="transactionManager"/>
<property name="proxyTargetClass" value="true"/>
![](/Images/OutliningIndicators/None.gif) ![](/Images/dot.gif)
</bean> 又因为这些Service Bean都是单例,效率应该不受影响。 4.总结
对比Appfuse里面的5个类,我的Model层里只有VO作为纯数据载体,Manager类放商业方法。有人说这样太简单了,但一个应用,要划成几个JSP,一个Controller,一个Manager,一个VO,对我来说已经足够复杂,再要往上架墙叠屋,恕不奉陪,起码在我的项目范围里不需要。(但有很多项目是需要的,神佑世人) 后记:迫于世人的压力, SpringSide暂时还是把DAO和Service层分开了,但依然坚持不搞那么多接口。 另外,尽量利用IDEA的代码生成热键,为Manager类生成delegate的Dao类方法。 相关文章 简化Spring(1)--配置文件 简化Spring(2)--Model层 简化Spring(3)--Controller层 简化Spring(4)--View层
作者:江南白衣 序
人人都爱Spring加Hibernate。 但Spring MVC+hibernate的Sample如Appfuse的代码却算不得最简洁优美好读,如果在自己的项目中继续发挥我们最擅长的依样画葫芦大法,美好愿望未必会实现。 所以,Pramatic精神不灭。这个系列就是探寻最适合自己的Spring+Hibernate模式。 I-配置文件简化
我厌倦一切配置文件繁重的框架。 最好的情况是,框架提供极端灵活复杂的配置方式,但只在你需要的时候。 Spring提供了三种可能来简化XML。随着国内用户水平的提高,这些基本的简化技巧大家都已掌握。 大家可以直接看第3,第4点--Spring 1.2, Spring 2.0的后继改进。
1.1.autowire="byName" /"byType"
假设Controller有一个属性名为customerDAO,Spring就会在配置文件里查找有没有名字为CustomerDAO的bean, 自动为Controller注入。 如果bean有两个属性,一个想默认注入,一个想自定义,只要设定了autowire,然后显式的声明那个想自定义的,就可以达到要求。这就应了需求,在需要特别配置的时候就提供配置,否则给我一个默认注入。
还有一个更懒的地方,在最最根部的<beans>节点写一句default-autovwrie="byName",可以让文件里的所有bean 都默认autowrie。 不过Rod认为开发期可以这样,但Production Server上不应该使用Autowire。而我觉得那些自定义一次的地方比如TranscationManager应该详细定义,而Dao,Controller这种大量重复定义的bean就可以偷点懒了。
1.2.<bean>节点之间抽象公共定义和 Inner Bean
这太方便懒人了,想不到两个独立的XML节点都可以玩继承和派生,子节点拥有父节点的全部属性。 最好用的地方就是那个Transtion Proxy的定义。先定义一个又长又冗的父类,然后用子类去继承它。 另外,还有一个Inner Bean的机制,可以把DAO写成Proxy的内部类。为什么要写成内部类?为了让Proxy冒名顶替它去让Controller Autowire。(详见后面的示例)
1.3. 宽松的配置, To XML or Not to XML 据说Spring比Struts的配置宽松了很多,这就给人把东西从配置文件中撤回原码中的机会。 不赞成什么都往配置文件里晒,造成了Rich Information的配置文件,修改或者查看的时候,要同时打开配置文件和原码才能清楚一切。 而我希望配置文件就集中做一些整体的配置,还有框架必须的、无需管理的冗余代码。而一些细节的变化不大的配置和逻辑,就尽量别往里塞了。因此,Success/Fail View 的配置,不建议放在里面。
2.简化后的配置文件
1.Controller只剩下一句
<bean name="customerController" class="org.springside.bookstore.web.CustomerController" autowire="byName"/>
2.DAO也只剩一句
<bean id="customerDAO" class="org.springside.bookstore.dao.CustomerDao"/>
3.Service类只剩下5行
<bean id="customerManager" parent="baseTxService"> <property name="target"> <bean class="org.springside.bookstore.service.CustomerManager"/> </property> </bean>
3.Spring 1.2后xml语法简化
最主要的简化是把属性值和引用bean从子节点变回了属性值,对不喜欢autowire的兄弟比较有用。 当然,如果value要CDATA的时候还是要用子节点。另外,list的值可以用空格隔开也比较实用。
<property name="myFriendList">
<list>
<value>gigix</value> <value>wuyu</value>
</list>
</property>
简化为
<property name="myFriendList" value="gigix wuyu"/>
![](/Images/OutliningIndicators/None.gif) 4.Spring 2.0来了 如果没什么外力刺激,spring xml 可能就这样不会变了。但现在xml成了过街老鼠,被ror的默认配置和JDK5的annotation逼得不行,当然就要继续求变。 比如有好事者认为,节点名必须以bean打头,附加一个属性id来表示bean名;属性值必须搞一个property子节点,子节点上有个属性name来表示属性名,是给机器看的很不直观的东西。
<bean id="customerDAO" class="org.springside...CustomerDAO"> <property name="maxCount" value="10"> </bean> 给人看的东西应该就写成
<customerDAO class="org.springside....CustomerDAO" maxCount="10"/> Spring 2.0正用schema实现类似的语法,具体请看它的JPetStore sample。
5.使用Spring自带的DTD使编辑器Smart.
如果没有用Eclipse的Spring插件,那至少也要使用spring自带的dtd使XML编辑器smart一些,能够自动为你生成属性,判断节点/属性名称有没有拼错等。
6.还有更变态的简化配置方法 比如autoproxy,不过我觉得更简化就不可控了,所以没有采用。
相关文章 简化Spring(1)--配置文件 简化Spring(2)--Model层 简化Spring(3)--Controller层 简化Spring(4)--View层
作者:江南白衣
1.Groovy的最新八卦之处 1.1 Wiki: http://docs.codehaus.org/pages/listpages.action?key=GROOVY 1.2 Mail list的在线浏览和rss定阅 Developer List http://dir.gmane.org/gmane.comp.lang.groovy.devel User List: http://dir.gmane.org/gmane.comp.lang.groovy.user
2.Groovy的开发现状和未来 编译期健壮性大大增强的1.0 JSR-2,全力除Bug的1.0 JSR-3,JSR-4已经发布。 第二次全球Groovy 开发人员FB大会也在巴黎开完,有决议若干。 理论上 1.0正式版很快就要发布。 而计划中的1.1版本将支持 ruby的maxin、continuations 和JDK1.5的Annotatin。
3.Groovy and Java的暧昧关系 作为Java的私生子,Groovy的最终可执行状态是Java class bytecode,所以Java代码里可以把它当普通Java Bean一样调用。还有,Groovy的基础类库,都是用Java代码来写的。
3.1 编译Java class bytecode 就像JSP的最终面目是servlet class,GroovyC也会把groovy文件编译成Java class bytecode以在JVM上运行。 其中Groovy Class会编译成GroovyObject的子类,Groovy Script代码段会编译成Script的子类。 可以用GroovyC来静态编译,也可以在Java程序里用GroovyShell动态parse Groovy文件。
3.2 在Java代码中调用Groovy 1.Groovy类: GroovyObject类默认有get/setProperty()和invokeMethod()的反射接口,在Java代码里,可以直接调用Groovy类的方法,也可以通过反射接口来调用。
2.Script代码段: Script类有Script(Binding)构造函数和run()接口,在java里先通过Script(Binding)构造一个Script类,绑定变量,然后通过run接口进行调用。
3.3 在Java中直接使用Groovy的类库 Groovy和Groovy的框架类库都是用Java写出来的的。所以有些类库如SimpleTemplateEngine,也可以在Java里直接使用,不用绕Groovy一圈。
4.groovyJ插件 groovyJ是IDEA插件,有语法变色和Run()功能,更有用的功能是编译Java文件目录时,会把其中的groovy文件也一同编译。而日后将支持重构、类间跳转等功能,值得期待。 而Eclipse插件只有Run()和语法变色,而且随着Eclipse的升级时灵时不灵,正在花时间实用化中。 NetBeans开了个Coyote的项目来支持脚本语言。
5.一些重要的开发人员 一个PM: Guillaume Laforge
两个Founder: Bob Mcwhirter (同时是Drools,Dom4J的founder) , James Strachan (Core Developers Network,同时work on Geronimo,Drools,ServiceMix 和很多Jarkarta 项目,似乎拥有无穷的精力)
三个来自ThoughtWorks的开发人员: Jame Walnes,Chris Stevenson,Matt Foemmel
四个star of JSR-2: Jeremy Rayner, Jochen Theodorou,和两位老大一起改进JSR-2编译的强壮性和出错信息显示 Franck Rasolo:IDEA插件GroovyJ的开发人员 Christian Stein :Groovlet,Template的开发人员
Steven Devijver : Grails--Groovy on Rails的主持,同时是Spring Modules的leader。
6.有哪些使用Groovy的项目
Grails(Groovy on rails,大老们非常期待的项目,把rails在MVC和ORM的优点抄到java下,而且是基于Spring Framework的)
Drools(规则引擎, 用户可以用groovy写规则)
eXo platform(porlet/Service container,本身核心是groovy,用户可以用groovy 来写Porlet)
XWiki (第2代的wiki引擎、Application引擎。用户可以用groovy写Plug-in,Marco和Application)
RIFE(一个MVC/Web framework,用户可以用groovy写action和配置layout,workflow。还含有一个CRUD框架,用户用groovy 定义domain class,滴嗒一下,就能获得一个CRUD模型)
7.Groovy-all-1.0-jsr3.jar groovy需要asm和antlr包的支持,使用groovy-all-10-jsr3.jar,将预带这两个包的正确版本,非常省心。
8.Migrating to JSR JSR版本语法的的最大改动有两处。网上很多Groovy文章都还是基于旧语法的,需要自己改正过来。 8.1 为了加强代码健壮性,Class里的变量需要用def 定义。而在script里的变量因为是动态binding的,仍然不需要def定义。
8.2 多行的String需要用 """ """而不是" "来括住。
9.SimpleTemplateEngine-总共200行就实现了JSP engine的功能 动态语言开发框架很方便,所以Ruby on Rails没有IDEA级的IDE都能这么就把MVC、ORM都实现了一遍。 请看src/groovy/text/SimpleTemplateEngine.java,总共219行。 原理就是把模版中的文本部分替换成println """ 文本""" ,Groovy部分照搬,生成一个新的Groovy script,然后拿GroovyShell执行一遍就完成了。
10.如何用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) { .} 11.ant 的编译脚本
<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>
作者:江南白衣
前篇:〈在Spring+Hibernate框架下,用动态语言写业务类〉讲述在Spring+Hibernate的架构下,因为动态语言所带来的利益,把一部分业务类改用Groovy编写并编译成Java Class文件。 而且,因为Groovy的强大与简便,加上与Java亲密无间的关系,一些框架类也可以逐渐考虑用Groovy编写。
1.虽然多是星零的好处,但忽然间一整吨好处摆在面前还是很让人感动的。
除了动态语言和闭包、MOP,Groovy其他的特性多是对J2SE中设计不合理的地方逐一进行修正,集合、IO、字符串操作......虽然多是星零的好处,但忽然间以整吨好处摆在面前还是挺让人感动的。
同时,Groovy完全兼容Java语法,但又提供糖糖选择的方式感觉很贴心。(Groovy唯一不支持的java语法就是Inner Class的定义和函数定义里的"throws Exception" , 私生子的好处啊)
隐约觉得因为动态语言的无类型,还有闭包这样带着Lisp式FP的印记,加上MOP这样的机制,可能会激发更大的变革发生。
1.动态类型 动态类型在Framework型项目中非常重要,多少设计模式呕心沥血,就是为了和这个类型搏斗。 而且,如果你是把代码编译成java Class,健壮性不会减低太多。 2.闭包 fp的基础,没有闭包的C++用函数指针,java用匿名内部类,都比他差远了。 详看Matin Flower <闭包>文章的中文版 ,在一段文件操作的Script中试演了一下,果然使代码简洁了好些。
3. MOP Groovy的Team Leader-- Guillaume Laforge最喜欢的一样特性,groovy 嵌入式XML语法的基础,对属性和方法访问的intercept 机制。详看另一篇blog。 又比如,在MOP下,DAO那一堆findByName,findByTitle不用再逐一实现了,实现一个findBy即可拦截其他子虚乌有的findByXXX。
4.强大的String类 a.可以直接在String中嵌入EL, "orderBy ${sortColumn}",省了好多"和+号。 b.hql 可以多行,不用写N多"和+ , 写sql时特别方便。 c.简单集成了正则表达式 If ("name"==~ "na.*") {println "match!"}
5. 集合与循环的语法 for (car in cars) { println car } for ( e in map ) { x += e.value}
或者 car.each{print it} 集合也可以直接定义了,如 def myList = ["Rod", 3, Date()] def myMap = ["Neeta":31, "Eric":34]
6.为JDK的基础类扩展了一系列Helper方法 //原来StringTokenizer类的功能被简单的集成到String类中了 names.tokenize(",").each{......} 其他基础类的扩展见Groovy-JDK
7.简化的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是一种修正。
8. Object内建的反射语法 customer.getAt("name") //得到属性name, customer.invokeMethod("someFunction") //调用方法someFunction 从此不再需要Apache BeanUtils。
9.GPath--内置的XML语法,和Fremarker类似。 传说中JDK7.0的功能 jdom和Dom4j可以安息了 book = new XmlSlurper().parseText("<book writer='calvin'><title>D</title></book>") println book.title; println book[@writer]; println book.children().size();
10.运算符重载 //向数组添加对象 params << customer.getAt(it); 还有如C++的向String,InputStream添加对象. 还有集合类相加,如list1+list2
11.简化了IO操作
12.省略了每行末尾的分号 既然每行都要的,何必多此一举呢? 另外return语句也可以省略,不过我还是习惯写:)
2.Groovy版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) } }
如果羡慕Ruby On Rails可以用动态语言来编码,但又舍不得Spring、Hibernate这些Javaer深以为傲的框架,那么有一种折中的方案: 仍然使用Spring+Hibernate框架,而用Groovy/Jython/JRuby来编写Controller类、Service类、DAO类,并把它们编译成普通的Java Class文件来使用。 BuggyBean的blog里用Jython示范了这种方案。
1.why 动态语言? 现在的动态语言都已经很面向对象,和传统的用来写写外围脚本(测试,安装)的script语言已经不同,而且Groovy,Jython,JRuby写成的类除了动态载入外,都可以编译成静态的Java Class文件,所以已能很好的承担J2EE应用里业务类的角色了。
动态语言有什么好处呢,请参看<Groovy写业务类、框架类的那一吨好处>。
2. 八卦:各种动态语言的Java实现 Groovy ,BeanShell,Jython(Python),JRuby(Ruby),Rhino(JavaScript), Jacl(TCL),Bistro(SmallTalk),Kawa(Lisp/Schema)
3.哪种动态语言? Jython总是若断若续,气若游丝的样子,而且现在都才移植到Jython2.1,比Python2.4 慢了几拍,很信不过。
JRuby呢? Dion Almaer在JRuby0.8.2发布时说:"The day JRuby gets up to Jython levels, and then C Ruby levels, will be a great day.",字面上JRuby比Jython还要不靠谱。 Ruby还有一个不好是暂时没有好的IDE(连那个收费的ruby-ide都好弱),如果没有好的IDE,可以抵消掉大部分语言本身的优势,真不能想像Ruby On Rails是用怎么个UltraEdit级的编辑器写出来的。
Groovy的弱势是1.0正式版还没有发行,用户社区还不大。
因为现在选的是Java框架下嵌入哪种动态语言作为业务类。所以Python和Ruby的用户社群和大量的已有项目作用不是很大。而Groovy比起两位舶来品, 1.作为私生子,嵌入性理所当然是最好的,两者的关系暧昧得不得了。 2.另一个天然优势是能兼容Java的语法,把Java代码copy到Groovy几乎不作什么修改(only不支持throws定义语句和Inner Class),团队的学习曲线平滑。 3.因为不是移植项目,语言升级时没有时间差,不用看移植人的脸色。
so,我会选Groovy,等它的正式版出来之后。
作者: 江南白衣 Groovy的Team Leader-- Guillaume Laforge说,MOP(Meta Object Protocol)是他最喜欢的Groovy特性。 MOP是对属性、方法进行拦截解释的简单机制,intercept 已经因为AOP而被大家熟悉。 Groovy的类都继承于GroovyObject,GroovyObject有get/setProperty()和invokeMethod()两个函数,当客户调用不存在的属性和方法时,就会交由这两个函数来处理,在Ruby里,这个方法被更贴切的命名为method_missing()。Groovy类可以通过重载这两个函数,加入自己的hook和behavior,比Java简单的多的实现 Proxy和 Delegator。
而更重要的是,MOP函数可以充当领域语言解释者的角色,拦截一些存在于领域语言的而在Class里根本没有定义的属性、方法来进行解释,这就是Groovy里XML嵌入式语法的魔法根源。 IBM DW有一篇专门的文章 :《PRACTICALLY mini-languages and MOPs Of Groovy:》 比如如下的xml
<shop> <book name="foo"> <writer>庄表伟< SPAN>writer> < SPAN>book> < SPAN>shop>
可以用groovy这样访问
println node.book.writer.text()
node类当然没有book,writer这样属于领域语言的属性,但通过重载getPropety(String name)函数,node类可以把对book,writer属性的访问,转换成相应DOM节点的访问。 实现请参看org.codehaus.groovy.sandbox.util.XMLList类的public Object getProperty(final String elementName)函数。
Guillaume Laforge说,It's an aspect of Groovy which makes the language very powerful, but rare are those who really know and use it.
|
|
公告
常用链接
随笔分类
随笔档案
朋友
积分与排名
最新评论
![](/images/xml.gif)
阅读排行榜
|
|