Skip to content

Commit a646f87

Browse files
committed
http client
1 parent f182c10 commit a646f87

File tree

13 files changed

+829
-2
lines changed

13 files changed

+829
-2
lines changed

src/main/java/code/distribution/transcation/common/BranchStatus.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*/
1010
public enum BranchStatus {
1111

12-
REGISTERD,
12+
REGISTERED,
1313

1414
PHASE1_DONE,
1515

src/main/java/code/distribution/transcation/tc/DefaultTransactionCoordinator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ public boolean registerBranch(String xid, String resourceId, LockKey lockKey, Re
123123
}
124124

125125
BranchSession branchSession = new BranchSession(rm, xid, resourceId, lockKey);
126-
branchSession.setBranchStatus(BranchStatus.REGISTERD);
126+
branchSession.setBranchStatus(BranchStatus.REGISTERED);
127127

128128
if(!branchSession.lock()){
129129
return false;
Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
package code.http;
2+
3+
import org.apache.http.config.RegistryBuilder;
4+
import org.apache.http.conn.socket.ConnectionSocketFactory;
5+
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
6+
import org.apache.http.conn.ssl.NoopHostnameVerifier;
7+
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
8+
import org.apache.http.conn.ssl.TrustAllStrategy;
9+
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
10+
import org.apache.http.impl.client.CloseableHttpClient;
11+
import org.apache.http.impl.client.HttpClients;
12+
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
13+
import org.apache.http.ssl.PrivateKeyDetails;
14+
import org.apache.http.ssl.PrivateKeyStrategy;
15+
import org.apache.http.ssl.SSLContextBuilder;
16+
import org.apache.http.ssl.SSLContexts;
17+
18+
import javax.net.ssl.HostnameVerifier;
19+
import javax.net.ssl.SSLContext;
20+
import java.io.File;
21+
import java.io.FileInputStream;
22+
import java.io.IOException;
23+
import java.net.Socket;
24+
import java.security.KeyStore;
25+
import java.util.Map;
26+
import java.util.concurrent.TimeUnit;
27+
28+
/**
29+
* 〈HttpClient 构造器〉<p>
30+
* 〈功能详细描述〉
31+
*
32+
* @author zixiao
33+
* @date 2019/5/16
34+
*/
35+
public class HttpClientBuilder {
36+
37+
/**
38+
* 是否开启ssl
39+
*/
40+
private boolean enableSSL = false;
41+
42+
/**
43+
* 是否信任所有证书
44+
* 忽略对服务器端证书合法性校验
45+
*/
46+
private boolean trustAll = false;
47+
48+
/**
49+
* 主机名验证
50+
* 验证目标主机名是否跟服务端存储在X.509认证里的一致
51+
*/
52+
private boolean verifyHostname = true;
53+
54+
/**
55+
* 最大总连接数
56+
*/
57+
private int maxTotal = 1024;
58+
59+
/**
60+
* 单个路由最大连接数
61+
*/
62+
private int defaultMaxPerRoute = 8;
63+
64+
/**
65+
* 最大空闲时间
66+
*/
67+
private int maxIdleTime = 5000;
68+
69+
/**
70+
* keyStore
71+
*/
72+
private KeyStore keyStore;
73+
74+
private String keyPass;
75+
76+
/**
77+
* trustStore
78+
*/
79+
private KeyStore trustStore;
80+
81+
private ConnectionSocketFactory socketFactory;
82+
83+
private ConnectionSocketFactory sslSocketFactory;
84+
85+
public static HttpClientBuilder custom(){
86+
return new HttpClientBuilder();
87+
}
88+
89+
/**
90+
* 开启双向认证的SSL
91+
* 服务端需要认证客户端的证书,一般用于双向认证
92+
* @param keyStorePath
93+
* @param storePass
94+
* @param keyPass
95+
* @return
96+
*/
97+
public HttpClientBuilder ssl2(String keyStorePath, String storePass, String keyPass){
98+
this.enableSSL = true;
99+
this.keyStore = loadKeyStore(keyStorePath, storePass);
100+
this.keyPass = keyPass;
101+
return this;
102+
}
103+
104+
/**
105+
* 开启SSL 指定trustStore
106+
* @param trustStorePath
107+
* @param trustStorePass
108+
* @return
109+
*/
110+
public HttpClientBuilder ssl(String trustStorePath, String trustStorePass){
111+
this.enableSSL = true;
112+
this.trustStore = loadTrustStore(trustStorePath, trustStorePass);
113+
return this;
114+
}
115+
116+
/**
117+
* 开启SSL 使用默认trustStore
118+
*
119+
* @return
120+
*/
121+
public HttpClientBuilder ssl(){
122+
this.enableSSL = true;
123+
return this;
124+
}
125+
126+
/**
127+
* 信任所有证书
128+
* 忽略对服务器端证书合法性校验
129+
*
130+
* @return
131+
*/
132+
public HttpClientBuilder trustAll(){
133+
this.trustAll = true;
134+
return this;
135+
}
136+
137+
/**
138+
* 是否主机名验证
139+
* 当 trustAll=false 时,有效
140+
* @param verifyFlag
141+
* @return
142+
*/
143+
public HttpClientBuilder verifyHostname(boolean verifyFlag){
144+
this.verifyHostname = verifyFlag;
145+
return this;
146+
}
147+
148+
/**
149+
* 连接池化
150+
* @param maxTotal
151+
* @param defaultMaxPerRoute
152+
* @return
153+
*/
154+
public HttpClientBuilder pool(int maxTotal, int defaultMaxPerRoute){
155+
this.maxTotal = maxTotal;
156+
this.defaultMaxPerRoute = defaultMaxPerRoute;
157+
return this;
158+
}
159+
160+
/**
161+
* 连接最大空闲时间,超过会被自动释放
162+
* @param maxIdleTime
163+
* @return
164+
*/
165+
public HttpClientBuilder maxIdleTime(int maxIdleTime){
166+
this.maxIdleTime = maxIdleTime;
167+
return this;
168+
}
169+
170+
private CloseableHttpClient buildClient(){
171+
// 创建 ConnectionSocketFactory
172+
createConnectionSocketFactory();
173+
174+
// 配置支持的协议
175+
RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.<ConnectionSocketFactory> create()
176+
.register("http", socketFactory);
177+
if(enableSSL && sslSocketFactory != null){
178+
registryBuilder.register("https", sslSocketFactory);
179+
}
180+
181+
// 连接池管理类
182+
PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager(registryBuilder.build());
183+
manager.setMaxTotal(maxTotal);
184+
manager.setDefaultMaxPerRoute(defaultMaxPerRoute);
185+
186+
return HttpClients.custom()
187+
.setConnectionManager(manager)
188+
.evictExpiredConnections()
189+
.evictIdleConnections(maxIdleTime, TimeUnit.MILLISECONDS)
190+
.build();
191+
}
192+
193+
/**
194+
* 构造池化的HttpClient
195+
*
196+
* @return
197+
*/
198+
public WrappedHttpClient build(){
199+
return new WrappedHttpClient(buildClient());
200+
}
201+
202+
private void createConnectionSocketFactory(){
203+
//Http
204+
this.socketFactory = PlainConnectionSocketFactory.getSocketFactory();
205+
206+
//Https
207+
if(enableSSL){
208+
SSLContext sslContext = createSSLContext();
209+
210+
HostnameVerifier hostnameVerifier = null;
211+
if(verifyHostname){
212+
//开启主机名验证,https://publicsuffix.org/list
213+
hostnameVerifier = SSLConnectionSocketFactory.getDefaultHostnameVerifier();
214+
}else {
215+
//使用 NoopHostnameVerifier 关闭主机名验证
216+
hostnameVerifier = NoopHostnameVerifier.INSTANCE;
217+
}
218+
219+
this.sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
220+
}
221+
}
222+
223+
224+
/**
225+
* 创建SSL上下文
226+
* @return
227+
*/
228+
private SSLContext createSSLContext(){
229+
SSLContextBuilder sslContextBuilder = SSLContexts.custom();
230+
try {
231+
if(keyStore != null){
232+
// 携带客户端证书
233+
sslContextBuilder.loadKeyMaterial(keyStore, keyPass.toCharArray(), new PrivateKeyStrategy() {
234+
@Override
235+
public String chooseAlias(Map<String, PrivateKeyDetails> aliases, Socket socket) {
236+
aliases.entrySet().forEach(entry -> {
237+
System.out.println(entry.getKey());
238+
});
239+
return "test";
240+
}
241+
});
242+
}
243+
if(trustAll){
244+
// 信任所有证书
245+
sslContextBuilder.loadTrustMaterial(trustStore, TrustAllStrategy.INSTANCE);
246+
}else {
247+
// 信任自己的CA和所有自签名的证书
248+
sslContextBuilder.loadTrustMaterial(trustStore, TrustSelfSignedStrategy.INSTANCE);
249+
}
250+
return sslContextBuilder.build();
251+
} catch (Exception e) {
252+
throw new HttpClientException("创建SSL上下文异常", e);
253+
}
254+
}
255+
256+
/**
257+
* 加载信任证书库
258+
*
259+
* A TrustStore contains only the certificates trusted by the client (a “trust” store).
260+
* These certificates are CA root certificates, that is, self-signed certificates.
261+
*
262+
* @param storePath
263+
* @param storePass
264+
* @return
265+
* @throws HttpClientException
266+
*/
267+
private KeyStore loadTrustStore(String storePath, String storePass) throws HttpClientException {
268+
FileInputStream fis = null;
269+
try {
270+
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
271+
fis = new FileInputStream(new File(storePath));
272+
trustStore.load(fis, storePass.toCharArray());
273+
return trustStore;
274+
} catch (Exception e) {
275+
throw new HttpClientException("加载trustStore失败", e);
276+
} finally{
277+
if(fis != null){
278+
try {
279+
fis.close();
280+
} catch (IOException e) {}
281+
}
282+
}
283+
}
284+
285+
/**
286+
* 加载KeyStore
287+
* 包括私钥,客户端证书,CA证书链
288+
* A KeyStore consists of a database containing a private key and an associated certificate, or an associated certificate chain.
289+
* The certificate chain consists of the client certificate and one or more certification authority (CA) certificates.
290+
*
291+
* @param storePath
292+
* @param storePass
293+
* @return
294+
* @throws HttpClientException
295+
*/
296+
private KeyStore loadKeyStore(String storePath, String storePass) throws HttpClientException {
297+
FileInputStream fis = null;
298+
try {
299+
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
300+
fis = new FileInputStream(new File(storePath));
301+
keyStore.load(fis, storePass.toCharArray());
302+
return keyStore;
303+
} catch (Exception e) {
304+
throw new HttpClientException("加载keyStore失败", e);
305+
} finally{
306+
if(fis != null){
307+
try {
308+
fis.close();
309+
} catch (IOException e) {}
310+
}
311+
}
312+
}
313+
314+
}

0 commit comments

Comments
 (0)