spring 3.2.0.RELEASE resttemplate および httpcomponents 4.2.3 を使用して、rest 呼び出しを行います。メモリフットプリントは、最大に達するまで着実に増加しています。
構成は次のとおりです。
<bean id="myRestTemplate" class="org.springframework.web.client.RestTemplate">
<constructor-arg>
<bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<constructor-arg index="0">
<bean factory-bean="httpClient" factory-method="get"/>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
<bean id="httpClient" class="com.mycompany.myproject.common.rest.HttpClient">
<constructor-arg index="0" ref="myKeyserverCA" ></constructor-arg>
<constructor-arg index="1" value="${com.mycompany.myproject.security.client.keyPassword}" ></constructor-arg>
<constructor-arg index="2" value="${default.max.total.connections}" ></constructor-arg>
<constructor-arg index="3" value="${default.max.host.connections}" ></constructor-arg>
</bean>
<bean id="myKeyserverCA"
class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="classpath:${com.mycompany.myproject.security.client.keyStore}" />
<property name="password" value="${com.mycompany.myproject.security.client.keyStorePass}" />
</bean>
Http クライアント:
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.params.CoreConnectionPNames;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import java.security.KeyStore;
public class HttpClient {
private static final int DEFAULT_READ_TIMEOUT_MILLISECONDS = (60 * 1000);
private KeyStore keystore;
private String password;
private int MAX_TOTAL_CONNECTION;
private int MAX_PER_ROUTE;
public HttpClient(KeyStore keyStore, String keyPassword, int MAX_TOTAL_CONNECTION, int MAX_PER_ROUTE) {
this.keystore = keyStore;
this.password = keyPassword;
this.MAX_TOTAL_CONNECTION = MAX_TOTAL_CONNECTION;
this.MAX_PER_ROUTE = MAX_PER_ROUTE;
}
public org.apache.http.client.HttpClient get() {
PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager(getSchemeRegistry(this.keystore, this.password));
connectionManager.setMaxTotal(MAX_TOTAL_CONNECTION);
connectionManager.setDefaultMaxPerRoute(MAX_PER_ROUTE);
connectionManager.closeExpiredConnections();
org.apache.http.client.HttpClient httpClient = new DefaultHttpClient(connectionManager);
httpClient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, DEFAULT_READ_TIMEOUT_MILLISECONDS);
return httpClient;
}
private static SchemeRegistry getSchemeRegistry(KeyStore keyStore, String keyPassword) {
SchemeRegistry registry = new SchemeRegistry();
try{
TrustManager[] trustManagerArray = { new TautologicalX509TrustManager() };
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, keyPassword.toCharArray());
SSLContext sslc = SSLContext.getInstance("TLS");
sslc.init(kmf.getKeyManagers(), trustManagerArray, null);
SSLSocketFactory sslSocketFactory = new SSLSocketFactory(sslc, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
registry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
registry.register(new Scheme("https", 443, sslSocketFactory));
return registry;
}catch(Exception e){
throw new RuntimeException(e.getMessage());
}
}
}
TautologicalX509TrustManager:
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
public class TautologicalX509TrustManager implements X509TrustManager {
private static final X509Certificate[] EMPTY_CERTIFICATES = new X509Certificate [0];
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return EMPTY_CERTIFICATES;
}
}
このコンポーネントで負荷テストを実行すると、多数の SSLSocketImpl オブジェクトと byte[] が表示されます。SSLSocketImpl への着信参照は、Finalizer オブジェクトからのものです。
負荷テストの停止後にマシンで netstat を実行すると、基礎となるサービスへの開いている TCP 接続が表示されません。ただし、負荷テスト中は、TIME_WAIT 状態の接続が多く、ESTABLISHED 状態の接続はほとんどありませんが、テストが停止するとすべてが閉じられます。
ソケットを閉じるための API 呼び出しが不足していませんか? ヒープ内に非常に多くの SSLSocketImpl オブジェクトがぶら下がっているのはなぜですか?