我们做web开发时,需要经常使用httpclient来请求http服务,有时为了安全起见,服务提供方会提供多个http地址,这样如果我们请求某个ip出现异常,可以重试其他的ip地址,来尽量保证系统的稳定,以下是自定义一个HttpMethod重试机制的简要代码。
HostCluster类定义需要连接的协议、ips[]、重试次数、随机获取一个host等:
点击(此处)折叠或打开
- public class HostCluster {
- protected static final String HTTP_PROTOCOL = \"http\";
- protected static final String HTTPS_PROTOCOL = \"https\";
-
- protected String protocol;
- protected String[] ips; //contain ip and port
-
- private int idx;
- private int retry;
-
- private Random random;
-
- public HostCluster(String ipAndPort) {
- this(HTTP_PROTOCOL, ipAndPort);
- }
-
- public HostCluster(String protocol, String ipAndPort) {
- this(protocol, ipAndPort, 0);
- }
-
- public HostCluster(String protocol, String ipAndPort, int retry) {
- if (StringUtils.isEmpty(ipAndPort)) {
- throw new IllegalArgumentException(\"invalid constructor params.\");
- }
- if (retry < 0) {
- throw new IllegalArgumentException(\"invalid retry.\");
- }
- if (!HTTP_PROTOCOL.equals(protocol) && !HTTPS_PROTOCOL.equals(protocol)) {
- throw new IllegalArgumentException(\"invalid protocol.\");
- }
-
- //split the string
- String[] splitStr = StringUtils.split(ipAndPort, \",\");
-
- this.protocol = protocol;
- this.ips = splitStr;
- this.retry = retry;
-
- this.idx = this.ips.length;
- this.random = new Random();
- }
-
- public String randomHost() {
- int index = this.random.nextInt(idx);
- log.info(\"randomIp=\" + ips[index]);
- return this.protocol + \"://\" + ips[index];
- }
-
- public boolean isHttps() {
- return HTTPS_PROTOCOL.equals(protocol);
- }
-
- public String getProtocol() {
- return protocol;
- }
-
- public int getRetry() {
- return retry;
- }
- }
ClusterRetryHttpMethod从HostCluster获取的randomHost,然后new URI()设置相应的base(GetMethod or PostMethod)
点击(此处)折叠或打开
- public abstract class ClusterRetryHttpMethod<T extends HttpMethod> {
- protected HostCluster cluster;
- protected String urlSuffix;
- protected T base;
- private Integer retry;
-
- public ClusterRetryHttpMethod(HostCluster cluster, String urlSuffix) {
- this(cluster, urlSuffix, null);
- }
-
- public ClusterRetryHttpMethod(HostCluster cluster, String urlSuffix, Integer retry) {
- if (cluster == null || StringUtils.isBlank(urlSuffix)) {
- throw new IllegalArgumentException(\"invalid params.\");
- }
- if (retry != null) {
- if (retry < 0) {
- throw new IllegalArgumentException(\"invalid retry.\");
- } else {
- this.retry = retry;
- }
- }
- this.cluster = cluster;
- this.urlSuffix = urlSuffix;
-
- this.base = initBase();
- }
-
- public boolean isHttps() {
- return this.cluster.isHttps();
- }
-
- public void setQueryString(String queryString) {
- this.base.setQueryString(queryString);
- }
-
- public void setQueryString(NameValuePair[] params) {
- this.base.setQueryString(params);
- }
-
- public int getRetry() {
- return retry == null ? this.cluster.getRetry() : retry;
- }
-
- protected abstract T initBase();//子类各自实现,GetMethod or PostMethod
-
- public T randomMethod() throws Exception {
- String url = this.randomUrl();
- if (StringUtils.isBlank(url)) {
- url = \"/\";
- }
-
- this.base.setURI(new URI(url, true));
- return base;
- }
-
- protected String randomUrl() {
- return cluster.randomHost() + urlSuffix;
- }
- }
最后就是怎么调用了,这里使用的是HttpClientPool来调用http连接,关于HttpClientPool详见我的另一篇文章:http://blog.itpub.net/28912557/viewspace-1223241/
点击(此处)折叠或打开
- public class HttpClientPool extends GenericObjectPool<HttpClient> {
-
- private int httpsPort;
-
- public HttpClientPool(PoolableObjectFactory<HttpClient> factory) {
- super(factory);
- }
-
- public <T> T doPost(ClusterRetryHttpMethod method, HttpClientDataCallback<T> callback) {
- HttpClient toUse = null;
- HttpMethod m = null;
- int index = 0;
- if (method == null) {
- return null;
- }
- if (method.isHttps()) {
- Protocol myhttps = new Protocol(\"https\", new SSLProtocolSocketFactoryImpl(), httpsPort);
- Protocol.registerProtocol(\"https\", myhttps);
- }
- try {
- toUse = borrowObject();
- while (index <= method.getRetry()) {
- try {
- m = method.randomMethod();
- toUse.executeMethod(m);
- T rel = callback.handleResponse(m.getResponseBodyAsString());
- return rel;
- } catch (Exception e) {
- logger.error(\"failed to execute http request.\", e);
- index++;
- } finally {
- try {
- m.releaseConnection();
- } catch (Exception e) {
- // in case fail, ignore and return object
- }
- }
- }
- } catch (Exception e) {
- return null;
- } finally {
- if (toUse != null) {
- try {
- returnObject(toUse);
- } catch (Exception e) {
- }
- }
- if (method.isHttps()) {
- try {
- Protocol.unregisterProtocol(\"https\");
- } catch (Exception e) {
- }
- }
- }
- // all retry failed
- return null;
-
- }
-
-
- public int getHttpsPort() {
- return httpsPort;
- }
-
- public void setHttpsPort(int httpsPort) {
- this.httpsPort = httpsPort;
- }
- }
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/28912557/viewspace-1356116/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/28912557/viewspace-1356116/