【问题标题】:Spring RestTemplate readtimeout property not working properly - strange issueSpring RestTemplate readtimeout 属性无法正常工作 - 奇怪的问题
【发布时间】:2015-12-26 05:27:18
【问题描述】:

我想使用 2 个服务并希望有不同的超时时间。所以,我已经覆盖了 Spring 的 SimpleClientHttpRequestFactory 并从我的 HttpDaoImpl 中使用它。

现在一切都在一个环境中工作,但完全相同的 EAR 在其他环境中不起作用,两种环境的唯一区别是我连接的服务 URL 在一个环境中是负载平衡 URL,而在另一个环境中是非 LB。问题在于负载平衡的服务 URL。

问题是每次httpReadTimeout 生效或被使用但不是XYZHttpReadTimeout,即使我有条件地设置超时。

这是一个非常奇怪的问题,因为一切都在一个环境中工作。而不是在其他。到目前为止,我对可能的根本原因的猜测是负载平衡 URL,但我仍然看不到任何技术原因说明负载平衡 URL 可能出现问题,因为我的机器将打开一个套接字并在读取超时后关闭它。

我已将记录器放在CustomClientHttpRequestFactory 中,并验证使用了正确的值,但最终以某种方式读取超时未按预期工作。

CustomClientHttpRequestFactory.java

public class CustomClientHttpRequestFactory extends SimpleClientHttpRequestFactory{

    private Log logger = LogFactory.getLog(CustomClientHttpRequestFactory.class);

    @Value("${httpRequest.readTimeoutInMilliseconds}")
    private Integer httpRequestTimeout;

    @Value("${httpRequest.connectionTimeoutInMilliseconds}")
    private Integer httpReadTimeout;

    @Value("${XYZ.httpRequest.readTimeoutInMilliseconds}")
    private Integer XYZHttpRequestTimeout;

    @Value("${XYZ.httpRequest.connectionTimeoutInMilliseconds}")
    private Integer XYZHttpReadTimeout;

    @Value("${sgw.XYZHttp.service.url}")
    private String XYZSystemUrl;


    /**
     * Overriding the default and setting a separate read timeout and HTTP connection timeout values for XYZ transactions.
     * 
     * @param uri
     */
    public void setTimeoutProperties(URI uri){
        boolean isXYZTransaction = isXYZTransaction(uri);
        Integer connectionTimeout = isXYZTransaction ? XYZHttpRequestTimeout : httpRequestTimeout;
        Integer readTimeout = isXYZTransaction ? XYZHttpReadTimeout : httpReadTimeout;
        logger.info("Setting " + connectionTimeout + " : " + readTimeout);
        this.setReadTimeout(readTimeout);
        this.setConnectTimeout(connectionTimeout);
    }

    private boolean isXYZTransaction(URI uri){
        try {
            URI XYZUrl = new URI(XYZSystemUrl);
            logger.info("################################### XYZ Debug");
            logger.info("XYZHttpRequestTimeout = " + XYZHttpRequestTimeout);
            logger.info("XYZHttpReadTimeout = " + XYZHttpReadTimeout);
            return XYZUrl.equals(uri);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return false;
    }
}

HttpDaoImpl

    CustomClientHttpRequestFactory httpRequestFactory = (CustomClientHttpRequestFactory) myAppUtils.getApplicationContext().getBean("httpRequestFactory");
    httpRequestFactory.setTimeoutProperties(lUri);
    restTemplate.setRequestFactory(httpRequestFactory);
    responseString = restTemplate.postForObject(lUri, requestString, String.class);

XML 配置

<bean id="httpRequestFactory" class="com.abc.xyz.customComponents.CustomClientHttpRequestFactory" scope="prototype"/>

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name = "supportedMediaTypes">
                    <list>
                        <value>text/xml;charset=UTF-8</value>
                    </list>
                </property>
            </bean>
        </list>
    </property>
</bean>

【问题讨论】:

    标签: java spring sockets weblogic resttemplate


    【解决方案1】:

    终于,找到了问题并解决了问题。

    根本原因:
    Spring 的RestTemplate 默认使用org.springframework.http.client.SimpleClientHttpRequestFactory,在多线程环境下会出现问题。如果在多线程环境中使用SimpleClientHttpRequestFactory 并且根据您的某些规则使用了一组以上的超时值(在我们的情况下,基于我正在使用的 URL 或服务的不同超时),这将产生问题。

    blog 突出显示相同。

    这是有道理的,因为我在问题中谈到的两个环境的另一个区别是一个环境(一切都很好)总是有一个用户,这意味着只有一个线程,而另一个环境(我有问题)有很多并发用户这意味着多个线程。

    解决方案:
    使用org.springframework.http.client.CommonsClientHttpRequestFactory,这是Spring 3.0.6 版本中org.springframework.http.client.ClientHttpRequestFactory 的另一种实现,在多线程环境中运行良好。

    如果 Spring 版本是 3.0+,则使用 HttpComponentsClientHttpRequestFactory

    【讨论】:

    • 这发生在我身上,即使我使用的是 HttpComponentsClientHttpRequestFactory。发生在一种环境中,但不在另一种环境中。我有两个restTemplates,每个都配置了自己的超时时间,1分钟,另一个3分钟。我看到的是所有的超时时间都是 1 分钟。
    • 我没有尝试HttpComponentsClientHttpRequestFactory,但我知道它适用于org.springframework.http.client.CommonsClientHttpRequestFactory
    • 没关系,我找到了问题的原因。它实际上是前端的 apache httpd 服务器,其超时设置为 1 分钟。谢谢@hagrawal。
    • @hagrawal 感谢您提供有用的信息。只有一个问题,我可以拥有一个 RestTemplate 并像您描述的那样更改每个请求的超时时间,它会是线程安全的吗?因为目前我有多个 RestTemplate,比如一个 RestTemplate 的 readTimeout 为 1000 毫秒,另一个为 3000 毫秒。所以每次他们需要一个新的 timeOut 值时,我都会创建一个新的 RestTemplate,我认为我目前的设计很糟糕。请参阅我上次发布的问题。非常感谢一些帮助。
    • @prettyvoid 抱歉回复晚了。我认为您可以使用单例 RestTemplate 并为每个请求创建单独的“CommonsClientHttpRequestFactory”并设置请求特定的超时时间。
    猜你喜欢
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    • 2013-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-15
    相关资源
    最近更新 更多