浏览 5366 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2007-01-16
Better Convention than Configuration这个肯定可以做到的吧,而且我觉得Hibernate应该官方支持这个特性,也许就在不久的将来。对象属性的自动创建这个肯定做不到,语言没这个能力。看过一些框架用xx.getProperty("id")这样的方式实现,有点儿东施效颦的感觉。而且不自动创建属性也有它的好处:比如在IDE中使用代码提示,可以通过编译发现错误使用的属性(通常是拼写错误,在自动实时编译的IDE中基本不可能会出现)。可能有人会说这个好处很小,但那是从Ruby的哲学上看的;如果从Java上看,这还是挺好的。CRUD方法的自动生成这个东东要讨论的比较多。首先,最基本的CRUD肯定是可以生成的,但是find_by_id_and_name这样的肯定不行。但是我觉得后一种方法的用处也不是很大,最关键的是要解决好基本CRUD操作中参数传递的能力和方式。Java 5里面已经可以传入不定参数了,这个特性肯定可以好好利用。但是Java中没有"id"=>"001"这样方便的构造pair(hash)的方法,所以参数传递的方式肯定会比RoR麻烦很多。Query Object提出了用一个Object封装所有查询条件的模式,虽然确实比较灵活,但是使用起来很不方便。所以,如何传递查询条件是需要仔细讨论的一个话题。我自己的一点儿实现我自己按照上面的思想实现了一点点东东:自动map简单的对象(不包括一对一、一对多关系),自动创建基本的CURD。大致的使用过程如下:
java 代码
java 代码
java 代码
目前的问题目前在开发中遇到了一个问题,一直没有解决办法,说出来大家一起分析。自动生成CRUD部分我使用的是byte code generation。这样做是有原因的。
有人可能会说ClassLoader可以reload或redefine,这个是当然的,但是reload或redefine后得到的是一个Class类型的对象,我要是用反射的写法才能执行其上的method,而不能简单的使用Model.find(...),这样就不是我们需要的CRUD了。 写这片文章有三个目的:
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2007-01-16
引用 因为是static方法,所以除了AspectJ,其他的AOP实现都不能拦截。而我不想引入AspectJ(独立的编译器)。 确实对开发工具的依赖越少越好. 引用 source code generation:主要有两个问题,如何merge自动生成的代码和用户编辑的代码,还有就是我不想引入源代码,真正的magic应该是没有源代码就能执行,而不是源代码生成。 JSR 269 系的设计思路主要是生成新的类和代码, 而不是去修改已有类代码, 我觉得这个对其它的代码生成机制也有借鉴意义. 引用 反射:Java对static method的反射支持少的可怜,可以说,用反射根本就无法实现。 Java是 静态类型 的 OO 语言, 这方面就不要想了. 你可以写成 Model.find(...); 但是编译器会把它翻译成 Base.find(...); 编译出来的代码里不会有 Model 或者其它子类的痕迹. 引用 请各位看看我的思路,提些建议。 可以参考 TOB 的一些思路, 目前只有apidoc是全的: http://tob.ableverse.org/apidoc/ 引用 讨论一下查询条件如何传递的问题,最好是即方便又灵活。 TOB是这样: <T extends TheObject> List<Persistent<? extends T>> query(long start, long max, Class<T> klass, String clause, Object... args) Query on class klass and all its direct and indirect subclasses for persistent objects matching criteria specified by clause. 实际使用时可以这样写: tob.querier.query(0, -1, Book.class, BookQ.NAME + " LIKE %?% AND " + BookQ.PRICE + " < ? " + " AND " + BookQ.AUTHOR$NAME + " = ? " " ORDER BY " + BookQ.PRICE, searchName, maxPrice, authorName); 其中 BookQ 是编译时自动生成的查询条件类. 用类似命名参数的方式的话, 可以类似这样: public class Simple { /** * {name} was {age} {! age>1 ? "years" : "year"} old in year {year}. * * @arg name : name of the person * @arg age = 26 : his/her age in that year * @arg year = 2002 : the year * @usage This is a demo message declaiming one person's age in a past year. */ @Msg private static final String YEAR_AGE = "yr-age"; public static void main(String[] args) { Messager msgr = Messager.get(); System.out.println(msgr.format(YEAR_AGE, "name", "Peter", "year", 2002, "age", 26)); msgr.info(YEAR_AGE, "age", 22, "year", 1998, "name", "Peter"); } } Messager里用来解析变参的是这样一个类, 效率上应该基本优化到极限了: /* * Copyright (c)2004-2006 Compl Yue Still, All Rights Reserved. */ package av.util; import java.util.Arrays; /** * This is a simple readonly map that takes an array of object in pairs. The * object at even index (odd position) is interpreted as the key, and the next * one at odd index (even position) is interpreted as the value, i.e. * <p> * <code> * new BinMap("name", "Peter", "year", 2006, "age", 26); * </code> * <p> * A binary index based on <code>key.hashCode()</code> will be constructed so * looking up gets optimized through binary search algorithm. * <p> * And this class benifits from operations on <code>long</code> type, so will * perform better in 64-bit platforms. * <p> * In fact, this class is providing fast lookups for * {@link av.msg.Messager#format(String, Object[])} and simular methods those * take a var arg list for key-value pairs. * * @author Compl * */ public class BinMap { private Object[] content; private long[] index; public BinMap(Object... content) { assert content.length % 2 == 0 : "content must be in pairs"; this.content = content; index = new long[content.length / 2]; for (int i = 0; i < index.length; i++) { index[i] = (((long) content[i + i].hashCode()) << 32) + (i + i + 1); } Arrays.sort(index); } public Object get(Object key) { long k = ((long) key.hashCode()) << 32; long vk; int left = -1, right = index.length; for (int i = (left + right) / 2; (left < i) && (i < right);) { vk = (index[i] & 0xFFFFFFFF00000000L); if (k == vk) { int pos = (int) (index[i] & 0xFFFFFFFFL); if (content[pos - 1].equals(key)) return content[pos]; for (int j = i + 1; j < right; j++) { if (k != (index[j] & 0xFFFFFFFF00000000L)) break; pos = (int) (index[j] & 0xFFFFFFFFL); if (content[pos - 1].equals(key)) return content[pos]; } for (int j = i - 1; j > left; j--) { if (k != (index[j] & 0xFFFFFFFF00000000L)) break; pos = (int) (index[j] & 0xFFFFFFFFL); if (content[pos - 1].equals(key)) return content[pos]; } return null; } else if (k > vk) { left = i; } else // (k < vk) { right = i; } i = (left + right) / 2; } return null; } /** * test this class. * * @param args */ public static void main(String[] args) { Object[] content = new Object[] { "Number 1", 1, "String 9", 9, "Number 5", 5, "Number 2", 2, "String 7", "7", "Number 3", 3, }; BinMap bm = new BinMap(content); for (int i = 0; i < content.length; i += 2) { Object key = new StringBuffer(content[i].toString()).toString(); Object val = bm.get(key); System.out.println(key + "=" + val); System.out.println(key + "_non" + "=" + bm.get(key + "_non")); } } } 引用 运行时reload class文件的问题,如何可以马上反映出我对byte code的修改。 这个在JVM上实现可能还是比较脆弱的, 真想走下去, 可能应用方面免不了要作出牺牲性的改变, 或许 BeanShell 的代码会有些借鉴意义. |
|
返回顶楼 | |
发表时间:2007-01-16
以RoR的高标准作为起点我觉得是太高了。在RoR和流行的Java开源框架对比来说,我觉得在ORM这一块来说,Java做的还是相当不错的,从实际开发角度来说,主要还是Web层的开发过于烦琐,和RoR差距比较大,对比而言,ORM的烦琐程度不算太多。
Hibernate的annotation已经可以抛弃XML,还能带有编译期检查,我觉得不错,没有必要和RoR看齐; 查询语言方面HQL我用得也挺好(除了生成的SQL让人看了恶心之外); 动态查询条件参数传递可以用Hibernate DetechedCriteria,这个也不是问题; ORM是比ActiveRecord烦琐,但我觉得可以接受,其实Hibernate从功能上来说要比AR强大的多。 IoC这一块不好弄,RoR不需要IoC,也不需要事务横切,也不需要管理数据库资源,所以业务逻辑可以直接写在Model里面,绝对的Rich Domain Model,简单说就是Java的PO,DAO,BO而为一体。但是Java的持久对象做不到,不能脱离IoC,不能脱离事务横切,也不能把所有的业务逻辑都放在Domain Model里面。 在Web这一块,差距也忒大了,rails1.2的REST都出来了,而Java Web框架还没有一个能够很好的实现Restful URL映射的,Struts2.0能把XML砍掉就谢天谢地了。 |
|
返回顶楼 | |
发表时间:2007-01-16
不使用AspectJ、Refleaction和Source Code Generation,这个基本上通过了。
complystill 写道 引用 请各位看看我的思路,提些建议。 可以参考 TOB 的一些思路, 目前只有apidoc是全的: http://tob.ableverse.org/apidoc/ 引用 讨论一下查询条件如何传递的问题,最好是即方便又灵活。 TOB的方法会不会太脆弱了?还有,这只是where子句,如果是order by,group by,paging,aggregation之类的东东该咋办... complystill 写道 引用 运行时reload class文件的问题,如何可以马上反映出我对byte code的修改。 这个在JVM上实现可能还是比较脆弱的, 真想走下去, 可能应用方面免不了要作出牺牲性的改变, 或许 BeanShell 的代码会有些借鉴意义. Java 5中有个Instrument机制,应该可以在main函数运行之前,先运行个premain函数,我可以在premain里面修改byte code。但是这需要使用额外的运行参数,这样一来,除了每次运行时要加参数,Junit做测试时也要加参数,启动tomcat也要加参数,所以不可取。 Java 6中增强了Instrument,提出可以不在运行时加参数,直接在main函数前执行一个类似premain的agentmain函数。但是,这个功能是可选的,Sun JDK没实现,它说每个vendor可以选择实现,我就faint了! |
|
返回顶楼 | |
发表时间:2007-01-16
robbin 写道 以RoR的高标准作为起点我觉得是太高了。
我觉得应该向高标准看齐,只是在具体实现的时候,实在由于无法实现,才应该降低标准。 robbin 写道 在RoR和流行的Java开源框架对比来说,我觉得在ORM这一块来说,Java做的还是相当不错的,从实际开发角度来说,主要还是Web层的开发过于烦琐,和RoR差距比较大,对比而言,ORM的烦琐程度不算太多。
web方面我还是期待struts2好了,2.02版本里面说是有RESTful API的支持了。至于ORM这里,Java领域从功能上看确实做得不错,而且比RoR要强,但是用起来方便我却不这么觉得。我想每个人(或组织)手里都应该有一个封装好的Hibernate CRUD操作实现库之类的东西吧,比如Manager.find(Model.class, ...)。 另外再说个其他问题,我用Spring 2.0里面的HibernateTemplate的save方法,本以为就可以save到数据库了,但是却不行。我要用execute,然后自己声明事务。如果说对于write操作,事务是必须的,那么提供一个save方法做什么?只是把对象加到session的cache中吗?那也太不直观了,我就不明白。 robbin 写道 Hibernate的annotation已经可以抛弃XML,还能带有编译期检查,我觉得不错,没有必要和RoR看齐;
是有了annotation,但是还是要配置一些(如果不是很多)东东啊。 robbin 写道 查询语言方面HQL我用得也挺好(除了生成的SQL让人看了恶心之外);
按照你的意思,我夸张点儿说,那我就写个execute方法,让调用者传HQL咯? robbin 写道 动态查询条件参数传递可以用Hibernate DetechedCriteria,这个也不是问题;
这个我看了,大概形式是:session.xxx(param).xxx(param).xxx(param).xxx(param).xxx(param)....xxx(param);我还是觉得不爽。 robbin 写道 ORM是比ActiveRecord烦琐,但我觉得可以接受,其实Hibernate从功能上来说要比AR强大的多。
强大当然强大,但是大家不是都希望更简单嘛,我这里讨论的也是简单。 robbin 写道 IoC这一块不好弄,RoR不需要IoC,也不需要事务横切,也不需要管理数据库资源,所以业务逻辑可以直接写在Model里面,绝对的Rich Domain Model,简单说就是Java的PO,DAO,BO而为一体。但是Java的持久对象做不到,不能脱离IoC,不能脱离事务横切,也不能把所有的业务逻辑都放在Domain Model里面。
这里还没想好,只能边做边看。 robbin 写道 在Web这一块,差距也忒大了,rails1.2的REST都出来了,而Java Web框架还没有一个能够很好的实现Restful URL映射的,Struts2.0能把XML砍掉就谢天谢地了。
我要是牛我就写web去了,不牛才在ORM这边叨咕,哈哈。 |
|
返回顶楼 | |
发表时间:2007-01-16
AllenYoung 写道 TOB的方法会不会太脆弱了?还有,这只是where子句,如果是order by,group by,paging,aggregation之类的东东该咋办... 开始一下子没写全, 刚才更新了一下加入了 ORDER BY 和 相关类字段的条件语法, 你再看一下. 另外TOB上的持久应用Java代码和传统数据库的存储过程性能是相当的, 基于SQL的查询通常只用作第一步的过滤, 更复杂的过滤/处理完全可以用Java代码来实现, 这时候就不要返回 List, 而是用这个: <T extends TheObject> void query(PersistentObjectProcessor<T> processor, long max, Class<T> klass, String clause, Object... args) Query on class klass and all its direct and indirect subclasses for persistent objects matching criteria specified by clause. 在实现 PersistentObjectProcessor<T> 的类代码里过滤和处理. AllenYoung 写道 Java 5中有个Instrument机制,应该可以在main函数运行之前,先运行个premain函数,我可以在premain里面修改byte code。但是这需要使用额外的运行参数,这样一来,除了每次运行时要加参数,Junit做测试时也要加参数,启动tomcat也要加参数,所以不可取。 Java 6中增强了Instrument,提出可以不在运行时加参数,直接在main函数前执行一个类似premain的agentmain函数。但是,这个功能是可选的,Sun JDK没实现,它说每个vendor可以选择实现,我就faint了! 类似的机制基本都是为了 Profiling 设计的, 主要目的可能还是为了第三方调试程序以及分析瓶颈, 热点等. 不是为了生产执行用的, 如果生产环境也必需启用它们的话, 对性能的影响应该是无法避免的. 而且挂上去的扩展程序不像 Annotation Processors 那样可以多个并存, 同时生效, 排他性很强, 会造成跟第三方优化分析工具的不兼容. |
|
返回顶楼 | |
发表时间:2007-01-16
唉...我现在就是被block在这个地方了,深感Java的不灵活啊!
|
|
返回顶楼 | |