HttpClient的作用:
现在的互联网大型项目采用的都是分布式部署,各个模块都有各个模块的服务器,这些资源之间的相互访问就需要借助http协议,HttpClient就是用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包.
首先导包
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
HttpClient的使用步骤
public void testGet() throws ClientProtocolException, IOException {
String url = "https://www.baidu.com"; //1..确定要访问的url地址,这里访问百度
HttpGet get = new HttpGet(url); //2..确定访问方式get/post
HttpClient htClient = HttpClients.createDefault(); //3..实例化一个HttpClient对象
HttpResponse response = htClient.execute(get); //4..发起请求,获取响应
if(200 == response.getStatusLine().getStatusCode()) { //5..判断返回状态信息
String result = EntityUtils.toString(response.getEntity(),"utf-8");
System.out.println(result); //6..对返回信息做出处理
}
}
SpringBoot整合HttpClient
package com.jt.config;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource(value="classpath:/properties/httpClient.properties")
public class HttpClientConfig {
@Value("${http.maxTotal}")
private Integer maxTotal; //最大连接数
@Value("${http.defaultMaxPerRoute}")
private Integer defaultMaxPerRoute; //最大并发链接数
@Value("${http.connectTimeout}")
private Integer connectTimeout; //创建链接的最大时间
@Value("${http.connectionRequestTimeout}")
private Integer connectionRequestTimeout; //链接获取超时时间
@Value("${http.socketTimeout}")
private Integer socketTimeout; //数据传输最长时间
@Value("${http.staleConnectionCheckEnabled}")
private boolean staleConnectionCheckEnabled; //提交时检查链接是否可用
//定义httpClient链接池
@Bean(name="httpClientConnectionManager")
public PoolingHttpClientConnectionManager getPoolingHttpClientConnectionManager() {
PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager();
manager.setMaxTotal(maxTotal); //设定最大链接数
manager.setDefaultMaxPerRoute(defaultMaxPerRoute); //设定并发链接数
return manager;
}
//定义HttpClient
/**
* 实例化连接池,设置连接池管理器。
* 这里需要以参数形式注入上面实例化的连接池管理器
@Qualifier 指定bean标签进行注入
*/
@Bean(name = "httpClientBuilder")
public HttpClientBuilder getHttpClientBuilder(@Qualifier("httpClientConnectionManager")PoolingHttpClientConnectionManager httpClientConnectionManager){
//HttpClientBuilder中的构造方法被protected修饰,所以这里不能直接使用new来实例化一个HttpClientBuilder,可以使用HttpClientBuilder提供的静态方法create()来获取HttpClientBuilder对象
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
httpClientBuilder.setConnectionManager(httpClientConnectionManager);
return httpClientBuilder;
}
/**
* 注入连接池,用于获取httpClient
* @param httpClientBuilder
* @return
*/
@Bean
public CloseableHttpClient getCloseableHttpClient(@Qualifier("httpClientBuilder") HttpClientBuilder httpClientBuilder){
return httpClientBuilder.build();
}
/**
* Builder是RequestConfig的一个内部类
* 通过RequestConfig的custom方法来获取到一个Builder对象
* 设置builder的连接信息
* @return
*/
@SuppressWarnings("deprecation")
@Bean(name = "builder")
public RequestConfig.Builder getBuilder(){
RequestConfig.Builder builder = RequestConfig.custom();
return builder.setConnectTimeout(connectTimeout)
.setConnectionRequestTimeout(connectionRequestTimeout)
.setSocketTimeout(socketTimeout)
.setStaleConnectionCheckEnabled(staleConnectionCheckEnabled);
}
/**
* 使用builder构建一个RequestConfig对象
* @param builder
* @return
*/
@Bean
public RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder){
return builder.build();
}
}
配置文件
#最大连接数
http.maxTotal = 1000
#并发数
http.defaultMaxPerRoute = 20
#创建连接的最长时间
http.connectTimeout=5000
#从连接池中获取到连接的最长时间
http.connectionRequestTimeout=500
#数据传输的最长时间
http.socketTimeout=5000
#提交请求前测试连接是否可用
http.staleConnectionCheckEnabled=true
自动清理不被使用的连接
package com.jt.config;
import javax.annotation.PreDestroy;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.pool.PoolStats;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component //交给spring容器管理
public class HttpClientClose extends Thread{
@Autowired
private PoolingHttpClientConnectionManager manage;
private volatile boolean shutdown; //开关 volatitle表示多线程可变数据,一个线程修改,其他线程立即修改
public HttpClientClose() {
///System.out.println("执行构造方法,实例化对象");
//线程开启启动
this.start();
}
@Override
public void run() {
try {
//如果服务没有关闭,执行线程
while(!shutdown) {
synchronized (this) {
wait(5000); //等待5秒
//System.out.println("线程开始执行,关闭超时链接");
//关闭超时的链接
PoolStats stats = manage.getTotalStats();
int av = stats.getAvailable(); //获取可用的线程数量
int pend = stats.getPending(); //获取阻塞的线程数量
int lea = stats.getLeased(); //获取当前正在使用的链接数量
int max = stats.getMax();
//System.out.println("max/"+max+": av/"+av+": pend/"+pend+": lea/"+lea);
manage.closeExpiredConnections();
}
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
super.run();
}
//关闭清理无效连接的线程
@PreDestroy //容器关闭时执行该方法.
public void shutdown() {
shutdown = true;
synchronized (this) {
notifyAll(); //全部从等待中唤醒.执行关闭操作;
}
}
}
这个时候,再写一个util工具类,简化拿取HttpClient 的过程.
package com.jt.util;
import java.io.IOException;
import java.util.Map;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.jt.Util.ObjectMapperUtil;
@Configuration
public class HttpClientService {
@Autowired
private CloseableHttpClient htClient;//从池中获取连接
@Autowired
private RequestConfig requestConfig; //控制请求超时时间
public String Client(String url,Map<String,String> params,String Charset) {
if(StringUtils.isEmpty(Charset)) {
Charset="UTF-8";
}
if(params!=null) {
url +="?";
for (Map.Entry<String, String> entry : params.entrySet()) {
String key=entry.getKey();
String value=entry.getValue();
url +=key+"="+value+"&";
}
url=url.substring(0, url.length()-1);
}
//3..定义请求的类型
HttpGet get = new HttpGet(url);
get.setConfig(requestConfig);
//4..发起请求获取结果
String result=null;
try {
HttpResponse response = htClient.execute(get);
if(200 == response.getStatusLine().getStatusCode()) {
result= EntityUtils.toString
(response.getEntity(),Charset);
}
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return result;
}
public String Client(String url) {
return Client(url,null,null);
}
public String Client(String url,String Charset) {
return Client(url,null,Charset);
}
public String Client(String url,Map<String, String>params) {
return Client(url,params,null);
}
public <T> T Client(String url,Map<String,String> params,Class<T> targetClass,String charset) {
String result = Client(url,params);
return ObjectMapperUtil.getObject(result, targetClass);
}
public <T> T Client(String url,Class<T> targetClass) {
String result = Client(url);
return ObjectMapperUtil.getObject(result, targetClass);
}
}
最后,测试一下
@Autowired
private HttpClientService Client;
@Test
public void test03() {
String url = "http://www.baidu.com";
String result = Client.Client(url);
System.out.println(result);
}
完美.