Невозможно получить соединение при выполнении нескольких звонков с использованием джерси ApacheHttpClient - PullRequest
1 голос
/ 10 января 2011

У меня проблемы с отсутствием соединений при вызове API отдыха с com.sun.jersey.client.apache.ApacheHttpClient и Spring Пару вызовов проходит, но вдруг я получаю:

DEBUG (org.apache.commons.httpclient.MultiThreadedHttpConnectionManager:501) : - Unable to get a connection, waiting..., hostConfig=HostConfiguration[host=www.dummyapi.com]`

вот и все. Ничего больше!

Это моё приложениеContext.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, но не повезло. Я также просматривал веб-страницы и нашел только примеры, когда люди создают свой клиент в коде, а затем уничтожают его там. Пожалуйста, помогите мне разобраться в этом, потому что я ударился об кирпичную стену.

С уважением Jakob!

Ответы [ 2 ]

4 голосов
/ 21 января 2011

Нашли причину моих проблем:

Кажется, я забыл установить soTimeout и connectionTimeout. документация четко гласит:
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>

Вуаля! Все работает как шарм! Спасибо скаффман, ты указал мне правильное направление!

0 голосов
/ 10 января 2011

Вам все еще нужно закрыть свои соединения, менеджер соединений не сделает этого за вас. Менеджер отвечает только за пул соединений, он не видит, когда вы закончили их использовать.

Если вы не закроете их, диспетчер соединений все еще думает, что вы их используете, и он быстро закончится.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...