服务间通信之Http框架
服务间通信之Http框架
1.服务间通讯调用
2.jersey代理连接池
3.综上
1.服务间通信调用
首先不提在微服务中,就是在我们使用spring cloud技术栈构建我们的服务中,如果我们需要调用其他的服务或者第三方的服务,一般的通信方式无非是http通信、rpc通信、异步消息通信等等,当然大多数服务一般都是以http接口的形式提供出来,那么可以用来调用该服务的方法可谓是多种多样,各式各样的http客户端,apache Httpclient、OKHttp、jersey-client、原生HttpURLConnection等等,大体以上几种我都用过,做了一些对比,可以看一下:
1.1 java原生HttpURLConnection
这个用的不多,在正式项目中几乎没有用过,写一些小的demo的时候偶尔用过,使用的原因更多是当时懒得再引入其他第三方的http框架了,用法如下:
public static void sendPostJson() throws IOException {
String path = "http://127.0.0.1:8080";
JSONObject obj = new JSONObject();
obj.put("id", "10001");
obj.put("name", "xiaxuan");
obj.put("sex", "M");
String jsonStr = obj.toJSONString();
byte[] data = jsonStr.getBytes();
java.net.URL url = new java.net.URL(path);
java.net.HttpURLConnection conn = (java.net.HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Connection", "keep-alive");
conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
conn.setRequestProperty("Content-Length", String.valueOf(data.length));
OutputStream outStream = conn.getOutputStream();
outStream.write(data);
outStream.flush();
outStream.close();
if(conn.getResponseCode() == 200){
BufferedReader in = new BufferedReader(new InputStreamReader((InputStream) conn.getInputStream(), "UTF-8"));
String msg = in.readLine();
System.out.println("msg: " + msg);
in.close();
}
conn.disconnect();
}
不多说,用法还是挺复杂的,简单的请求甚至需要数十行才能完成,并且不易于理解,当时写完调试了半天才通,挺后悔用原生的HttpURLConnection来进行当时功能的测试,感觉比我当时写的一个http-server还要麻烦,在正式的项目中一般不会用到原生http请求类。
1.2 apache HttpClient
apache common下的子项目,高效、功能丰富、易于使用,这个在我所在的公司中的所负责的项目中用的不多,找了一个,用法如下:
public CloseableHttpResponse stream(String url) throws IOException {
String fileId = url.substring(url.lastIndexOf("/"), url.length());
url = this.bootConfig.getHttpFilesUri() + fileId;
log.info("DefaultTransport files url: " + url);
HttpGet get = new HttpGet(url);
CloseableHttpResponse response = (CloseableHttpResponse)this.client.execute(get);
return response;
}
这个是内部请求一个下载图片使用的,get请求获取文件,使用比较简单,更多的使用方法还是请去官网看下吧:
http://hc.apache.org/httpclient-3.x/tutorial.html
1.3 OKhttp
这个是我在open server项目中使用的一款http框架,特性如下:
-
支持http2.0,对一台机器的请求共享一个socket。
-
采用连接池技术,可以有效的减少Http链接数量。
-
无缝集成GZIP压缩技术。
-
支持Response Cache,避免重复请求
-
域名多IP支持。
以下是我在以前写的一个简单demo,项目中使用的是okhttp连接池,设置的参数较多,各种拦截器之类的,使用比较复杂,不再展示出来。
OkHttpClient client = new OkHttpClient();
String run(String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
给我的感觉是确实是好用,相当易用的api,设置读取超时、写入超时、重试拦截器、长连接等等都很容易实现,在先前的文章
Spring boot使用ProxyFilter进行服务代理,这篇文章中使用的ProxyFilter里面原生使用的http连接池是使用的HttpClient的连接池,但是连接池中连接数太少,各种参数的配置不适合于我们系统的开发,替换成了OkHttp的连接池,后来我升级为Okhttp3之后,加上的重试拦截器等等。另外OkHttp的特性中还提到了另外一点,就是 OkHttp还处理了代理服务器问题和SSL握手失败问题,ssl握手失败问题是比较难定位和追踪的,在将公司内我所负责的模块升级为java8以后,因为https产生的问题就是多个,带来不少的麻烦。
1.4 jersey client
我所负责的另外一个项目中,使用的rest框架是jersey,调用其他服务使用的是jersey提供的jersey-client,用法如下:
private static Client getClient () {
return ClientBuilder.newClient().register(JacksonFeature.class);
}
public static EnterpriseRs openDomain (String url, EnterpriseDomain domain) {
Client client = getClient();
Response response = client.target(url).request().accept(MediaType.APPLICATION_JSON_TYPE)
.buildPost(Entity.entity(domain, MediaType.APPLICATION_JSON_TYPE))
.invoke();
// String str = response.readEntity(String.class);
EnterpriseEmailRs rs;
String data = "";
try {
data = response.readEntity(String.class);
rs = objectMapper.readValue(data.getBytes(), EnterpriseEmailRs.class);
} catch (Exception e) {
log.error("email exception {}", data);
throw new ServiceException(SecurityError.ENTERPRISE_EMAIL_ERROR);
}
closeClient(client);
return rs.getData();
}
简单来说就是api使用简单,很舒服,但是需要和jersey一起来使用,没有单独拿出来进行http的请求。
2.jersey代理连接池
以上说了这么多的http框架,但是在使用的时候要实例化client或者从连接池里面拿出连接,进行各种配置,指定url,参数,接收数据类型等等,虽说可以讲所有的GET、POST、PUT方法的调用加上泛型修饰,但是未免有些臃肿,但也确实是有比较好的方法,我只写出接口,然后进行一定程度的配置后,调用这些接口就会去请求远程的服务,jersey确实是可以做到,在我所在公司,以在产品越来越大,进行模块拆分独立部署的时候,相互之间的内部调用的方法便变成了内网http请求,在这虽说更好的方法是使用rpc框架来进行模块之间的通信,但是对于我们的产品来说使用rest通信,然后进行一定程度的性能调优之后,还是可以接受的,因此便一直采用了这种通信方法。
jersey内置一个WebResourceFactory类,我们再使用的时候,注册webTarget,指定远程调用地址、编写的接口,然后使用的时候从resources中取出对应注册的接口,调用的时候,就是调用到远程服务,这个整个的配置十分复杂,要完全讲述下来需要搭一套完整的以jersey为rest框架的应用程序,基本上可以抽出来单独写一个系列了,这个有疑问的可以私信我单独讨论。
3. 综上
上述讲了多种http框架的使用,有的难用,有的易用,有的功能十分强大,支持各种特性、有的使用依赖于一个完整的rest框架,如jersey-client和jersey代理连接池等等,但是讲述以上内容并不是说对这几个http框架进行一个对比,而是要在spring cloud搭建的系统中使用一款http框架来进行服务间的调用,这一片是对我使用的http的框架的一个总结,下一篇将要讲述spring cloud中的feign,以一种十分优雅的形式调用远程服务,并且可以选择底层调用的http的框架是HttpClient还是OkHttp,这个在下一篇文章中将要展开。