完成springboot-resttemplate升级重构
This commit is contained in:
parent
623125ba64
commit
a3cc973e42
@ -25,6 +25,17 @@
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- @ConfigurationProperties annotation processing (metadata for IDEs)
|
||||
生成spring-configuration-metadata.json类,需要引入此类-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
|
@ -0,0 +1,153 @@
|
||||
package com.xncoding.pos.config;
|
||||
|
||||
import com.xncoding.pos.config.properties.HttpClientProperties;
|
||||
import org.apache.http.HeaderElement;
|
||||
import org.apache.http.HeaderElementIterator;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.config.Registry;
|
||||
import org.apache.http.config.RegistryBuilder;
|
||||
import org.apache.http.conn.ConnectionKeepAliveStrategy;
|
||||
import org.apache.http.conn.socket.ConnectionSocketFactory;
|
||||
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.TrustStrategy;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.apache.http.message.BasicHeaderElementIterator;
|
||||
import org.apache.http.protocol.HTTP;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
import org.apache.http.ssl.SSLContextBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* - Supports both HTTP and HTTPS
|
||||
* - Uses a connection pool to re-use connections and save overhead of creating connections.
|
||||
* - Has a custom connection keep-alive strategy (to apply a default keep-alive if one isn't specified)
|
||||
* - Starts an idle connection monitor to continuously clean up stale connections.
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/7/5
|
||||
*/
|
||||
@Configuration
|
||||
@EnableScheduling
|
||||
public class HttpClientConfig {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientConfig.class);
|
||||
|
||||
@Resource
|
||||
private HttpClientProperties p;
|
||||
|
||||
@Bean
|
||||
public PoolingHttpClientConnectionManager poolingConnectionManager() {
|
||||
SSLContextBuilder builder = new SSLContextBuilder();
|
||||
try {
|
||||
builder.loadTrustMaterial(null, new TrustStrategy() {
|
||||
public boolean isTrusted(X509Certificate[] arg0, String arg1) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
} catch (NoSuchAlgorithmException | KeyStoreException e) {
|
||||
LOGGER.error("Pooling Connection Manager Initialisation failure because of " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
SSLConnectionSocketFactory sslsf = null;
|
||||
try {
|
||||
sslsf = new SSLConnectionSocketFactory(builder.build());
|
||||
} catch (KeyManagementException | NoSuchAlgorithmException e) {
|
||||
LOGGER.error("Pooling Connection Manager Initialisation failure because of " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
|
||||
.<ConnectionSocketFactory>create()
|
||||
.register("https", sslsf)
|
||||
.register("http", new PlainConnectionSocketFactory())
|
||||
.build();
|
||||
|
||||
PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
|
||||
poolingConnectionManager.setMaxTotal(p.getMaxTotalConnections()); //最大连接数
|
||||
poolingConnectionManager.setDefaultMaxPerRoute(p.getDefaultMaxPerRoute()); //同路由并发数
|
||||
return poolingConnectionManager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConnectionKeepAliveStrategy connectionKeepAliveStrategy() {
|
||||
return new ConnectionKeepAliveStrategy() {
|
||||
@Override
|
||||
public long getKeepAliveDuration(HttpResponse response, HttpContext httpContext) {
|
||||
HeaderElementIterator it = new BasicHeaderElementIterator
|
||||
(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
|
||||
while (it.hasNext()) {
|
||||
HeaderElement he = it.nextElement();
|
||||
String param = he.getName();
|
||||
String value = he.getValue();
|
||||
if (value != null && param.equalsIgnoreCase("timeout")) {
|
||||
return Long.parseLong(value) * 1000;
|
||||
}
|
||||
}
|
||||
return p.getDefaultKeepAliveTimeMillis();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CloseableHttpClient httpClient() {
|
||||
RequestConfig requestConfig = RequestConfig.custom()
|
||||
.setConnectionRequestTimeout(p.getRequestTimeout())
|
||||
.setConnectTimeout(p.getConnectTimeout())
|
||||
.setSocketTimeout(p.getSocketTimeout()).build();
|
||||
|
||||
return HttpClients.custom()
|
||||
.setDefaultRequestConfig(requestConfig)
|
||||
.setConnectionManager(poolingConnectionManager())
|
||||
.setKeepAliveStrategy(connectionKeepAliveStrategy())
|
||||
.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)) // 重试次数
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Runnable idleConnectionMonitor(final PoolingHttpClientConnectionManager connectionManager) {
|
||||
return new Runnable() {
|
||||
@Override
|
||||
@Scheduled(fixedDelay = 10000)
|
||||
public void run() {
|
||||
try {
|
||||
if (connectionManager != null) {
|
||||
LOGGER.trace("run IdleConnectionMonitor - Closing expired and idle connections...");
|
||||
connectionManager.closeExpiredConnections();
|
||||
connectionManager.closeIdleConnections(p.getCloseIdleConnectionWaitTimeSecs(), TimeUnit.SECONDS);
|
||||
} else {
|
||||
LOGGER.trace("run IdleConnectionMonitor - Http Client Connection manager is not initialised");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("run IdleConnectionMonitor - Exception occurred. msg={}, e={}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TaskScheduler taskScheduler() {
|
||||
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||
scheduler.setThreadNamePrefix("poolScheduler");
|
||||
scheduler.setPoolSize(50);
|
||||
return scheduler;
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
package com.xncoding.pos.config;
|
||||
|
||||
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.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.conn.ssl.TrustStrategy;
|
||||
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.apache.http.ssl.SSLContextBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* RestTemplate客户端连接池配置
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/1/24
|
||||
*/
|
||||
@Configuration
|
||||
public class RestClientConfig {
|
||||
|
||||
private Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
restTemplate.setRequestFactory(clientHttpRequestFactory());
|
||||
restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {
|
||||
try {
|
||||
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
|
||||
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
|
||||
public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
|
||||
return true;
|
||||
}
|
||||
}).build();
|
||||
httpClientBuilder.setSSLContext(sslContext);
|
||||
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
|
||||
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
|
||||
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
|
||||
.register("http", PlainConnectionSocketFactory.getSocketFactory())
|
||||
.register("https", sslConnectionSocketFactory).build();// 注册http和https请求
|
||||
// 开始设置连接池
|
||||
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
|
||||
poolingHttpClientConnectionManager.setMaxTotal(500); // 最大连接数500
|
||||
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100); // 同路由并发数100
|
||||
httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
|
||||
httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)); // 重试次数
|
||||
HttpClient httpClient = httpClientBuilder.build();
|
||||
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); // httpClient连接配置
|
||||
clientHttpRequestFactory.setConnectTimeout(20000); // 连接超时
|
||||
clientHttpRequestFactory.setReadTimeout(30000); // 数据读取超时时间
|
||||
clientHttpRequestFactory.setConnectionRequestTimeout(20000); // 连接不够用的等待时间
|
||||
return clientHttpRequestFactory;
|
||||
} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
|
||||
log.error("初始化HTTP连接池出错", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package com.xncoding.pos.config;
|
||||
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* RestTemplate客户端连接池配置
|
||||
*
|
||||
* @author XiongNeng
|
||||
* @version 1.0
|
||||
* @since 2018/1/24
|
||||
*/
|
||||
@Configuration
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = true)
|
||||
public class RestTemplateConfig {
|
||||
|
||||
@Resource
|
||||
private CloseableHttpClient httpClient;
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate(MappingJackson2HttpMessageConverter jackson2HttpMessageConverter) {
|
||||
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory());
|
||||
|
||||
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
|
||||
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(Charset.forName("utf-8"));
|
||||
messageConverters.add(stringHttpMessageConverter);
|
||||
messageConverters.add(jackson2HttpMessageConverter);
|
||||
restTemplate.setMessageConverters(messageConverters);
|
||||
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {
|
||||
HttpComponentsClientHttpRequestFactory rf = new HttpComponentsClientHttpRequestFactory();
|
||||
rf.setHttpClient(httpClient);
|
||||
return rf;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
package com.xncoding.pos.config.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* HttpClient连接池配置
|
||||
*
|
||||
* @author xiongneng
|
||||
* @since 2018/7/09 22:31
|
||||
*/
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "httpclient")
|
||||
public class HttpClientProperties {
|
||||
/**
|
||||
* 建立连接的超时时间
|
||||
*/
|
||||
private int connectTimeout = 20000;
|
||||
/**
|
||||
* 连接不够用的等待时间
|
||||
*/
|
||||
private int requestTimeout = 20000;
|
||||
/**
|
||||
* 每次请求等待返回的超时时间
|
||||
*/
|
||||
private int socketTimeout = 30000;
|
||||
/**
|
||||
* 每个主机最大连接数
|
||||
*/
|
||||
private int defaultMaxPerRoute = 100;
|
||||
/**
|
||||
* 最大连接数
|
||||
*/
|
||||
private int maxTotalConnections = 300;
|
||||
/**
|
||||
* 默认连接保持活跃的时间
|
||||
*/
|
||||
private int defaultKeepAliveTimeMillis = 20000;
|
||||
/**
|
||||
* 空闲连接生的存时间
|
||||
*/
|
||||
private int closeIdleConnectionWaitTimeSecs = 30;
|
||||
|
||||
public int getConnectTimeout() {
|
||||
return connectTimeout;
|
||||
}
|
||||
|
||||
public void setConnectTimeout(int connectTimeout) {
|
||||
this.connectTimeout = connectTimeout;
|
||||
}
|
||||
|
||||
public int getRequestTimeout() {
|
||||
return requestTimeout;
|
||||
}
|
||||
|
||||
public void setRequestTimeout(int requestTimeout) {
|
||||
this.requestTimeout = requestTimeout;
|
||||
}
|
||||
|
||||
public int getSocketTimeout() {
|
||||
return socketTimeout;
|
||||
}
|
||||
|
||||
public void setSocketTimeout(int socketTimeout) {
|
||||
this.socketTimeout = socketTimeout;
|
||||
}
|
||||
|
||||
public int getDefaultMaxPerRoute() {
|
||||
return defaultMaxPerRoute;
|
||||
}
|
||||
|
||||
public void setDefaultMaxPerRoute(int defaultMaxPerRoute) {
|
||||
this.defaultMaxPerRoute = defaultMaxPerRoute;
|
||||
}
|
||||
|
||||
public int getMaxTotalConnections() {
|
||||
return maxTotalConnections;
|
||||
}
|
||||
|
||||
public void setMaxTotalConnections(int maxTotalConnections) {
|
||||
this.maxTotalConnections = maxTotalConnections;
|
||||
}
|
||||
|
||||
public int getDefaultKeepAliveTimeMillis() {
|
||||
return defaultKeepAliveTimeMillis;
|
||||
}
|
||||
|
||||
public void setDefaultKeepAliveTimeMillis(int defaultKeepAliveTimeMillis) {
|
||||
this.defaultKeepAliveTimeMillis = defaultKeepAliveTimeMillis;
|
||||
}
|
||||
|
||||
public int getCloseIdleConnectionWaitTimeSecs() {
|
||||
return closeIdleConnectionWaitTimeSecs;
|
||||
}
|
||||
|
||||
public void setCloseIdleConnectionWaitTimeSecs(int closeIdleConnectionWaitTimeSecs) {
|
||||
this.closeIdleConnectionWaitTimeSecs = closeIdleConnectionWaitTimeSecs;
|
||||
}
|
||||
}
|
@ -22,25 +22,18 @@ logging:
|
||||
spring:
|
||||
profiles: dev
|
||||
|
||||
logging:
|
||||
level:
|
||||
ROOT: INFO
|
||||
com:
|
||||
xncoding: DEBUG
|
||||
file: E:/logs/app.log
|
||||
|
||||
---
|
||||
|
||||
#####################################################################
|
||||
######################## 测试环境profile ##########################
|
||||
#####################################################################
|
||||
|
||||
spring:
|
||||
profiles: test
|
||||
httpclient:
|
||||
connectTimeout: 20000
|
||||
requestTimeout: 20000
|
||||
socketTimeout: 30000
|
||||
defaultMaxPerRoute: 100
|
||||
maxTotalConnections: 300
|
||||
defaultKeepAliveTimeMillis: 20000
|
||||
closeIdleConnectionWaitTimeSecs: 30
|
||||
|
||||
logging:
|
||||
level:
|
||||
ROOT: INFO
|
||||
com:
|
||||
xncoding: DEBUG
|
||||
file: /var/logs/app.log
|
||||
file: D:/logs/app.log
|
||||
|
@ -39,7 +39,6 @@ public class ApplicationTests {
|
||||
|
||||
@Test
|
||||
public void testRestTemplate() {
|
||||
logger.info("解绑成功后推送消息给对应的POS机");
|
||||
LoginParam param = new LoginParam();
|
||||
param.setUsername("admin");
|
||||
param.setPassword("12345678");
|
||||
@ -47,7 +46,6 @@ public class ApplicationTests {
|
||||
BaseResponse r = restTemplate.postForObject(loginUrl, param, BaseResponse.class);
|
||||
assertThat(r.isSuccess(), is(true));
|
||||
|
||||
logger.info("推送消息登录认证成功");
|
||||
String token = (String) r.getData();
|
||||
UnbindParam unbindParam = new UnbindParam();
|
||||
unbindParam.setImei("imei");
|
||||
|
Loading…
Reference in New Issue
Block a user