面试题答案
一键面试连接池管理原理
在高并发场景下,频繁创建和销毁HTTP连接开销巨大。连接池管理通过预先创建一定数量的连接,并将这些连接复用给不同的请求,从而减少连接创建和销毁的开销,提升性能。当请求到来时,从连接池中获取可用连接,请求完成后将连接归还连接池,而非直接关闭。
连接池配置代码示例(以Java为例)
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
public class HttpClientPoolExample {
private static CloseableHttpClient httpClient;
static {
try {
// 创建SSL上下文,信任所有证书(仅适用于测试环境,生产环境应使用正规证书)
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
}, new SecureRandom());
// 创建连接套接字工厂
ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
// 注册协议
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", plainsf)
.register("https", sslsf)
.build();
// 创建连接池管理器
HttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
// 设置最大连接数
cm.setMaxTotal(100);
// 设置每个路由的最大连接数
cm.setDefaultMaxPerRoute(20);
// 创建请求配置
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000) // 连接超时时间
.setSocketTimeout(5000) // 读取超时时间
.build();
// 创建HttpClient
httpClient = HttpClients.custom()
.setConnectionManager(cm)
.setDefaultRequestConfig(requestConfig)
.build();
} catch (Exception e) {
e.printStackTrace();
}
}
public static CloseableHttpClient getHttpClient() {
return httpClient;
}
}
异常处理
- 连接超时:连接超时通常意味着在规定时间内未能与目标服务器建立连接。在上述代码中,通过
RequestConfig
的setConnectTimeout
方法设置连接超时时间(示例中为5000毫秒)。当发生连接超时时,HttpClient
会抛出ConnectTimeoutException
。可以通过捕获该异常进行相应处理,例如记录日志、重试请求等。
try {
// 使用HttpClient发送请求
HttpResponse response = httpClient.execute(new HttpGet("http://example.com"));
// 处理响应
} catch (ConnectTimeoutException e) {
// 连接超时处理
System.err.println("连接超时: " + e.getMessage());
// 可添加重试逻辑
} catch (IOException e) {
// 其他I/O异常处理
e.printStackTrace();
}
- 读取超时:读取超时表示在规定时间内未能从服务器读取到数据。同样在上述代码中,通过
RequestConfig
的setSocketTimeout
方法设置读取超时时间(示例中为5000毫秒)。当发生读取超时时,HttpClient
会抛出SocketTimeoutException
。捕获该异常后,也可以进行类似的日志记录、重试等操作。
try {
// 使用HttpClient发送请求
HttpResponse response = httpClient.execute(new HttpGet("http://example.com"));
// 处理响应
} catch (SocketTimeoutException e) {
// 读取超时处理
System.err.println("读取超时: " + e.getMessage());
// 可添加重试逻辑
} catch (IOException e) {
// 其他I/O异常处理
e.printStackTrace();
}