Java Spring RestTemplate readtimeout属性工作不正常-奇怪的问题
我想使用2个服务,并希望有不同的超时。因此,我重写了Spring的Java Spring RestTemplate readtimeout属性工作不正常-奇怪的问题,java,spring,sockets,weblogic,resttemplate,Java,Spring,Sockets,Weblogic,Resttemplate,我想使用2个服务,并希望有不同的超时。因此,我重写了Spring的SimpleClientHttpRequestFactory,并从我的HttpDaoImpl中使用它 现在,所有东西都在一个环境中工作,但完全相同的EAR在另一个环境中不工作,两个环境中唯一的区别是,我连接的服务URL在一个环境中是负载平衡URL,在另一个环境中是非LB URL。问题出现在负载平衡服务URL中 问题是每次httpReadTimeout生效或正在使用,但不是XYZHttpReadTimeout,即使我有条件地设置超时
SimpleClientHttpRequestFactory
,并从我的HttpDaoImpl
中使用它
现在,所有东西都在一个环境中工作,但完全相同的EAR在另一个环境中不工作,两个环境中唯一的区别是,我连接的服务URL在一个环境中是负载平衡URL,在另一个环境中是非LB URL。问题出现在负载平衡服务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;
}
}
CustomClientHttpRequestFactory httpRequestFactory = (CustomClientHttpRequestFactory) myAppUtils.getApplicationContext().getBean("httpRequestFactory");
httpRequestFactory.setTimeoutProperties(lUri);
restTemplate.setRequestFactory(httpRequestFactory);
responseString = restTemplate.postForObject(lUri, requestString, String.class);
<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>
HttpDaoImpl:
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;
}
}
CustomClientHttpRequestFactory httpRequestFactory = (CustomClientHttpRequestFactory) myAppUtils.getApplicationContext().getBean("httpRequestFactory");
httpRequestFactory.setTimeoutProperties(lUri);
restTemplate.setRequestFactory(httpRequestFactory);
responseString = restTemplate.postForObject(lUri, requestString, String.class);
<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>
XML配置:
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;
}
}
CustomClientHttpRequestFactory httpRequestFactory = (CustomClientHttpRequestFactory) myAppUtils.getApplicationContext().getBean("httpRequestFactory");
httpRequestFactory.setTimeoutProperties(lUri);
restTemplate.setRequestFactory(httpRequestFactory);
responseString = restTemplate.postForObject(lUri, requestString, String.class);
<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>
text/xml;字符集=UTF-8
最后,找到问题并使其正常工作
根本原因:Spring的
RestTemplate
默认使用org.springframework.http.client.SimpleClientHttpRequestFactory
,并且在多线程环境中会出现问题。如果在多线程环境中使用了SimpleClientHttpRequestFactory
,并且根据您的一些规则使用了一组以上的超时值(在本例中,基于URL或我使用的服务的不同超时),则会出现此问题
A也一样
这是有道理的,因为我在问题中提到的两个环境的另一个区别是,一个环境(一切正常)总是有一个用户,这意味着只有一个线程,而另一个环境(我有问题)有许多并发用户,这意味着多个线程
解决方案:使用
org.springframework.http.client.commonclienthtprequestfactory
,这是Spring 3.0.6版中提供的org.springframework.http.clienthtprequestfactory
的另一个实现,在多线程环境中运行良好
如果Spring版本为3.0+,则使用
HttpComponents客户端HttpRequestFactory
即使我使用的是HttpComponents客户端HttpRequestFactory,这种情况也会发生在我身上。发生在一个环境中,但不发生在另一个环境中。我有两个restTemplates,每个都配置了自己的超时时间,1分钟,另一个3分钟。我看到的是,每件事的超时时间都是1分钟。我没有尝试httpcomponents客户端httprequestfactory
,但我知道它可以与org.springframework.http.client.commonclienthtprequestfactory一起工作。不管怎样,我找到了问题的原因。它实际上是前端上的一个apachehttpd服务器,超时设置为1分钟。谢谢@hagrawal@hagrawal谢谢你提供的有用信息。只有一个问题,我是否可以使用一个RestTemplate并像您描述的那样更改每个请求的超时时间,它是否是线程安全的?因为目前我有多个RestTemplate,比如一个读取超时为1000ms的RestTemplate,另一个为3000ms。。所以每次他们需要一个新的超时值时,我都会创建一个新的RestTemplate,我认为我当前的设计很糟糕。请参阅我上一个发布的问题。非常感谢您的帮助。@prettyvoid很抱歉没有及时回复。我认为您可以使用singleton RestTemplate,为每个请求创建单独的“CommonClientHttPrequestFactory”,并在其上设置特定于请求的超时。