Version1.0:2015-08-09 18:09
Version1.1:2015-10-10 21:05
新增接口设计中异常和错误码的思考
接口设计
内容列表:
引言
什么是接口
接口返回值
代码示例
异常和错误码
如何选择错误处理方式
引言
今天刚入职一个月,这个月主要做的事情是熟悉团队的技术栈和接口联调,主要包括以下几个方面:
内部web框架学习,主要基于spring做了扩展。
中间件学习:分布式缓存,分布式消息队列,分布式任务调度,分布式配置中心,数据访问层。
内部流程发布平台
因为曾经在这家公司实习过,所以在入职的第三天就接到了接口的联调的任务,刚开始也觉得接口联调很简单,慢慢的发现并不是想象的那个样子,个人觉得接口联调之前,要首先熟悉一下几个方面:
在联调的过程中发现有些依赖系统接口设计的不是很合理,自己总结一下。
业务
当前负责系统的上游和下游,对每个接口的调用链路要清楚,自己要能针对某个接口的调用画出调用链路图
依赖系统的接口人
什么是接口
,由于近年来软件的规模日益庞大,常常会需要把复杂的系统划分成小的组成部分,编程接口的设计十分重要。程序设计的实践中,编程接口的设计首先要使软件系统的职责得到合理划分。良好的接口设计可以降低系统各部分的相互依赖,提高组成单元的内聚性,降低组成单元间的耦合程度,进而提高系统的维护性和扩展性。接口的几要素:
返回值
名称,唯一标志的,类似方法名:classloader -> package name : class name :function name
传递参数
接口返回值
参考开放平台:
返回信息要明确: 如果接口调用失败,要分清楚什么是业务失败,什么是真正的失败。
如果是机遇http协议实现的接口调用:应该使用http的状态码(标志此次请求的结果是成功还是失败,大致原因是在客户端还是在服务端)加上错误码(错误码用来表示失败的具体的原因是什么)
示例代码
定义一个通用的接口返回类,代码如下:
public class Result{ /** * 本次接口调用是否成功。 * true,表示成功,result返回数据 *false,表示失败,errorMsg返回失败的原因 */ protected boolean success; /** * success=false,表示失败,errorCode返回失败的错误码 */ protected String errorCode; /** * success=false,表示失败,errorMsg返回失败的原因 */ protected String errorMsg; /** * success=true,表示成功,result返回数据 */ protected T result; /** * 默认构造函数 */ public Result() { super(); } /** * 带数据结果的构造函数,默认为成功 * @param result */ public Result(T result) { super(); this.result = result; this.success = true; } /** * 本次服务是否正常处理: *如果是,说明可以获得结果对象 *如果否,说明发生了异常,可以通过getErrorMsg()了解错误原因 * Getter method for property success. * * @return property value of success */ public boolean isSuccess() { return success; } /** * Setter method for property success. * * @param success value to be assigned to property success */ public void setSuccess(boolean success) { this.success = success; } /** * 当isSuccess()方法返回false时,返回错误原因 * Getter method for property errorMsg. * * @return property value of errorMsg */ public String getErrorMsg() { return errorMsg; } /** * Setter method for property errorMsg. * * @param errorMsg value to be assigned to property errorMsg */ public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } /** * 当isSuccess()方法返回true时,可以通过该方法获得处理结果 * Getter method for property result. * * @return property value of result */ public T getResult() { return result; } /** * Setter method for property result. * * @param result value to be assigned to property result */ public void setResult(T result) { this.result = result; } /** * Getter method for property errorCode. * * @return property value of errorCode */ public String getErrorCode() { return errorCode; } /** * Setter method for property errorCode. * * @param errorCode value to be assigned to property errorCode */ public void setErrorCode(String errorCode) { this.errorCode = errorCode; } /** ErrorEnum代表系统的错误码枚举 * @param err */ public void setError(ErrorEnum err) { if (err != null) { this.errorCode = err.getCode(); this.errorMsg = err.getErrorMsg(); } } /** * @see java.lang.Object#toString() */ @Override public String toString() { return success + ", " + errorCode + ", " + errorMsg + ", " + result; } /** * @param* @return */ public static Result newResult(){ return new Result (); }}
通过此次联调,使得自己更加懂得在写接口的时候要把返回值描写清楚,因为自己的系统对别人来说完全是黑盒子,给定一个输入应该明确的给出返回信息。
异常和错误码
在层与层之间调用接口的时候,有两种方式处理中间的错误。主要是异常、和错误码。关于哪种方式更好,网上也有很多争论,下面会先介绍异常和错误码,稍后给出自己的观点。
异常:
本文以java语言为例来说明异常相关的问题。异常就是在执行一个程序正常逻辑的过程中,出现错误的现象。java中提供了很健壮的异常处理机制,来处理这些现象。
首先要介绍一下,java中异常的类型,如下图所示。
1、Error:这种错误,比如常见的OutOfMemoryError 、StackOverflowError。这些错误信息都是无法恢复的,再比如硬件问题、jvm挂掉,所以在继承关系中,你会发现分成了Error和Exception。
2、Checkd Exceptions:检查型异常,是我们在程序中显示的声明并捕获的异常,并尝试恢复的异常。比如如过我们要从远程获取某个列表,但是网络出现异常,我们恢复的策略可以从本地读取。
3、Runtime Exceptions:运行时异常,往往是由于编程错误产生的,这种异常,一般我们会重新实现自己的异常类来使用。
异常的类型介绍完了,给出一个自定义运行时异常的示例:
public class CustomerException extends RuntimeException { /** * success=false,表示失败,errorCode返回失败的错误码 */ protected String errorCode; /** * success=false,表示失败,errorMsg返回失败的原因 */ protected String errorMsg; //get&set}
在开发的过程中,每个开发者都不喜欢异常,那满满的红色,但是异常又是我们不得不每天面对的事情。什么情况下会产生异常呢?我们在开发的过程对输入的参数未做check、网络异常、db当掉、服务器挂掉等等的时候会出现异常。我们要理解java中异常处理的机制才能更好的使用异常。
java是一种面向对象的编程语言,当程序执行某条语句出现异常的时候会抛出一个Exception的对象,然后运行时环境会中断正常的流程,并尝试找到该异常的处理策略。异常的对象包含很多信息,比如调用堆栈、出错的行号、异常的类型等。
上面提到的异常处理策略实质上就是一段接收Exception对象并提供后续操作的代码。策略很简单,运行时环境首先找到抛出异常(check exception)的函数来寻找Exception Handler,如果找不到,此时调用该函数的方法肯定要处理,如果不处理他要在抛到上层,总有一个地方要处理,这里讲的是检查型异常。举个例子,如果调用关系是A->B->C,而且在C中是抛出异常的,那么运行时环境寻找Exception Handler的顺序是C->B->A。而运行时异常无需捕获。
错误码:
错误码很简单,类似如下图描述的结构:
我们需要一个全局唯一的错误码,然后需要一个字典文件描述错误码对应的错误信息,更好的话,也可以提供错误码对应的解决方案。
如何选择错误处理方式
//TODO