解惑

解己之惑,解人之惑

标签:Java (第3页共6页)

没落的Java社区

感觉原来的几个Java社区日益没落,当然这个和Java世界的消沉有很大关系,这两年已经看不到什么大的Java新闻了,特别是对于Java开发人员而言的大新闻,原来Spring带来的各种火热的讨论也已经沉寂下来,Java世界似乎已经毫无新意了,现有的任何Java开源产品或者组件所能够带来的开发效率的提升都无法和新的脚本语言匹敌(我想这也是为什么JavaEye会使用RoR重写的一个重要原因,同时也是Robin转向研究Ruby的重要原因),在可以预见的一段时间以内,都不太可能出现一颗真正的银弹。但是我对于Java并没有丧失信心,因为Java依然拥有广大的开发人员以及丰富的开源产品和组件,现在所缺少的是一个真正简单并且易用的快速开发框架,提供Java Web开发所必备的大部分功能,开发人员所需要关注的仅仅是创建数据库和业务逻辑代码(不需要开发常见的CRUD操作代码),当然开发人员也不需要太多的配置就能够让整个系统跑起来(不需要Spring的Bean配置、Struts的Action配置、Hibernate的配置)。
就我个人感觉,完成这样的一个框架并不是很难,困难在于Java世界应该引入更多的规则而不是可配置,最起码可配置是第二位的需求,但是Java世界的人似乎已经习惯了配置,习惯了对象间的关系是在运行时通过读取配置文件来确定,也习惯了通过读取配置文件来组装系统。
对于多人并行开发的系统而言,Java的强类型约束无疑对于代码的可维护性和可读性更加有利,但是基础设施的严重缺失使得代码的开发难度加大,代码的重复性也因此加大(对于一个简单功能,由于Java本身没有提供,只能自己写、寻找其它的开源组件或者公司自己的框架提供,但是很多新来的人不知道已经有那样的功能,即使知道也是拷贝一份代码稍加修改)。
我相信现在有很多人都有和我一样的想法,也有很多人在做,包括EasyJF(简易Java框架),问题是他们并不能真正的普及,他们的设计者和维护者并不能得到大部分人的认可,而像AppFuseSpringSideJdonFramework这样拼凑起来的快速开发框架也不能解决问题(还是需要大量的配置),我期望中的真正的Java快速开发框架是完全重写的基于规则的框架,不需要配置或者只需要极少的配置(例如数据库配置),具有强大的Model和View的转换能力,可以很容易的将POJO或者POJO集合转换为各种页面组件(表格、树),不需要POJO和数据库的映射配置,不需要写CRUD代码,URL请求自动映射到Action。。。。。。

Java很简单也很难

说Java简单,是因为它的语法,这个也是当初最吸引我的,我被C++的语法搞蒙了
但是,在实际的工作中,能够真正把Java使用得自如的人并不是很多,见到的大部分的人写代码没有问题,但是如果遇到一些问题就茫然了,不知道如何去解决问题,虽然有些人知道用google可以解决很多问题,但是有时候是因为自己的某些问题导致的问题,也有时候仅仅是开发环境的一些干扰导致的,很少有人和他遇到的问题完全一样。在这种情况下,就可以看出真正的功底了,对Java更加了解的人并不会急于解决问题,而是详细的查看出错信息,思考最有可能的原因。虽然就是简单的两句话,但是每一句都是建立在大量的经验的基础上的。
先说出错信息,我们知道Java的出错信息往往有很多冗余,在这么多信息里面怎么找到关键信息呢?加上有时候代码编写不规范,出错信息被吞掉了,或者配置的日志工具有问题,出错信息不输出到控制台,而是输出到日志文件。
再说最有可能的原因,你遇到的错误足够多了,你才能在脑海中搜索类似的问题,而且要保持一个开放的思想,因为错误信息稍微差一点,错误的原因可能就千差万别,还有时候信息一样也可能是不同的原因导致的。

表现层的一些想法

