使用com.sun.jersey.client.apache.ApacheHttpClient和Spring调用rest api时遇到连接时遇到问题。几个电话都通过了,但我突然得到了一个:
DEBUG (org.apache.commons.httpclient.MultiThreadedHttpConnectionManager:501) : - Unable to get a connection, waiting..., hostConfig=HostConfiguration[host=www.dummyapi.com]`
就是这样。没什么了!
这是我的applicationContext.xml:
<bean id="customHttpClient" class="com.sun.jersey.client.apache.ApacheHttpClient">
<constructor-arg>
<bean class="com.sun.jersey.client.apache.ApacheHttpClientHandler" >
<constructor-arg>
<bean class="org.apache.commons.httpclient.HttpClient" >
<constructor-arg>
<bean class="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager" >
<property name="params">
<bean class="org.apache.commons.httpclient.params.HttpConnectionManagerParams">
<property name="defaultMaxConnectionsPerHost" value="10" />
</bean>
</property>
</bean>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
</constructor-arg>
<constructor-arg ref="customClientConfiguration" />
</bean>
<bean id="customRestClient" class="com.custom.web.service.common.RestClient" >
<constructor-arg ref="customHttpClient" />
<constructor-arg value="${my.service.url}" />
</bean>
这些是我的课程:
import com.sun.jersey.client.apache.config.DefaultApacheHttpClientConfig;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
public class CustomApacheHttpClientConfig extends DefaultApacheHttpClientConfig {
/**
* Constructor with username and password.
* @param username
* @param password
*/
public CustomApacheHttpClientConfig(final String username, final String password) {
getClasses().add(JacksonJsonProvider.class);
getProperties().put(PROPERTY_PREEMPTIVE_AUTHENTICATION, Boolean.TRUE);
getState().setCredentials(null, null, -1, username, password);
}
}
package com.custom.web.service.common;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import org.apache.log4j.Logger;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.net.URI;
public class RestClient {
private static final Logger LOG = Logger.getLogger(RestClient.class);
private final String baseUrl;
private final Client client;
private final ObjectMapper objectMapper;
public RestClient(final String baseUrl, final Client client) {
this.baseUrl = baseUrl;
this.client = client;
this.objectMapper = new ObjectMapper();
this.objectMapper.getDeserializationConfig().set(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
public RestClient(final String baseUrl, final Client client, final ObjectMapper objectMapper) {
this.baseUrl = baseUrl;
this.client = client;
this.objectMapper = objectMapper;
}
public String getBaseUrl() {
return baseUrl;
}
public Client getClient() {
return client;
}
public ObjectMapper getObjectMapper() {
return objectMapper;
}
}
电话:
public void do() {
UriBuilder uriBuilder = UriBuilder.fromUri(
String.format(
this.customRestClient.getBaseUrl(),
"SE")).
path(SOME_UNIT_PATH_PARAM).
path(id).
path(SOME_OTHER_PATH_PARAM);
ClientResponse response = this.customRestClient.getClient().resource(uriBuilder.build()).get(ClientResponse.class);
if (response.getClientResponseStatus().getStatusCode() != 200) {
throw new CustomRestClientException(String.format("Something went wrong when getting stuff from rest api for id: %s %d %s ",
id, response.getClientResponseStatus().getStatusCode(),
" reasonPhrase: " + response.getClientResponseStatus().getReasonPhrase()));
}
String json = response.getEntity(String.class);
Stuff[] stuff = null;
try {
stuff = this.customRestClient.getObjectMapper().readValue(json, Stuff[].class);
} catch (IOException e) {
throw new CustomRestClientException(
String.format("Something went wrong when reading json value for stuff from api: %s %s %d %s ",
id, json, response.getClientResponseStatus().getStatusCode(), " reasonPhrase: " + e.getMessage()));
}
List<Stuff> stuffList = new ArrayList<Stuff>();
stuffList.addAll(Arrays.asList(stuff));
}
正如您所看到的,我没有在每次请求后显式关闭连接,我将其留给ApacheHttpClientHandler。我试图增加defaultMaxConnectionsPerHost,但没有运气。我也浏览过网络,只找到了人们在代码中实例化客户端然后在那里销毁它的例子。请帮我解决这个问题,因为我已经碰到了这堵砖墙。
关心 雅各布!
答案 0 :(得分:4)
找到我的问题的原因:
似乎我忘了设置soTimeout和connectionTimeout。 documentation明确指出:
的 soTimout:
定义默认套接字超时(SO_TIMEOUT),以毫秒为单位,即等待数据的超时。超时值为零被解释为无限超时。
和
的 connectionTimout:
确定在建立连接之前的超时。值为零表示不使用超时。默认值为零。
所以我所要做的就是定义这个:
<bean id="customHttpClient" class="com.sun.jersey.client.apache.ApacheHttpClient">
<constructor-arg>
<bean class="com.sun.jersey.client.apache.ApacheHttpClientHandler" >
<constructor-arg>
<bean class="org.apache.commons.httpclient.HttpClient" >
<constructor-arg>
<bean class="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager" >
<property name="params">
<bean class="org.apache.commons.httpclient.params.HttpConnectionManagerParams">
<property name="defaultMaxConnectionsPerHost" value="30" />
<property name="maxTotalConnections" value="30" />
<property name="soTimeout" value="60000" />
<property name="connectionTimeout" value="5000" />
</bean>
</property>
</bean>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
</constructor-arg>
<constructor-arg ref="customClientConfiguration" />
</bean>
瞧!一切都像魅力一样! 谢谢skaffman你指出我正确的方向!
答案 1 :(得分:0)
您仍然需要关闭连接,连接管理器不会为您执行此操作。经理只负责汇集连接,它不知道你何时完成使用它们。
如果你不关闭它们,那么连接管理器仍然认为你正在使用它们,它会很快耗尽。