Apache OFbiz entity engine源码解读

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:

简介

最近一直在看Apache OFbiz entity engine的源码。为了能够更透彻得理解,也因为之前没有看人别人写过分析它的文章,所以决定自己来写一篇。

首先,我提出一个问题,如果你有兴趣可以想一下它的答案:

JDBC真的给数据访问提供了足够的抽象,以至于你可以在多个支持jdbc访问的数据库之间任意切换而完全不需要担心你的数据访问代码吗?

我曾经在微博上有过关于该问题的思考:


其实这个感慨正是来自于我之前在看的一篇关于jdbc的文章,里面提到了jdbc中的一些设计模式(工厂方法),提供了与底层数据库交互的抽象(不可否认是非常好的做法),可以应对在不需要修改DAO的情况下,自由切换数据库。而我结合最近在看的OFbiz的entityengine发了上面的这些吐槽!

OFbiz对数据源的访问是否仍然借助于JDBC?当然,毫无疑问。但它解决了我在吐槽中所说的,它并不依赖程序员遵循SQL标准,而是通过entity engine根据它给出的语义,生成标准的sql。这些sql包含了DML、DDL、TCL(事务控制语言),从而提供一套完整的数据访问Engine。它带来的好处是什么?省去了大量机械而重复的DAO CRUD 的编写工作量,无缝支持多达13种数据库,抽象了常用的查询/筛选逻辑,提供了通过配置生成服务而无需编写代码的底层支持!(当然好处还不止这些)。

下面我们就一起来看看entity engine到底是如何做到这些的。

源码解读

SQL的执行——SQLProcessor

SQLProcessor 负责entityengine中所有SQL的最终执行,包括了事务的提交、回滚等。从该类的实现中你能看出,ofbiz最终跟数据库打交道的还是JDBC,而因为JDBC本身就是对数据库访问的抽象,所以使用JDBC操作数据库对于任何RDBMS都是适用的,你只需要提供最终使用的数据库的jdbc-driver。但数据库的某些特性,sql,数据类型,这些并不是完全一致的标准,因此entityengine提供的语义层有效得屏蔽了SQL与字段类型等在各个数据库上的差异,使得最终用户无需直接这些差异打交道,一切都有它来处理。

提供了对实体最基本的CRUD功能——GenericDAO

GenericDAO使用了多线程技术来执行某些操作,因此创建该对象的时候需要实例化一组线程以及创建一个线程池,这些操作相对来说有些“昂贵”,在其内部采用一个staticmap 来缓存已被成功创建的对象:

public static GenericDAO getGenericDAO(GenericHelperInfo helperInfo) {
        GenericDAO newGenericDAO = genericDAOs.get(helperInfo.getHelperFullName());

        if (newGenericDAO == null) {
            genericDAOs.putIfAbsent(helperInfo.getHelperFullName(), new GenericDAO(helperInfo));
            newGenericDAO = genericDAOs.get(helperInfo.getHelperFullName());
        }
        return newGenericDAO;
    }


如果你随意浏览一个方法的实现,在其内部都会实例化一个SQLProcessor来执行拼接而成的SQL(当然这里只有简单的SQL是直接拼接的,复杂一点的,带条件的SQL都是采用各种方式生成的,比如EntityCondition)。

提供更多面向业务层的数据访问方法的抽象——GenericHelper接口

GenericHelper接口提供了更偏向业务的数据访问抽象,这使得你可以不用去关注数据源是什么,基于数据源的实现交给该接口的实现类即可。事实上,GenericHelper也确实有一个完全基于内存的实现(MemoryHelper),只是除了用于测试,好像没有正式在线上场景中使用,不过这是一个不错的想法——随着nosql的流行,一部分关系不是很强或者不是很重要的数据可以基于一些memorydb来实现。来看看该接口极其实现类的关系图:


它有两个实现者,其中一个实现便是GenericHelperDAO,毫无疑问它是基于RDBMS的实现,因为它内部都是通过GenericDAO的实例来完成数据访问的。另一个之前提到过了,是基于内存的实现。

梳理一下上面的几个部件:GenericDAO实现了基本的数据访问操作的(CRUD)。这其中,每个方法都需要具体去跟数据库通信,通过什么?通过SQLProcessor,SQLProcessor负责每次SQL的执行。通常一个系统里对于数据的访问/操作并不仅仅只是简单的CRUD,其中还包含有更复杂的操作(比如关系查询、条件删除等),因此OFbiz为这些相对复杂的操作抽象出了一个接口GenericHelper。GenericHelperDAO是对GenericHelper的实现,其内部借助于GenericDAO,来实现这些相对复杂的数据访问。到最后我们会看到entity engine内最关键的一个部件——Delegator,其内部就是基于GenericHelper来实现数据访问的。

数据库连接信息实体抽象——GenericHelperInfo

GenericHelperInfo提供了对数据库建立连接所需信息的封装(包括用户名、密码等)

数据库连接的创建工厂——ConnectionFactory

该类提供了对JDBC连接的集中创建,提供了很多静态方法,根据给定的不同参数,来创建JDBC连接: