diff --git a/sentinel-adapter/pom.xml b/sentinel-adapter/pom.xml
index d7a973f0..127aa8af 100755
--- a/sentinel-adapter/pom.xml
+++ b/sentinel-adapter/pom.xml
@@ -18,6 +18,7 @@
sentinel-web-servlet
sentinel-dubbo-adapter
sentinel-apache-dubbo-adapter
+ sentinel-apache-httpclient-adapter
sentinel-sofa-rpc-adapter
sentinel-grpc-adapter
sentinel-zuul-adapter
diff --git a/sentinel-adapter/sentinel-apache-httpclient-adapter/README.md b/sentinel-adapter/sentinel-apache-httpclient-adapter/README.md
new file mode 100755
index 00000000..3ec548d2
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient-adapter/README.md
@@ -0,0 +1,75 @@
+# Sentinel Apache Httpclient Adapter
+
+## Introduction
+
+Sentinel provides integration for OkHttp client to enable flow control for web requests.
+
+Add the following dependency in `pom.xml` (if you are using Maven):
+
+```xml
+
+ com.alibaba.csp
+ sentinel-apache-httpclient-adapter
+ x.y.z
+
+```
+
+We can use the `SentinelApacheHttpClientBuilder` when `CloseableHttpClient` at initialization, for example:
+
+```java
+CloseableHttpClient httpclient = new SentinelApacheHttpClientBuilder().build();
+```
+
+If we want to add some additional configurations, we can refer to the following code
+
+```java
+HttpClientBuilder builder = new SentinelApacheHttpClientBuilder();
+//builder Other Definitions
+CloseableHttpClient httpclient = builder.build();
+```
+
+## Configuration
+
+- `SentinelApacheHttpClientConfig` configuration:
+
+| name | description | type | default value |
+|------|------------|------|-------|
+| prefix | customize resource prefix | `String` | `httpclient:` |
+| extractor | customize resource extractor | `ApacheHttpClientResourceExtractor` | `DefaultApacheHttpClientResourceExtractor` |
+| fallback | handle request when it is blocked | `ApacheHttpClientFallback` | `DefaultApacheHttpClientFallback` |
+
+### extractor (resource extractor)
+
+We can define `ApacheHttpClientResourceExtractor` to customize resource extractor replace `DefaultApacheHttpClientResourceExtractor` at `SentinelApacheHttpClientBuilder` default config, for example: httpclient:GET:/httpclient/back/1 ==> httpclient:GET:/httpclient/back/{id}
+
+```java
+SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+config.setExtractor(new ApacheHttpClientResourceExtractor() {
+
+ @Override
+ public String extractor(HttpRequestWrapper request) {
+ String contains = "/httpclient/back/";
+ String uri = request.getRequestLine().getUri();
+ if (uri.startsWith(contains)) {
+ uri = uri.substring(0, uri.indexOf(contains) + contains.length()) + "{id}";
+ }
+ return request.getMethod() + ":" + uri;
+ }
+});
+CloseableHttpClient httpclient = new SentinelApacheHttpClientBuilder(config).build();
+```
+
+### fallback (Block handling)
+
+We can define `ApacheHttpClientFallback` at `SentinelApacheHttpClientBuilder` default config, to handle request is blocked according to the actual scenario, for example:
+
+```java
+public class DefaultApacheHttpClientFallback implements ApacheHttpClientFallback {
+
+ @Override
+ public CloseableHttpResponse handle(HttpRequestWrapper request, BlockException e) {
+ // Just wrap and throw the exception.
+ throw new SentinelRpcException(e);
+ }
+}
+```
\ No newline at end of file
diff --git a/sentinel-adapter/sentinel-apache-httpclient-adapter/pom.xml b/sentinel-adapter/sentinel-apache-httpclient-adapter/pom.xml
new file mode 100644
index 00000000..3dde07bf
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient-adapter/pom.xml
@@ -0,0 +1,69 @@
+
+
+
+ sentinel-adapter
+ com.alibaba.csp
+ 1.8.0-SNAPSHOT
+
+ 4.0.0
+
+ sentinel-apache-httpclient-adapter
+ jar
+
+
+ 4.5.6
+ 2.1.3.RELEASE
+ 5.1.5.RELEASE
+
+
+
+
+ com.alibaba.csp
+ sentinel-core
+
+
+ org.apache.httpcomponents
+ httpclient
+ ${apache.httpclient.version}
+ provided
+
+
+
+ junit
+ junit
+ test
+
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+ com.alibaba
+ fastjson
+ test
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${spring.boot.version}
+ test
+
+
+ org.springframework.boot
+ spring-boot-test
+ ${spring.boot.version}
+ test
+
+
+ org.springframework
+ spring-test
+ ${spring-test.version}
+ test
+
+
+
\ No newline at end of file
diff --git a/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/SentinelApacheHttpClientBuilder.java b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/SentinelApacheHttpClientBuilder.java
new file mode 100644
index 00000000..4b6aad37
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/SentinelApacheHttpClientBuilder.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.csp.sentinel.adapter.apache.httpclient;
+
+import com.alibaba.csp.sentinel.*;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.config.SentinelApacheHttpClientConfig;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.util.StringUtil;
+import org.apache.http.HttpException;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpExecutionAware;
+import org.apache.http.client.methods.HttpRequestWrapper;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.execchain.ClientExecChain;
+
+import java.io.IOException;
+
+/**
+ * @author zhaoyuguang
+ */
+public class SentinelApacheHttpClientBuilder extends HttpClientBuilder {
+
+ private final SentinelApacheHttpClientConfig config;
+
+ public SentinelApacheHttpClientBuilder(){
+ this.config = new SentinelApacheHttpClientConfig();
+ }
+
+ public SentinelApacheHttpClientBuilder(SentinelApacheHttpClientConfig config){
+ this.config = config;
+ }
+
+ @Override
+ protected ClientExecChain decorateMainExec(final ClientExecChain mainExec) {
+ return new ClientExecChain() {
+ @Override
+ public CloseableHttpResponse execute(HttpRoute route, HttpRequestWrapper request,
+ HttpClientContext clientContext, HttpExecutionAware execAware)
+ throws IOException, HttpException {
+ Entry entry = null;
+ try {
+ String name = config.getExtractor().extractor(request);
+ if (!StringUtil.isEmpty(config.getPrefix())) {
+ name = config.getPrefix() + name;
+ }
+ entry = SphU.entry(name, ResourceTypeConstants.COMMON_WEB, EntryType.OUT);
+ return mainExec.execute(route, request, clientContext, execAware);
+ } catch (BlockException e) {
+ return config.getFallback().handle(request, e);
+ } catch (Throwable t) {
+ Tracer.traceEntry(t, entry);
+ throw t;
+ } finally {
+ if (entry != null) {
+ entry.exit();
+ }
+ }
+ }
+ };
+ }
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/config/SentinelApacheHttpClientConfig.java b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/config/SentinelApacheHttpClientConfig.java
new file mode 100644
index 00000000..9dbc1520
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/config/SentinelApacheHttpClientConfig.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.csp.sentinel.adapter.apache.httpclient.config;
+
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.extractor.ApacheHttpClientResourceExtractor;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.extractor.DefaultApacheHttpClientResourceExtractor;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.fallback.ApacheHttpClientFallback;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.fallback.DefaultApacheHttpClientFallback;
+import com.alibaba.csp.sentinel.util.AssertUtil;
+
+/**
+ * @author zhaoyuguang
+ */
+public class SentinelApacheHttpClientConfig {
+
+ private String prefix = "httpclient:";
+ private ApacheHttpClientResourceExtractor extractor = new DefaultApacheHttpClientResourceExtractor();
+ private ApacheHttpClientFallback fallback = new DefaultApacheHttpClientFallback();
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public void setPrefix(String prefix) {
+ AssertUtil.notNull(prefix, "prefix cannot be null");
+ this.prefix = prefix;
+ }
+
+ public ApacheHttpClientResourceExtractor getExtractor() {
+ return extractor;
+ }
+
+ public void setExtractor(ApacheHttpClientResourceExtractor extractor) {
+ AssertUtil.notNull(extractor, "extractor cannot be null");
+ this.extractor = extractor;
+ }
+
+ public ApacheHttpClientFallback getFallback() {
+ return fallback;
+ }
+
+ public void setFallback(ApacheHttpClientFallback fallback) {
+ AssertUtil.notNull(fallback, "fallback cannot be null");
+ this.fallback = fallback;
+ }
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/extractor/ApacheHttpClientResourceExtractor.java b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/extractor/ApacheHttpClientResourceExtractor.java
new file mode 100644
index 00000000..ab494d67
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/extractor/ApacheHttpClientResourceExtractor.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.csp.sentinel.adapter.apache.httpclient.extractor;
+
+import org.apache.http.client.methods.HttpRequestWrapper;
+
+/**
+ * @author zhaoyuguang
+ */
+public interface ApacheHttpClientResourceExtractor {
+
+ String extractor(HttpRequestWrapper request);
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/extractor/DefaultApacheHttpClientResourceExtractor.java b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/extractor/DefaultApacheHttpClientResourceExtractor.java
new file mode 100644
index 00000000..02ccf697
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/extractor/DefaultApacheHttpClientResourceExtractor.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.csp.sentinel.adapter.apache.httpclient.extractor;
+
+import org.apache.http.client.methods.HttpRequestWrapper;
+
+/**
+ * @author zhaoyuguang
+ */
+public class DefaultApacheHttpClientResourceExtractor implements ApacheHttpClientResourceExtractor {
+
+ @Override
+ public String extractor(HttpRequestWrapper request) {
+ return request.getRequestLine().getUri();
+ }
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/fallback/ApacheHttpClientFallback.java b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/fallback/ApacheHttpClientFallback.java
new file mode 100644
index 00000000..f670eca8
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/fallback/ApacheHttpClientFallback.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.csp.sentinel.adapter.apache.httpclient.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpRequestWrapper;
+import org.apache.http.protocol.HttpContext;
+
+import java.io.IOException;
+
+/**
+ * @author zhaoyuguang
+ */
+public interface ApacheHttpClientFallback {
+
+ CloseableHttpResponse handle(HttpRequestWrapper request, BlockException e);
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/fallback/DefaultApacheHttpClientFallback.java b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/fallback/DefaultApacheHttpClientFallback.java
new file mode 100644
index 00000000..81994bfc
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/fallback/DefaultApacheHttpClientFallback.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.csp.sentinel.adapter.apache.httpclient.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpRequestWrapper;
+import org.apache.http.protocol.HttpContext;
+
+import java.io.IOException;
+
+/**
+ * @author zhaoyuguang
+ */
+public class DefaultApacheHttpClientFallback implements ApacheHttpClientFallback {
+
+ @Override
+ public CloseableHttpResponse handle(HttpRequestWrapper request, BlockException e) {
+ // Just wrap and throw the exception.
+ throw new SentinelRpcException(e);
+ }
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/SentinelApacheHttpClientTest.java b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/SentinelApacheHttpClientTest.java
new file mode 100644
index 00000000..882edafe
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/SentinelApacheHttpClientTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.csp.sentinel.adapter.apache.httpclient;
+
+import com.alibaba.csp.sentinel.Constants;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.app.TestApplication;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.config.SentinelApacheHttpClientConfig;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.extractor.ApacheHttpClientResourceExtractor;
+import com.alibaba.csp.sentinel.node.ClusterNode;
+import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpRequestWrapper;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.EntityUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.io.IOException;
+
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * @author zhaoyuguang
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = TestApplication.class,
+ webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
+ properties = {
+ "server.port=8084"
+ })
+public class SentinelApacheHttpClientTest {
+
+ @Value("${server.port}")
+ private Integer port;
+
+ @Test
+ public void testSentinelOkHttpInterceptor0() throws Exception {
+
+ CloseableHttpClient httpclient = new SentinelApacheHttpClientBuilder().build();
+
+ HttpGet httpGet = new HttpGet("http://localhost:" + port + "/httpclient/back");
+ System.out.println(getRemoteString(httpclient, httpGet));
+ ClusterNode cn = ClusterBuilderSlot.getClusterNode("httpclient:/httpclient/back");
+ assertNotNull(cn);
+ Constants.ROOT.removeChildList();
+ ClusterBuilderSlot.getClusterNodeMap().clear();
+ }
+
+ @Test
+ public void testSentinelOkHttpInterceptor1() throws Exception {
+ SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+ config.setExtractor(new ApacheHttpClientResourceExtractor() {
+
+ @Override
+ public String extractor(HttpRequestWrapper request) {
+ String contains = "/httpclient/back/";
+ String uri = request.getRequestLine().getUri();
+ if (uri.startsWith(contains)) {
+ uri = uri.substring(0, uri.indexOf(contains) + contains.length()) + "{id}";
+ }
+ return request.getMethod() + ":" + uri;
+ }
+ });
+ CloseableHttpClient httpclient = new SentinelApacheHttpClientBuilder(config).build();
+
+ HttpGet httpGet = new HttpGet("http://localhost:" + port + "/httpclient/back/1");
+ System.out.println(getRemoteString(httpclient, httpGet));
+ ClusterNode cn = ClusterBuilderSlot.getClusterNode("httpclient:GET:/httpclient/back/{id}");
+ assertNotNull(cn);
+ Constants.ROOT.removeChildList();
+ ClusterBuilderSlot.getClusterNodeMap().clear();
+ }
+
+ private String getRemoteString(CloseableHttpClient httpclient, HttpGet httpGet) throws IOException {
+ String result;
+ HttpContext context = new BasicHttpContext();
+ CloseableHttpResponse response;
+ response = httpclient.execute(httpGet, context);
+ try {
+ HttpEntity entity = response.getEntity();
+ result = EntityUtils.toString(entity, "utf-8");
+ EntityUtils.consume(entity);
+ } finally {
+ response.close();
+ }
+ httpclient.close();
+ return result;
+ }
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/app/TestApplication.java b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/app/TestApplication.java
new file mode 100644
index 00000000..e073dda5
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/app/TestApplication.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.csp.sentinel.adapter.apache.httpclient.app;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author zhaoyuguang
+ */
+@SpringBootApplication
+public class TestApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(TestApplication.class);
+ }
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/app/controller/TestController.java b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/app/controller/TestController.java
new file mode 100644
index 00000000..2ae4275f
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/app/controller/TestController.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.csp.sentinel.adapter.apache.httpclient.app.controller;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author zhaoyuguang
+ */
+@RestController
+public class TestController {
+
+ @RequestMapping("/httpclient/back")
+ public String back() {
+ return "Welcome Back!";
+ }
+
+ @RequestMapping("/httpclient/back/{id}")
+ public String back(@PathVariable String id) {
+ return "Welcome Back! " + id;
+ }
+}
\ No newline at end of file
diff --git a/sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/config/SentinelApacheHttpClientConfigTest.java b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/config/SentinelApacheHttpClientConfigTest.java
new file mode 100644
index 00000000..414322b7
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/config/SentinelApacheHttpClientConfigTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.csp.sentinel.adapter.apache.httpclient.config;
+
+import org.junit.Test;
+
+/**
+ * @author zhaoyuguang
+ */
+public class SentinelApacheHttpClientConfigTest {
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testConfigSetPrefix() {
+ SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+ config.setPrefix(null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testConfigSetCleaner() {
+ SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+ config.setExtractor(null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testConfigSetFallback() {
+ SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+ config.setFallback(null);
+ }
+}
diff --git a/sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/fallback/ApacheHttpClientFallbackTest.java b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/fallback/ApacheHttpClientFallbackTest.java
new file mode 100644
index 00000000..56865918
--- /dev/null
+++ b/sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/fallback/ApacheHttpClientFallbackTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.csp.sentinel.adapter.apache.httpclient.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
+import org.junit.Test;
+
+/**
+ * @author zhaoyuguang
+ */
+public class ApacheHttpClientFallbackTest {
+
+ @Test(expected = SentinelRpcException.class)
+ public void testDefaultOkHttpFallback() {
+ BlockException e = new FlowException("xxx");
+ ApacheHttpClientFallback fallback = new DefaultApacheHttpClientFallback();
+ fallback.handle(null, e);
+ }
+}
diff --git a/sentinel-demo/pom.xml b/sentinel-demo/pom.xml
index 62a3937c..280d486e 100755
--- a/sentinel-demo/pom.xml
+++ b/sentinel-demo/pom.xml
@@ -32,6 +32,7 @@
sentinel-demo-command-handler
sentinel-demo-spring-webflux
sentinel-demo-apache-dubbo
+ sentinel-demo-apache-httpclient
sentinel-demo-sofa-rpc
sentinel-demo-spring-cloud-gateway
sentinel-demo-zuul-gateway
diff --git a/sentinel-demo/sentinel-demo-apache-httpclient/pom.xml b/sentinel-demo/sentinel-demo-apache-httpclient/pom.xml
new file mode 100644
index 00000000..b83a5faf
--- /dev/null
+++ b/sentinel-demo/sentinel-demo-apache-httpclient/pom.xml
@@ -0,0 +1,52 @@
+
+
+
+ sentinel-demo
+ com.alibaba.csp
+ 1.8.0-SNAPSHOT
+
+ 4.0.0
+
+ sentinel-demo-apache-httpclient
+
+
+ 2.1.3.RELEASE
+ 4.3
+ 4.5.6
+
+
+
+
+ com.alibaba.csp
+ sentinel-core
+
+
+ com.alibaba.csp
+ sentinel-transport-simple-http
+
+
+ com.alibaba.csp
+ sentinel-apache-httpclient-adapter
+ ${project.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${spring.boot.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ ${spring.boot.version}
+
+
+
+ org.apache.httpcomponents
+ httpclient
+ ${apache.httpclient.version}
+
+
+
+
\ No newline at end of file
diff --git a/sentinel-demo/sentinel-demo-apache-httpclient/src/main/java/com/alibaba/csp/sentinel/demo/apache/httpclient/ApacheHttpClientDemoApplication.java b/sentinel-demo/sentinel-demo-apache-httpclient/src/main/java/com/alibaba/csp/sentinel/demo/apache/httpclient/ApacheHttpClientDemoApplication.java
new file mode 100644
index 00000000..797e8e1b
--- /dev/null
+++ b/sentinel-demo/sentinel-demo-apache-httpclient/src/main/java/com/alibaba/csp/sentinel/demo/apache/httpclient/ApacheHttpClientDemoApplication.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.csp.sentinel.demo.apache.httpclient;
+
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author zhaoyuguang
+ */
+@SpringBootApplication
+public class ApacheHttpClientDemoApplication implements CommandLineRunner {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ApacheHttpClientDemoApplication.class);
+ }
+
+ @Override
+ public void run(String... args) {
+ }
+}
diff --git a/sentinel-demo/sentinel-demo-apache-httpclient/src/main/java/com/alibaba/csp/sentinel/demo/apache/httpclient/controller/ApacheHttpClientTestController.java b/sentinel-demo/sentinel-demo-apache-httpclient/src/main/java/com/alibaba/csp/sentinel/demo/apache/httpclient/controller/ApacheHttpClientTestController.java
new file mode 100644
index 00000000..3b1bf897
--- /dev/null
+++ b/sentinel-demo/sentinel-demo-apache-httpclient/src/main/java/com/alibaba/csp/sentinel/demo/apache/httpclient/controller/ApacheHttpClientTestController.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.csp.sentinel.demo.apache.httpclient.controller;
+
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.SentinelApacheHttpClientBuilder;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.config.SentinelApacheHttpClientConfig;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.extractor.ApacheHttpClientResourceExtractor;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpRequestWrapper;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.EntityUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.IOException;
+
+/**
+ * @author zhaoyuguang
+ */
+@RestController
+public class ApacheHttpClientTestController {
+
+ @Value("${server.port}")
+ private Integer port;
+
+ @RequestMapping("/httpclient/back")
+ public String back() {
+ System.out.println("back");
+ return "Welcome Back!";
+ }
+
+ @RequestMapping("/httpclient/back/{id}")
+ public String back(@PathVariable String id) {
+ System.out.println("back");
+ return "Welcome Back! " + id;
+ }
+
+ @RequestMapping("/httpclient/sync")
+ public String sync() throws Exception {
+ SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+ config.setExtractor(new ApacheHttpClientResourceExtractor() {
+
+ @Override
+ public String extractor(HttpRequestWrapper request) {
+ String contains = "/httpclient/back/";
+ String uri = request.getRequestLine().getUri();
+ if (uri.startsWith(contains)) {
+ uri = uri.substring(0, uri.indexOf(contains) + contains.length()) + "{id}";
+ }
+ return request.getMethod() + ":" + uri;
+ }
+ });
+ CloseableHttpClient httpclient = new SentinelApacheHttpClientBuilder(config).build();
+
+ HttpGet httpGet = new HttpGet("http://localhost:" + port + "/httpclient/back");
+ return getRemoteString(httpclient, httpGet);
+ }
+
+ @RequestMapping("/httpclient/sync/{id}")
+ public String sync(@PathVariable String id) throws Exception {
+ SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+ config.setExtractor(new ApacheHttpClientResourceExtractor() {
+
+ @Override
+ public String extractor(HttpRequestWrapper request) {
+ String contains = "/httpclient/back/";
+ String uri = request.getRequestLine().getUri();
+ if (uri.startsWith(contains)) {
+ uri = uri.substring(0, uri.indexOf(contains) + contains.length()) + "{id}";
+ }
+ return request.getMethod() + ":" + uri;
+ }
+ });
+ CloseableHttpClient httpclient = new SentinelApacheHttpClientBuilder(config).build();
+
+ HttpGet httpGet = new HttpGet("http://localhost:" + port + "/httpclient/back/" + id);
+ return getRemoteString(httpclient, httpGet);
+ }
+
+ private String getRemoteString(CloseableHttpClient httpclient, HttpGet httpGet) throws IOException {
+ String result;
+ HttpContext context = new BasicHttpContext();
+ CloseableHttpResponse response;
+ response = httpclient.execute(httpGet, context);
+ try {
+ HttpEntity entity = response.getEntity();
+ result = EntityUtils.toString(entity, "utf-8");
+ EntityUtils.consume(entity);
+ } finally {
+ response.close();
+ }
+ httpclient.close();
+ return result;
+ }
+}
diff --git a/sentinel-demo/sentinel-demo-apache-httpclient/src/main/resources/application.properties b/sentinel-demo/sentinel-demo-apache-httpclient/src/main/resources/application.properties
new file mode 100644
index 00000000..e3e48949
--- /dev/null
+++ b/sentinel-demo/sentinel-demo-apache-httpclient/src/main/resources/application.properties
@@ -0,0 +1,2 @@
+spring.application.name=sentinel-demo-apache-httpclient
+server.port=8083
\ No newline at end of file