ginkgo spi 错误_开发SPI时不要犯这个错误

ginkgo spi 错误

您的大多数代码都是私有的,内部的,专有的,并且永远不会公开。 在这种情况下,您可以放轻松–您可以重构所有错误,包括那些可能导致API更改中断的错误。

但是,如果要维护公共API,则不是这种情况。 如果您要维护公共SPI( 服务提供商接口 ),那么情况就更糟了。

H2触发SPI

在最近的有关如何使用jOOQ实现H2数据库触发器的 Stack Overflow问题中,我再次遇到了org.h2.api.Trigger SPI,这是一个简单且易于实现的SPI,它实现了触发器语义。 以下是H2数据库中触发器的工作方式:

使用扳机

CREATE TRIGGER my_trigger
BEFORE UPDATE
ON my_table
FOR EACH ROW
CALL "com.example.MyTrigger"

实施触发器

public class MyTrigger implements Trigger {@Overridepublic void init(Connection conn, String schemaName,String triggerName, String tableName, boolean before, int type)throws SQLException {}@Overridepublic void fire(Connection conn, Object[] oldRow, Object[] newRow)throws SQLException {// Using jOOQ inside of the trigger, of courseDSL.using(conn).insertInto(LOG, LOG.FIELD1, LOG.FIELD2, ..).values(newRow[0], newRow[1], ..).execute();}@Overridepublic void close() throws SQLException {}@Overridepublic void remove() throws SQLException {}
}

整个H2触发器SPI实际上相当好用,通常您只需要实现fire()方法。

那么,这个SPI有什么问题呢?

这是非常微妙的错误。 考虑init()方法。 它具有一个boolean标志,指示触发器是在触发事件之前还是之后触发,即UPDATE 。 如果突然之间,H2还支持INSTEAD OF触发器怎么办? 理想情况下,此标志将被enum代替:

public enum TriggerTiming {BEFORE,AFTER,INSTEAD_OF
}

但是我们不能简单地引入这种新的enum类型,因为init()方法不应该被不兼容地更改,从而破坏所有实现代码! 使用Java 8,我们至少可以这样声明一个重载:

default void init(Connection conn, String schemaName,String triggerName, String tableName, TriggerTiming timing, int type)throws SQLException {// New feature isn't supported by defaultif (timing == INSTEAD_OF)throw new SQLFeatureNotSupportedException();// Call through to old feature by defaultinit(conn, schemaName, triggerName,tableName, timing == BEFORE, type);}

这将允许新的实现处理INSTEAD_OF触发器,而旧的实现仍将起作用。 但这感觉很毛,不是吗?

现在,想象一下,我们还将支持ENABLE / DISABLE子句,并且我们希望将这些值传递给init()方法。 或者,也许我们想处理FOR EACH ROW 。 目前尚无法使用此SPI进行此操作。 因此,我们将越来越多地实现这些重载,这些重载很难实现。 实际上,这已经发生了,因为还有org.h2.tools.TriggerAdapter ,它与Trigger冗余(但与Trigger略有不同)。

那么,哪种方法更好呢?

SPI提供者的理想方法是提供“参数对象”,如下所示:

public interface Trigger {default void init(InitArguments args)throws SQLException {}default void fire(FireArguments args)throws SQLException {}default void close(CloseArguments args)throws SQLException {}default void remove(RemoveArguments args)throws SQLException {}final class InitArguments {public Connection connection() { ... }public String schemaName() { ... }public String triggerName() { ... }public String tableName() { ... }/** use #timing() instead */@Deprecatedpublic boolean before() { ... }public TriggerTiming timing() { ... }public int type() { ... }}final class FireArguments {public Connection connection() { ... }public Object[] oldRow() { ... }public Object[] newRow() { ... }}// These currently don't have any propertiesfinal class CloseArguments {}final class RemoveArguments {}
}

如您在上面的示例中所见, Trigger.InitArguments已经成功开发了适当的弃用警告。 没有客户端代码被破坏,并且如果需要,可以使用新功能。 而且,即使我们不需要任何参数, close()remove()也为将来的发展做好了准备。

该解决方案的开销是每个方法调用最多分配一个对象,这不会造成太大影响。

另一个示例:Hibernate的UserType

不幸的是,这个错误经常发生。 另一个著名的例子是Hibernate难以实现的org.hibernate.usertype.UserType SPI:

public interface UserType {int[] sqlTypes();Class returnedClass();boolean equals(Object x, Object y);int hashCode(Object x);Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws SQLException;void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws SQLException;Object deepCopy(Object value);boolean isMutable();Serializable disassemble(Object value);Object assemble(Serializable cached, Object owner);Object replace(Object original, Object target, Object owner);
}

SPI看起来很难实现。 也许您可以很快地使某些东西起作用,但是您会感到放心吗? 你会认为你做对了吗? 一些例子:

  • 从来没有在nullSafeSet()也需要owner引用的情况?
  • 如果您的JDBC驱动程序不支持按名称从ResultSet获取值怎么办?
  • 如果您需要在CallableStatement为存储过程使用用户类型怎么办?

此类SPI的另一个重要方面是实现者可以向框架提供价值的方式。 在SPI中使用非void方法通常是一个坏主意,因为您将永远无法再更改方法的返回类型。 理想情况下,您应该具有接受“结果”的参数类型。 上面的许多方法都可以用单个configuration()方法代替,例如:

public interface UserType {default void configure(ConfigureArgs args) {}final class ConfigureArgs {public void sqlTypes(int[] types) { ... }public void returnedClass(Class<?> clazz) { ... }public void mutable(boolean mutable) { ... }}// ...
}

另一个示例,SAX ContentHandler

在这里看看这个例子:

public interface ContentHandler {void setDocumentLocator (Locator locator);void startDocument ();void endDocument();void startPrefixMapping (String prefix, String uri);void endPrefixMapping (String prefix);void startElement (String uri, String localName,String qName, Attributes atts);void endElement (String uri, String localName,String qName);void characters (char ch[], int start, int length);void ignorableWhitespace (char ch[], int start, int length);void processingInstruction (String target, String data);void skippedEntity (String name);
}

此SPI缺点的一些示例:

  • 如果在endElement()事件中需要元素的属性怎么办? 您必须自己记住它们。
  • 如果您想在endPrefixMapping()事件中知道前缀映射uri怎么办? 还是其他任何事件?

显然,SAX针对速度进行了优化,并且在JIT和GC仍然较弱的时候针对速度进行了优化。 尽管如此,实现SAX处理程序并非易事。 部分原因是由于SPI难以实现。

我们不知道未来

作为API或SPI提供程序,我们根本不知道未来。 现在,我们可能认为给定的SPI就足够了,但是我们将在下一个次要版本中将其破坏。 否则我们不会破坏它,并告诉我们的用户我们无法实现这些新功能。

通过以上技巧,我们可以继续发展我们的SPI,而不会引起任何重大变化:

  • 始终将唯一一个参数对象传递给方法。
  • 总是返回void 。 让实现者通过参数对象与SPI状态进行交互。
  • 使用Java 8的default方法,或提供“空”默认实现。

翻译自: https://www.javacodegeeks.com/2015/05/do-not-make-this-mistake-when-developing-an-spi.html

ginkgo spi 错误

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/337615.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python账号密码一一对应_python模拟用户登录系统,如何两个用户输入各自的密码才能登入?...

展开全部 #我可以把我自己2113的成果送你&#xff0c;你来研究5261研究 import json #用来存储数据4102的模块 import os #用来进行文件操作1653 import sys #获取脚本所在目录用 import re #用来进行字符串操作 script_path os.path.realpath(__file__) PATH os.path.dirnam…

计算机课实验三,成都信息工程学院计算机网络课程实验三

成都信息工程学院计算机网络课程实验三 本文关键词&#xff1a;成都&#xff0c;计算机网络&#xff0c;信息工程学院&#xff0c;课程&#xff0c;实验成都信息工程学院计算机网络课程实验三 本文简介&#xff1a;计算机网络实验报告实验三&#xff1a;编写客户服务器程序班级…

C语言#define与typedef的区别

点击蓝字关注我们在C语言编程中&#xff0c;typedef 和 #define是最常用语句&#xff0c;可能很多工作过几年的工程师都没有去深究过它们的一些用法和区别。typedef的用法在C/C语言中&#xff0c;typedef常用来定义一个标识符及关键字的别名&#xff0c;它是语言编译过程的一部…

netflix_Netflix Archaius用于物业管理–基础知识

netflixNetflix Archaius提供了一组精巧的功能&#xff0c;可将动态属性加载到应用程序中。 这篇博客文章只是我所了解的Archaius范围的文档&#xff0c;比我在这里所记录的内容要多得多&#xff0c;但这应该提供一个很好的开始&#xff1a; 默认行为 考虑一个简单的属性文件…

python安装pygame模块_windows下 python 如何安装pygame模块

本机系统&#xff1a;win7&#xff0c;Pyhon版本&#xff1a; 3.6.0 1. 安装下载python 官网 https://www.python.org/ 下载地址 https://www.python.org/downloads/windows/ 下载后运行并安装。注意&#xff1a; 官网明确表示&#xff0c;3.5及以上版本不支持xp操作系统。要兼…

html文字添加波浪线,利用css渐变给文字下方加波浪线

具体代码如下.wavy-line-decoration {position: relative;line-height: 1.5em;}.wavy-line-decoration::before {content: ;position: absolute;bottom: -3px;width: 100%;height: 0.25em;background: // 可以给同一个元素同时添加多个背景渐变图层&#xff0c;用逗号隔开&…

新旧C++生成随机浮点数方法,你喜欢哪个?

点击蓝字关注我们一、在C11之前&#xff0c;我们通常采用rand函数来生成随机数。有时我们想用rand生成一组随机数&#xff0c;即使我们调用了srand&#xff0c;但生成的还是相同值。为什么会产生这种情况&#xff1f;又该如何解决&#xff1f;下面将用第一视角一起探究这其中的…

arm926ej_EJB超时策略:它们如何提供帮助?

arm926ejEJB 3.1在其API中引入了与超时相关的注释。 AccessTimeout StatefulTimeout 让我们快速看一下它们是什么以及它们为什么重要 AccessTimeout 指定一个排队请求&#xff08;等待另一个线程完成&#xff09;超时的时间段。 当您的会话bean实例被并发请求轰炸时&#…

html页面加载完成后会触发的事件_前端隐秘角落 - 页面渲染

前言如图所示&#xff0c;webkit内核浏览器的渲染过程(解析HTML&#xff0c;构建DOM树&#xff0c;解析CSS&#xff0c;构建CSSOM树 &#xff0c;构建render树&#xff0c;布局layout&#xff0c;绘制painting)&#xff0c;这些过程理解起来可能有些抽象&#xff0c;今天我们一…

计算机进管理提示找不到入口,win10系统开机提示xxxdll模块已加载但找不到入口点的教程...

有关win10系统开机提示xxxdll模块已加载但找不到入口点的操作方法想必大家有所耳闻。但是能够对win10系统开机提示xxxdll模块已加载但找不到入口点进行实际操作的人却不多。其实解决win10系统开机提示xxxdll模块已加载但找不到入口点的问题也不是难事&#xff0c;小编这里提示两…

十大经典排序,你真的都会了吗?(源码详解)

点击蓝字关注我们一、前言&#xff1a;排序的概念排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键…

jvm 架构_不可变的基础架构,热部署和JVM

jvm 架构您是否在生产中部署和取消部署基于JVM的应用程序&#xff08;无论JVM容器/无容器&#xff09;&#xff1f; 也就是说&#xff0c;当您拥有某个应用程序或服务的新版本时&#xff0c;是否通过“取消部署”和“热部署”该应用程序的新更新版本来更改正在运行的JVM&#x…

c语言默认参数_5.1 C++有默认参数的函数

点击上方“C语言入门到精通”&#xff0c;选择置顶第一时间关注程序猿身边的故事作者闫小林白天搬砖&#xff0c;晚上做梦。我有故事&#xff0c;你有酒么&#xff1f;C有默认参数的函数在函数调用时形参从实参获取值&#xff0c;因为实参的个数要和形参相同&#xff0c;但有时…

计算机组成原理唐朔飞课后答案第六章,计算机组成原理第六章部分课后题答案(唐朔飞版)...

计算机组成原理第六章部分课后题答案(唐朔飞版) 6.4 设机器数字‎长为8位(含1位符号‎位在内)&#xff0c;写出对应下‎列各真值的‎原码、补码和反码‎。 -13/64&#xff0c;29/128&#xff0c;100&#xff0c;-87 解&#xff1a;十进制数 二进制数 原 码 反 码 补 码 -13/64 …

jboss eap 7.0_是时候抛弃Java 7 – JBoss EAP 6.4了!

jboss eap 7.0这一周真是太棒了。 JBoss EAP 6.4已发布&#xff0c;在众多技术增强和新功能中 &#xff0c;最大的是&#xff1a;Java 8已添加到受支持的配置列表中。 其中包括Oracle JDK和IBM JDK。 Java SE 7公开更新结束通知 2015年4月之后&#xff0c;Oracle将不再将Java …

C语言史上最愚蠢的BUG ???

点击蓝字关注我们本文来自“The most stupid C bug ever”&#xff0c;很有意思&#xff0c;分享给大家。我相信这样的bug&#xff0c;就算你是高手你也会犯的。你来看看作者犯的这个Bug吧。。首先&#xff0c;作者想用一段程序来创建一个文件&#xff0c;如果有文件名的话&…

python 字符串转日期_我总结的130页Python与机器学习之路V1.2.pdf,都是干货!

告别枯燥&#xff0c;通过学习有趣的小例子&#xff0c;扎实而系统的入门Python&#xff0c;从菜鸟到大师&#xff0c;个人觉得这是很靠谱的一种方法。通过一个又一个的小例子&#xff0c;真正领悟Python之强大&#xff0c;之简洁&#xff0c;真正做到高效使用Python.两周前发出…

大学计算机需要论文吗,大一新生刚开学,是否有必要带电脑?听听辅导员的建议,非常中肯...

原标题&#xff1a;大一新生刚开学&#xff0c;是否有必要带电脑&#xff1f;听听辅导员的建议&#xff0c;非常中肯各大高校的录取工作正在如火如荼的进行&#xff0c;很快考生们就能接到来自各个学校的录取通知书。对于考生来说&#xff0c;没有什么事情会比被心仪的大学录取…

计算机系统是连续系统,连续系统的计算机模拟

连续系统的计算机模拟 (36页)本资源提供全文预览&#xff0c;点击全文预览即可全文预览,如果喜欢文档就下载吧&#xff0c;查找使用更方便哦&#xff01;29.9 积分&#xfeff; 第2章 连续系统的计算机模拟本章讨论连续系统的模拟技术,由于这类系统中状态随时间连续动态地变化&…

ae合成设置快捷键_教程|AE教程第三波:必须掌握的关键帧之基础设置

该如何高效的学习AE&#xff1f;星驰君认为知其然还需知其所以然正确的学习顺序应该是了解核心原理&#xff0c;掌握基本操作&#xff0c;案例实战模仿比如&#xff0c;想要更好的掌握和运用关键帧来制作更复杂的效果。就先要知道关键帧是什么关键帧&#xff1a;计算机动画术语…