是一个抽象类型,是抽象方法的集合(100%的抽象类)。接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。
就像一个类一样,一个接口也能够拥有方法和属性。但是在接口中声明的方法默认是抽象的(即只有方法标识符,而没有方法体)。
实现接口的类必须实现该接口中的方法。
如果一个类实现了一个接口中要求的所有的方法,然而没有提供方法体而仅仅只有方法标识,那么这个类一定是抽象类(必须记住:抽象方法只能存在于抽象类或者接口中,但抽象类中却能存在非抽象方法,即有方法体的方法。接口是百分之百的抽象类)
接口被用来描述一种抽象。
因为Java不像C++一样支持多继承,所以Java可以通过实现接口来弥补这个局限。
接口也被用来实现解耦。
接口被用来实现抽象,而抽象类也被用来实现抽象,为什么一定要用接口呢?接口和抽象类之间又有什么区别呢?原因是抽象类内部可能包含非final的变量,但是在接口中存在的变量一定是public static final修饰的。
1.接口必须要有子类,但此时一个子类可以使用implements关键字实现多个接口;
2.接口的子类(如果不是抽象类),那么必须要覆写接口中的全部抽象方法;
3.接口的对象可以利用子类对象的向上转型进行实例化。
为了声明一个接口,我们使用interface这个关键字,在接口中的所有方法都必须只声明方法标识,而不要去声明具体的方法体,因为具体的方法体的实现是由继承该接口的类来去实现的,因此,接口并不用管具体的实现。接口中的属性默认为public static final一个类实现这个接口必须实现这个接口中定义的所有的抽象方法。
一个简单的接口就像这样:拥有全局变量和抽象方法。
package com.proxy;
//被代理的接口 ---用户管理接口
public interface IUserManager {
//等同于 public static final int a=1;
final int a=1;
void addUser(String id, String password);
}
(1) 抽象类可以有构造方法,接口中不能有构造方法
(2) 抽象类中可以有普通成员变量,接口中没有普通成员变量
(3) 抽象类中可以包含非抽象普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的方法
(4) 抽象类中的抽象方法的访问权限可以是 public、protected ,接口中的抽象方法只能是 public 类型的
(5) 一个类可以实现多个接口但只能继承一个抽象类。接口不可以实现接口,但可以继承接口并且可以继承多个接口
1.虽然接口内部定义了一些抽象方法,但是并不是所有的接口内部都必须要有方法,比如Seriallizable接口,Seriallizable接口的作用是使对象能够“序列化”,但是Seriallizable接口中却没有任何内容,也就是说,如果有一个类需要实现“序列化”的功能,则这个类必须去实现Seriallizable接口,但是却并不用实现方法(因为接口中没有方法),此时,这个Serilizable接口就仅仅是一个“标识”接口,是用来标志一个类的,标志这个类具有这个“序列化”功能。
2.一个类可以实现不止一个接口。
3.一个接口可以继承于另一个接口,或者另一些接口,接口也可以继承,并且可以多继承。在Java中,一个抽象类只能继承一个抽象类,但一个接口却可以使用extends关键字同时继承多个接口(但接口不能继承抽象类)。
4.一个类如果要实现某个接口的话,那么它必须要实现这个接口中的所有方法。
5.接口中所有的方法都是抽象的和public的,所有的属性都是public,static,final的。
6.接口用来弥补类无法实现多继承的局限。
7.接口也可以用来实现解耦。
1.在发送POST或GET请求时,返回超时异常处理办法使用try/catch对异常进行捕获。
捕获 SocketTimeoutException | ConnectTimeoutException | ConnectionPoolTimeout 异常。
public static String doGet(String url, Object params, String contentType) {
try {
return HttpUtils.doGetSend(url, params, contentType);
} catch (SocketTimeoutException | ConnectTimeoutException e) {
e.printStackTrace();
System.out.println("请求连接超时:" + e.getMessage());
} catch (IOException e) {
e.printStackTrace();
System.out.println("请求异常,异常信息:" + e.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
2.增加超时时间
假设A系统有个方法methodA,会调用B系统的methodB这个http接口,如果mehodA不追求超快的响应速度,那么你在调用methodB这个http接口时,可以增长超时时间,例如10秒超时。因为经常在某些时刻,由于网络原因或者系统原因,调用method会超时的。
@GetMapping("/test1")
public void timeOut() throws IOException {
CloseableHttpClient httpClient = HttpClients.createDefault();
// 请求第三方接口
HttpGet httpGet = new HttpGet("http://localhost:8082/springboot/hello");
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(5000)
.setConnectTimeout(5000)
.setSocketTimeout(5000).build();
httpGet.setConfig(requestConfig);
CloseableHttpResponse response = httpClient.execute(httpGet);
if (response.getStatusLine().getStatusCode() == 200) {
HttpEntity entity = response.getEntity();
// 使用工具类EntityUtils,从响应中取出实体表示的内容并转换成字符串
String string = EntityUtils.toString(entity, "utf-8");
System.out.println(string);
}
response.close();
httpClient.close();
}
3.重试
如果第一次调用methodB超时了,那么你可以尝试多调用一次。当然前提是,methodA不追求超快的响应时间。注意:调用多次不代表重复调用 制造脏数据
4.使用待处理队列
如果methodA需要很快的响应速度,那么当调用methodB接口超时时,可以使用一个队列存储本次失败的记录,然后使用一个job每隔一段时间去扫这个队列,看看是否有待处理的数据。
备注:如果对方系统挂掉了,使用待处理队列的方式,比较合适。
例如支付宝转账,当别人调用A系统的MethodA接口的时候,MethodA接口需要去调用支付宝的MethodB接口,如果超时了,那么MethodA接口可以立刻返回给调用方说:银行转账处理中。。。同时MethodA把这次转账接口失败记录到队列中,过段时间等job去扫描队列,找出失败的记录,然后再次调用支付宝接口,最终保证数据的一致性。。其实我们使用支付宝转到银行的时候,也不是立刻到账的。只要数据最终一致就好了。
5.回滚数据
catch这个超时异常,然后记录日志后,抛出这个异常,并把之前的数据回滚。让对方的系统重新调用。
备注:宁愿没有数据,也不要存储脏数据。
6.使用异步机制
如果你的业务方法中,需要调用对方的http接口,如果这个http接口不影响主流程的,那么可以使用一个线程,异步调用对方的http接口,并把超时时间设置长一些。由于使用了异步,主流程会立刻继续走的。
7.使用缓存机制
使用一台缓存服务器,每次调用先调用我们的缓存服务器里面的数据,来实现快速调用解决超时问题。
参考资料
https://blog.csdn.net/qq_19782019/article/details/80259836
https://blog.csdn.net/wei_zhi/article/details/52738471
https://blog.csdn.net/weixin_43681591/article/details/88942889