原文连接html
最近在用 Python
的 SQLAlchemy
库时(一个相似于 Hibernate
的 ORM
框架),发现它的 Events
事件还挺好用。java
简单说就是当某张表的数据发生变化(曾、删、改)时会有一个事件回调,这样一些埋点之类的需求均可以实如今这里,同时和业务代码彻底解耦,维护起来也很方便。git
例如当订单状态发生变化须要发异步通知这样的需求也能够利用这个实现。github
根据我以前使用 Mybatis
的经验,好像没怎么注意有这个功能,查阅了下发现 Hibernate
是支持的,只是我用得也少,因此也没怎么在乎。sql
逐渐偏离主题。。。数据库
说这些的主要缘由是我打算为以前写的 cicada (轻量的 http 框架)加一个数据库操做包,也实现相似的功能。markdown
最终的使用效果以下:oracle
初版本还比较粗糙,但功能都具有。框架
第一步:须要实现一个初始化接口,该接口会在应用初始化的时候执行。异步
紧接着咱们须要定义一个 Model
:
@Data @OriginName("user") @ToString public class User extends Model { @PrimaryId private Integer id ; private String name ; private String password ; @FieldName(value = "city_id") private Integer cityId ; private String description ; } 复制代码
它所对应的表结构以下:
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL, `password` varchar(100) DEFAULT NULL, `description` varchar(100) DEFAULT NULL, `roleId` int(11) DEFAULT NULL COMMENT '角色ID', `city_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) 复制代码
当须要查询数据时:
即可以这样访问数据库。
当须要更新数据时:
在初始化 DBHandle
时指定一个回调接口(也就是这里的 UserUpdateListener
),即可以在修改数据的时候拿到本次修改的数据实体。
@Slf4j public class UserUpdateListener implements DataChangeListener { @Override public void listener(Object obj) { log.info("user update data={}", obj.toString()); } } 复制代码
同时咱们能够在控制台看到数据修改时的回调结果:
这样就实现了文初所提到的功能,即可以实现一些数据变化后须要执行的业务逻辑。
下面重点来看看这个功能的实现过程;其实经过生成 DBHandle
(数据库增删改的接口)实例的 API
即可以看出些端倪。
DBHandle handle = (DBHandle) new HandleProxy(DBHandle.class).getInstance(new UserSaveListener()); 复制代码
DBHandel
虽然是个接口,可是它并非使用一个实现类来实现的,而是经过代理生成。
那经过代理生成比直接实例化实现类有啥好处呢?
举个例子,好比如今你想买一个新手机。
第一种方式能够直接在官方旗舰店买一个标配的手机,没有额外的东西只有一个手机。
固然你也能够在某些第三方经销商那里购买带套餐的,好比套餐一
在标配的基础上多了保护壳、贴膜
之类的附加属性。
这个经销商就相似于咱们这里的代理类,他能够在原有实现的基础上新增一些东西,至于新增什么全看你本身的须要了。
而之因此叫动态代理,也是由于这个代理类是在程序运行过程当中动态建立的,在编译过程当中并不能肯定这个类的全限定名。
下面来看看这个代理类是如何生成的:
JDK
自带的
API
实现的,具体参数能够直接参考官方文档:
docs.oracle.com/javase/8/do…
总之这样即可以建立一个 DBHandler
接口的代理对象,而真正的代理过程是在 InvocationHandler#invoke()
函数中实现的:
这里的实现也是很是简单,在实现完代理对象的业务逻辑后便回调咱们传入的事件接口,其中的参数即是当前的数据库 Model
实体对象。
不过须要注意的是,这个事件回调和业务线程是同一个,因此写在这里的逻辑建议都为异步(Hibernate 和 SQLAlchemy 都存在这个状况)。
以上即是整个动态代理实现 ORM
监听机制的全过程,其实能够看出并无它名称那样看起来高大上,固然自己实现也比较简单。
同时也不止这一种实现方式,例如:
etc..
他们的具体实现及优劣就不在本文探讨了,感兴趣的后续我会将这个功能用这几种方式实现一遍。
同时动态代理的应用也不止于此,好比:
RPC
中无感知的远程调用。Spring
中的 AOP
、拦截器等。后续会继续完善这个 ORM
库,甚至能够独立出来做为一个小巧的数据库工具也何尝不可。
相关源码见此处: github.com/TogetherOS/…
你的点赞与分享是对我最大的支持