上次也说过表现层是最难解决的,主要是解决复用和开发速度,目前的一些基本想法:

  • 有一个类似ECS的通用页面基本元素模型
  • 在上面的基本元素的基础上有项目需要的粒度更大一些的组件,例如下拉列表、表格甚至页面模版
  • 页面Builder,根据一定的规则可以自动创建页面的框架,然后开发人员只需要做一些小的调整
  • 和项目的模型层绑定,这样很多地方拿到模型后,使用Builder就可以使用非常少的代码得到外观一致的页面了
  • 引入AJAX,特别是一些过滤条件,根据一定的规则获取并更新到(可能增加一个客户端缓存),特别是Intranet应用,大部分可能都可以考虑使用AJAX
  • 基于规则的请求转发,不需要进行配置

其实,考虑这么多,主要是现在的视图层太灵活,因此代码风格以及解决问题的风格太不一致,维护起来简直是噩梦,给开发人员提供一个沙箱,他们只能在这个沙箱中发挥,那么产品整体的可维护性和一致性会大大提高。而且,开发的工作量也可以减少一倍以上,当然,搭建这个框架也需要很长时间,但是可以慢慢来,逐步的重构。

深度克隆的简单通用实现

今天看ECS的源代码,发现一个深度克隆的简单通用实现,当然这个实现会克隆所有的成员,因此如果你的类有一些不能保存或者克隆的成员,那么这个就无效了,但是如果你的类就是简单的POJO,那么这个还是不错的,正在为我的持久层的克隆发愁,这个应该是我正想要的。我也相信这个对很多人一样有用,虽然性能可能不是很好:

    /**
        Allows all Elements the ability to be cloned.
    */
    public Object clone()
    {
        try
        {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(baos);
            out.writeObject(this);
            out.close();
            ByteArrayInputStream bin = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream in = new ObjectInputStream(bin);
            Object clone =  in.readObject();
            in.close();
            return(clone);
        }
        catch(ClassNotFoundException cnfe)
        {
            throw new InternalError(cnfe.toString());
        }
        catch(StreamCorruptedException sce)
        {
            throw new InternalError(sce.toString());
        }
        catch(IOException ioe)
        {
            throw new InternalError(ioe.toString());
        }
    }
   

表现层是最难解决的问题

在Web开发中,表现层是最难于通用化的,个人的感觉,Tapestry是一个不错的思路,可惜学习起来并不简单,而且也需要积累才能真正的简化开发。其它的表现层框架我都不是很看好,目前我的思路倾向于使用类生成页面,和模型层绑定,这样在产品或者大型项目中可以大大的简化工作量,也减少很多问题。目前,公司的产品中虽然是使用的这种思路,但是力度不够,组件太少,和模型的绑定也不够,需要写的代码太多,一种问题在不同的地方都需要小心,搞得QA也是很不爽。
而且表现层似乎也是搞开发的人中最不喜欢做的部分,因为“技术含量太少”,基本上堆代码肯定可以搞定。虽然我也不喜欢做表现层的工作,但是必须承认,如果能够实现一个易于使用的表现层框架,对于整个项目的贡献是很大的,至少有30%的代码量,因此可以简化的工作量实际上很多。公司考虑将更多的工作转移到中国来做,希望自己有机会能够改变这个情况,让表现层的工作更加的简单。

我的持久层规范

昨天说了我的这个大轮子的大致情况,就是尽量保持简单,而配置最多的可能就是持久层和Action的配置,我的框架会完全取消这两个的配置,先说说持久层的情况。

  1. 类名和表名直接关联,关系是类名前带 t_
  2. 类的成员和表字段直接关联,名称完全一致,全部的表都需要一个名字为ID的主键,类型为long,由系统自动在插入的时候产生
  3. 表关联根据类之间的关联决定,如果两个类对对方都是直接引用,就是一对一,如果一个是直接引用,例外一个是集合,则是一对多,如果两边都是集合,就是多对多,对于集合的成员,其成员名是类名加s。多对多的表名是t_加两个类名,中间用_分隔,字段名就是类名加_id,如果是一对多,则外键名就是类名加_id
  4. 类型现在是自动匹配,也就是数据库的类型和类中的对应字段的类型是匹配的
  5. 主键的值在系统初始化的时候会从数据库表中读取最大值,然后缓存在系统中,每次加一
  6. 缓存的大小根据系统启动时数据库对应表的记录数决定,记录数小于一千的缓存100%,一千到一万的缓存50%,一万以上的缓存10%,十万以上缓存1%
  7. 类名可以分布在多个包中,配置文件配置都有那些包可以存放这些持久化对应的类,类名不可重复

根据这个规则,我完全取消了持久层的配置,对于新项目,这个规则的要求并不高,符合绝大部分的需要。至于查询,目前还没有完全想好,但是我考虑的是大部分的简单情况,只提供一个简单的对象表达式语法,复杂的查询还是使用SQL。

具体的例子:
阅读全文

KISS

记得最开始学习Java的时候就被它的KISS原则深深吸引了,因为那个时候正在为c++的各种语法而头疼。做了这么多年的Java开发,也感觉Java确实在语法和跨平台上符合它的这个原则,现在,Java的内容扩展越来越广,学习Java,使用好Java越来越需要对OO、设计模式、敏捷开发等深入理解并实践。
随着struts、spring和hibernate在国内的普及,越来越多的人得到提高,当然,我们也看到了以EasyJF为代表的国内开源力量的发展,在那些通用框架的基础上,他们期望能够进一步简化,实际上,我也在做这个工作,虽然我很欣赏spring和hibernate的灵活性,但是那么多的配置文件也是一个很头疼的事情,根据我自己的经验,很多应用没有必要进行配置,根据一定的规则就可以直接得到配置,为什么还要配置呢?即使是使用JDK5的新特性元数据进行简单配置我也感觉不是很必要,所以,我开始了我的大轮子计划,为自己定制一个最精简,最快速(性能和开发速度)的框架,在验证自己的设计能力的同时也可以强迫自己去学习别人的代码(但是不会全部照搬,也不会过度设计,需要的时候再重构),而且,这个框架我打算几乎完全自己构建,能够自己写的一定自己写,目前为止只使用了log4j和cglib这两个第三方的包,连连接池都是自己写的。在构造这个大轮子的过程中,我会把自己的心得体会写下来和大家交流。

使用ThreadLocal消除循环依赖

昨天刚刚说了在用Cglib完成我的持久层的设计,我实现了一个通用的clone方法,但是有一个问题,因为我在后台保留了一个和数据库记录对应的对象,其他的部分要使用的时候都是从那个记录clone一个出来,为了防止潜在的修改,必须进行深度clone,刚开始我就是用了一个简单的递归clone,但是不行,在存在关系的时候就会无休止的clone下去,最后StackOverflowError了。本来想把刚刚创建的保存下来标记一下,但是多线程不太好处理,最后想到的就是使用ThreadLocal,把刚刚clone出来还未进行深度clone的那个对象保存到ThreadLocal,如果它的关系类clone的时候需要使用对应的记录就直接返回那个引用而不是再clone,这样就不会StackOverflowError了。

使用Cglib

现在在做我的持久层,本来是打算现在就做延迟加载的,但是考虑到刚开始没有太大的必要,这个框架的定位还是快速开发,开发小型的应用,所以先完全加载,这样比较简单。不过还是先做了接口,开始使用的是JDK带的Proxy类,但是它只能创建Interface,不能扩展类,后来想到Cglib应该是做这个的,大致看了下,使用也很简单,就先写了一个简单的,目前只是延迟克隆(clone),因为我对数据库记录对应的对象只保留一个主要的,其他部分要使用,返回的是一个深度克隆的对象,现在使用Cglib返回一个增强的实例,保存了对那个数据库对象的引用,只有在对那个对象进行写操作的时候才进行真正的克隆并且把变化保存到克隆的对象,然后调用对象的save方法才会进行持久化并替换原来的对象,还不知道这样会有多大的性能提高,但是不会有太大的坏处。

类型转换和自动装箱

这段时间还在完成我的大轮子计划的持久化部分,本来想利用原来做的EJB单元测试的代码,结果发现自己还是对很多API不熟悉。我要将ResultSet的结果转换为Java的类型,本来是打算用一个工具类来转换的,结果发现ResultSet.getObject()返回的就是Java的类型。另外一个发现就是通过反射,JDK其实会自动为你进行装箱拆箱操作,如果传入的参数是Integer类型,而方法的实际类型是int,JDK会自动转换,反之也是一样,返回的结果是Integer,实际返回的是int,JDK也会自动转换,当然,这个JDK是1.4,不是JDK1.5。

更早的文章 更新的文章

© 2024 解惑

本主题由Anders Noren提供向上 ↑