通用配置
正如初始化中所解釋的,RestClientBuilder
支持提供RequestConfigCallback
和HttpClientConfigCallback
,它們允許Apache Async Http Client公開的任何自定義。這些回調可以修改客戶端的某些特定行爲,而不會覆蓋RestClient
初始化的所有其他默認配置,本節介紹一些需要爲低級別Java REST Client進行其他配置的常見方案。
超時
配置請求超時可以通過在通過其構建器構建RestClient
時提供RequestConfigCallback
實例來完成,該接口有一個方法接收org.apache.http.client.config.RequestConfig.Builder的實例作爲參數並具有相同的返回類型,可以修改請求配置構建器,然後返回。在以下示例中,我們將增加連接超時(默認爲1秒)和socket超時(默認爲30秒),我們也相應地調整最大重試超時(默認爲30秒)。
RestClientBuilder builder = RestClient.builder(
new HttpHost("localhost", 9200))
.setRequestConfigCallback(
new RestClientBuilder.RequestConfigCallback() {
@Override
public RequestConfig.Builder customizeRequestConfig(
RequestConfig.Builder requestConfigBuilder) {
return requestConfigBuilder
.setConnectTimeout(5000)
.setSocketTimeout(60000);
}
})
.setMaxRetryTimeoutMillis(60000);
線程數
Apache Http Async Client默認啓動一個調度線程,以及連接管理器使用的許多工作線程,與本地檢測到的處理器數量一樣多(取決於Runtime.getRuntime().availableProcessors()
的返回),線程數可以修改如下:
RestClientBuilder builder = RestClient.builder(
new HttpHost("localhost", 9200))
.setHttpClientConfigCallback(new HttpClientConfigCallback() {
@Override
public HttpAsyncClientBuilder customizeHttpClient(
HttpAsyncClientBuilder httpClientBuilder) {
return httpClientBuilder.setDefaultIOReactorConfig(
IOReactorConfig.custom()
.setIoThreadCount(1)
.build());
}
});
基本認證
配置基本身份驗證可以通過在通過其構建器構建RestClient
時提供HttpClientConfigCallback
來完成,該接口有一個方法接收org.apache.http.impl.nio.client.HttpAsyncClientBuilder的實例作爲參數並具有相同的返回類型,可以修改http
客戶端構建器,然後返回。在以下示例中,我們設置了需要基本身份驗證的默認憑據提供程序。
final CredentialsProvider credentialsProvider =
new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials("user", "password"));
RestClientBuilder builder = RestClient.builder(
new HttpHost("localhost", 9200))
.setHttpClientConfigCallback(new HttpClientConfigCallback() {
@Override
public HttpAsyncClientBuilder customizeHttpClient(
HttpAsyncClientBuilder httpClientBuilder) {
return httpClientBuilder
.setDefaultCredentialsProvider(credentialsProvider);
}
});
可以禁用搶佔式身份驗證,這意味着每個請求都將在沒有授權標頭的情況下發送,以查看是否接受該請求,並且在接收到HTTP401
響應後,將重新發送與基本身份驗證標頭完全相同的請求,如果你希望這樣做,那麼你可以通過HttpAsyncClientBuilder
禁用它:
final CredentialsProvider credentialsProvider =
new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials("user", "password"));
RestClientBuilder builder = RestClient.builder(
new HttpHost("localhost", 9200))
.setHttpClientConfigCallback(new HttpClientConfigCallback() {
@Override
public HttpAsyncClientBuilder customizeHttpClient(
HttpAsyncClientBuilder httpClientBuilder) {
httpClientBuilder.disableAuthCaching();
return httpClientBuilder
.setDefaultCredentialsProvider(credentialsProvider);
}
});
httpClientBuilder.disableAuthCaching();
— 禁用搶佔式身份驗證。
加密通信
也可以通過HttpClientConfigCallback
配置加密通信,作爲參數接收的org.apache.http.impl.nio.client.HttpAsyncClientBuilder公開了多種方法來配置加密通信:setSSLContext
、setSSLSessionStrategy
和setConnectionManager
,按照最不重要的優先順序排列,以下是一個例子:
KeyStore truststore = KeyStore.getInstance("jks");
try (InputStream is = Files.newInputStream(keyStorePath)) {
truststore.load(is, keyStorePass.toCharArray());
}
SSLContextBuilder sslBuilder = SSLContexts.custom()
.loadTrustMaterial(truststore, null);
final SSLContext sslContext = sslBuilder.build();
RestClientBuilder builder = RestClient.builder(
new HttpHost("localhost", 9200, "https"))
.setHttpClientConfigCallback(new HttpClientConfigCallback() {
@Override
public HttpAsyncClientBuilder customizeHttpClient(
HttpAsyncClientBuilder httpClientBuilder) {
return httpClientBuilder.setSSLContext(sslContext);
}
});
如果未提供顯式配置,則將使用系統默認配置。
其他
對於所需的任何其他必需配置,應參考Apache HttpAsyncClient文檔:https://hc.apache.org/httpcomponents-asyncclient-4.1.x/。
如果你的應用程序在安全管理器下運行,則可能會受到JVM默認策略的限制,即無限期緩存正主機名解析和負主機名解析10秒,如果你連接客戶端的主機的已解析地址隨時間變化,那麼你可能希望修改默認的JVM行爲,可以通過將networkaddress.cache.ttl=<timeout>和networkaddress.cache.negative.ttl=<timeout>添加到Java安全策略來修改這些。
節點選擇器
客戶端以循環方式將每個請求發送到其中一個配置的節點,可以選擇通過初始化客戶端時需要提供的節點選擇器來過濾節點,這在啓用嗅探時很有用,以防只有HTTP請求才能觸發專用主節點。對於每個請求,客戶端將運行最終配置的節點選擇器以過濾候選節點,然後從剩餘的節點中選擇列表中的下一個節點。
RestClientBuilder builder = RestClient.builder(
new HttpHost("localhost", 9200, "http"));
builder.setNodeSelector(new NodeSelector() {
@Override
public void select(Iterable<Node> nodes) {
/*
* Prefer any node that belongs to rack_one. If none is around
* we will go to another rack till it's time to try and revive
* some of the nodes that belong to rack_one.
*/
boolean foundOne = false;
for (Node node : nodes) {
String rackId = node.getAttributes().get("rack_id").get(0);
if ("rack_one".equals(rackId)) {
foundOne = true;
break;
}
}
if (foundOne) {
Iterator<Node> nodesIt = nodes.iterator();
while (nodesIt.hasNext()) {
Node node = nodesIt.next();
String rackId = node.getAttributes().get("rack_id").get(0);
if ("rack_one".equals(rackId) == false) {
nodesIt.remove();
}
}
}
}
});
設置分配感知節點選擇器,允許選擇本地rack中的節點(如果有),否則轉到任何rack中的任何其他節點。它充當偏好而不是嚴格的要求,如果沒有任何本地節點可用,它將進入另一個rack,而不是在這種情況下不返回任何節點,這將使客戶端在首選rack中沒有任何節點可用時強制恢復本地節點。
不一致地選擇相同節點集的節點選擇器將使循環行爲變得不可預測並且可能不公平,上面的偏好示例很好,因爲它可以解釋已經影響輪詢調度可預測性的節點的可用性,節點選擇不應該依賴於其他外部因素,否則輪詢調度將無法正常工作。