Nutz1.a.15发布两个月以来,反响不错,更值得欣慰的是,提意见帮助Nutz的盆友很多很多,借此转载一篇新近由 fireflyc 发表的意见(据说zozoh在看到意见之后甚为欣慰,当即表示感谢热心人士的意见,欢迎大家更多地表达,尽情的抨击):
仔细阅读了一下源代码,单纯的几个技术观点:
1.数据库的封装。这里的封装我觉得太薄太脆弱。和hibernate比起来根本没有办法比,hibernate的HQL是一种语法分析的推导。而这里只有SQL,虽然简单但是意味着耦合。对sql的执行我看到SqlMaker这样写道
"INSERT INTO %s (%s,%s) VALUES(@%s,@%s)"
也就是说,所谓的封装是对字符串的一种封装。把SQL的各个部分进行拼装。这种做法我不觉得有什么地方好,反而不如直接写sql,不做任何封装的好。这里估计是想要模仿什么,同样的道理注解的加入也是想要模仿什么。或许模仿的那个不合适这里的设计哲学。作者的设计哲学应该是输入sql,输出对象(或map)。那么很显然,作者如果能忍痛割爱把那些违反这个哲学的“对某些东西的模仿”剔除掉,那么这个东西会更加简洁明确。(我只是推测作者的设计哲学,可能有偏差。呵呵。。莫气)
2.对controller的封装,我觉的也是想在模仿什么,头部的那些注解暗示着返回的状态和输入的url都是由配置决定的,或者说是写死在代码里面的(我的哲学是,注解=代码而非配置)。我不知道这些注解和直接写死在代码里面有什么区别。两者都需要重新比编译。我还没有找到数据绑定相关的内容,难道直接使用request?这个我喜欢,但是问题是应该有一些工具类给我方便把request绑定到对象上才行。否则如果属性多无聊的代码也就多了。
3.代码整体结构有点out了。试举两例:
在日志的org.nutz.log.file.FileWriterPool中,26行getWriter方法,作者把打开的Writer放到一个HashMap里面,然后在getWriter的时候为了保证线程安全有如下代码段
Writer w = writers.get(file.getAbsolutePath()); if (null == w) synchronized (this) { w = writers.get(file.getAbsolutePath()); if (null == w) { try { w = new BufferedWriter(new FileWriter(file, true)); writers.put(file.getAbsolutePath(), w); } catch (IOException e) { throw Lang.wrapThrow(e); } } } return w; Writer w = writers.get(file.getAbsolutePath()); if (null == w) synchronized (this) { w = writers.get(file.getAbsolutePath()); if (null == w) { try { w = new BufferedWriter(new FileWriter(file, true)); writers.put(file.getAbsolutePath(), w); } catch (IOException e) { throw Lang.wrapThrow(e); } } } return w;
synchronized这个锁,太大了,java早已经在jdk5的时候重写了所有的并发相关的内容,引入了Lock类。
再看这里是否有必要自己来加锁?打开java.lang.concurrent包,引入眼帘的是ConcurrentHashMap类。应该猜到是干什么了的吧?
4.作者太偏执,作者的偏执体现在不引用任何除jdk以外的第三方包,也许是对混乱的jar愤怒到了极点。但是这种做法意味着你将与开源世界完全脱离,你重新制作一切,不利用社区的任何帮助。这是一种浪费,我觉得和开源哲学背离(个人观点中的开源哲学)
5.整个框架的封装说不上好用,有些东西明明是两样背离的东西却被试图封装在一起。与其破坏一个东西,不如去修改一个东西。我们的框架被我偷梁换柱替换几乎把struts1架空了,把hibernate限制的几乎只有HQL了,甚至把事务变成了手工的,把spring和guice都做了一层封装,但是我没有再去考虑自己重写这一切,因为我曾经这样尝试过,最后发现远不如修改来的直接和巧妙。至少它还是struts、hiberate、spring之类的。