From 18acb1d154d0412fc34a2db541ffa6bbfd1eff6c Mon Sep 17 00:00:00 2001
From: cdfive <31885791+cdfive@users.noreply.github.com>
Date: Mon, 2 Mar 2020 18:13:54 +0800
Subject: [PATCH] Add Sentinel SOFARPC adapter module (#1307)
---
sentinel-adapter/pom.xml | 1 +
.../sentinel-sofa-rpc-adapter/README.md | 63 +++++++
.../sentinel-sofa-rpc-adapter/pom.xml | 43 +++++
.../sofa/rpc/AbstractSofaRpcFilter.java | 57 +++++++
.../rpc/SentinelSofaRpcConsumerFilter.java | 82 +++++++++
.../rpc/SentinelSofaRpcProviderFilter.java | 93 +++++++++++
.../adapter/sofa/rpc/SofaRpcUtils.java | 59 +++++++
.../sofa/rpc/config/SofaRpcConfig.java | 9 +
.../rpc/fallback/DefaultSofaRpcFallback.java | 37 +++++
.../sofa/rpc/fallback/SofaRpcFallback.java | 39 +++++
.../rpc/fallback/SofaRpcFallbackRegistry.java | 46 ++++++
.../com.alipay.sofa.rpc.filter.Filter | 3 +
.../sofa/rpc/AbstractSofaRpcFilterTest.java | 109 ++++++++++++
.../sentinel/adapter/sofa/rpc/BaseTest.java | 58 +++++++
.../SentinelSofaRpcConsumerFilterTest.java | 155 ++++++++++++++++++
.../SentinelSofaRpcProviderFilterTest.java | 154 +++++++++++++++++
.../adapter/sofa/rpc/SofaRpcUtilsTest.java | 68 ++++++++
.../fallback/DefaultSofaRpcFallbackTest.java | 48 ++++++
.../fallback/SofaRpcFallbackRegistryTest.java | 74 +++++++++
.../adapter/sofa/rpc/service/DemoService.java | 24 +++
.../rpc/service/impl/DemoServiceImpl.java | 29 ++++
sentinel-demo/pom.xml | 1 +
.../sentinel-demo-sofa-rpc/README.md | 42 +++++
sentinel-demo/sentinel-demo-sofa-rpc/pom.xml | 44 +++++
.../sentinel/demo/sofa/rpc/DemoConsumer.java | 79 +++++++++
.../sentinel/demo/sofa/rpc/DemoProvider.java | 54 ++++++
.../demo/sofa/rpc/service/DemoService.java | 24 +++
.../rpc/service/impl/DemoServiceImpl.java | 41 +++++
.../src/main/resources/log4j.xml | 16 ++
.../main/resources/sofa-rpc/rpc-config.json | 6 +
30 files changed, 1558 insertions(+)
create mode 100755 sentinel-adapter/sentinel-sofa-rpc-adapter/README.md
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/pom.xml
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilter.java
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilter.java
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilter.java
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtils.java
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/config/SofaRpcConfig.java
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallback.java
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallback.java
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistry.java
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.filter.Filter
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilterTest.java
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/BaseTest.java
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilterTest.java
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilterTest.java
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtilsTest.java
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallbackTest.java
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistryTest.java
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/service/DemoService.java
create mode 100644 sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/service/impl/DemoServiceImpl.java
create mode 100644 sentinel-demo/sentinel-demo-sofa-rpc/README.md
create mode 100644 sentinel-demo/sentinel-demo-sofa-rpc/pom.xml
create mode 100644 sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/DemoConsumer.java
create mode 100644 sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/DemoProvider.java
create mode 100644 sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/service/DemoService.java
create mode 100644 sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/service/impl/DemoServiceImpl.java
create mode 100755 sentinel-demo/sentinel-demo-sofa-rpc/src/main/resources/log4j.xml
create mode 100644 sentinel-demo/sentinel-demo-sofa-rpc/src/main/resources/sofa-rpc/rpc-config.json
diff --git a/sentinel-adapter/pom.xml b/sentinel-adapter/pom.xml
index 1f152c16..d1bdc9e6 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-sofa-rpc-adapter
sentinel-grpc-adapter
sentinel-zuul-adapter
sentinel-reactor-adapter
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/README.md b/sentinel-adapter/sentinel-sofa-rpc-adapter/README.md
new file mode 100755
index 00000000..ee9d2522
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/README.md
@@ -0,0 +1,63 @@
+# Sentinel SOFARPC Adapter
+
+Sentinel SOFARPC Adapter provides service provider filter and consumer filter
+for [SOFARPC](https://www.sofastack.tech/projects/sofa-rpc) services.
+
+**Note: This adapter supports SOFARPC 5.4.x version and above, and 5.6.x is officially recommended.**
+
+To use Sentinel SOFARPC Adapter, you can simply add the following dependency to your `pom.xml`:
+
+```xml
+
+ com.alibaba.csp
+ sentinel-sofa-rpc-adapter
+ x.y.z
+
+```
+
+The Sentinel filters are **enabled by default**. Once you add the dependency,
+the SOFARPC services and methods will become protected resources in Sentinel,
+which can leverage Sentinel's flow control and guard ability when rules are configured.
+Demos can be found in [sentinel-demo-sofa-rpc](https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-sofa-rpc).
+
+If you don't want the filters enabled, you can manually disable them. For example:
+
+```java
+providerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
+consumerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
+```
+
+or add setting in `rpc-config.json` file, and its priority is lower than above.
+```json
+{
+ "sofa.rpc.sentinel.enabled": true
+}
+```
+
+For more details of SOFARPC filter, see [here](https://www.sofastack.tech/projects/sofa-rpc/custom-filter/).
+
+## SOFARPC resources
+
+The resource for SOFARPC services has two granularities: service interface and service method.
+
+- Service interface:resourceName format is `interfaceName`,e.g. `com.alibaba.csp.sentinel.demo.sofa.rpc.DemoService`
+- Service method:resourceName format is `interfaceName#methodSignature`,e.g. `com.alibaba.csp.sentinel.demo.sofa.rpc.DemoService#sayHello(java.lang.Integer,java.lang.String,int)`
+
+## Flow control based on caller
+
+In many circumstances, it's also significant to control traffic flow based on the **caller**.
+For example, assuming that there are two services A and B, both of them initiate remote call requests to the service provider.
+If we want to limit the calls from service B only, we can set the `limitApp` of flow rule as the identifier of service B (e.g. service name).
+
+Sentinel SOFARPC Adapter will automatically resolve the SOFARPC consumer's *application name* as the caller's name (`origin`),
+and will bring the caller's name when doing resource protection.
+If `limitApp` of flow rules is not configured (`default`), flow control will take effects on all callers.
+If `limitApp` of a flow rule is configured with a caller, then the corresponding flow rule will only take effect on the specific caller.
+
+## Global fallback
+
+Sentinel SOFARPC Adapter supports global fallback configuration.
+The global fallback will handle exceptions and give replacement result when blocked by
+flow control, degrade or system load protection. You can implement your own `SofaRpcFallback` interface
+and then register to `SofaRpcFallbackRegistry`. If no fallback is configured, Sentinel will wrap the `BlockException`
+then directly throw it out.
\ No newline at end of file
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/pom.xml b/sentinel-adapter/sentinel-sofa-rpc-adapter/pom.xml
new file mode 100644
index 00000000..12b91a9d
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/pom.xml
@@ -0,0 +1,43 @@
+
+
+
+ sentinel-adapter
+ com.alibaba.csp
+ 1.7.2-SNAPSHOT
+
+ 4.0.0
+
+ sentinel-sofa-rpc-adapter
+
+
+ 5.6.4
+
+
+
+
+ com.alibaba.csp
+ sentinel-core
+
+
+
+ com.alipay.sofa
+ sofa-rpc-all
+ ${sofa-rpc-all.version}
+ provided
+
+
+
+ junit
+ junit
+ test
+
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
\ No newline at end of file
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilter.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilter.java
new file mode 100644
index 00000000..850f255a
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilter.java
@@ -0,0 +1,57 @@
+package com.alibaba.csp.sentinel.adapter.sofa.rpc;
+
+import com.alibaba.csp.sentinel.Entry;
+import com.alibaba.csp.sentinel.Tracer;
+import com.alibaba.csp.sentinel.adapter.sofa.rpc.config.SofaRpcConfig;
+import com.alipay.sofa.rpc.common.RpcConfigs;
+import com.alipay.sofa.rpc.common.utils.StringUtils;
+import com.alipay.sofa.rpc.config.AbstractInterfaceConfig;
+import com.alipay.sofa.rpc.core.exception.RpcErrorType;
+import com.alipay.sofa.rpc.core.exception.SofaRpcException;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import com.alipay.sofa.rpc.filter.Filter;
+import com.alipay.sofa.rpc.filter.FilterInvoker;
+
+/**
+ * @author cdfive
+ */
+abstract class AbstractSofaRpcFilter extends Filter {
+
+ @Override
+ public boolean needToLoad(FilterInvoker invoker) {
+ AbstractInterfaceConfig config = invoker.getConfig();
+
+ String enabled = config.getParameter(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED);
+ if (StringUtils.isNotBlank(enabled)) {
+ return Boolean.valueOf(enabled);
+ }
+
+ return RpcConfigs.getOrDefaultValue(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, true);
+ }
+
+ protected void traceResponseException(SofaResponse response, Entry interfaceEntry, Entry methodEntry) {
+ if (response.isError()) {
+ SofaRpcException rpcException = new SofaRpcException(RpcErrorType.SERVER_FILTER, response.getErrorMsg());
+ Tracer.traceEntry(rpcException, interfaceEntry);
+ Tracer.traceEntry(rpcException, methodEntry);
+ } else {
+ Object appResponse = response.getAppResponse();
+ if (appResponse instanceof Throwable) {
+ Tracer.traceEntry((Throwable) appResponse, interfaceEntry);
+ Tracer.traceEntry((Throwable) appResponse, methodEntry);
+ }
+ }
+ }
+
+ protected SofaRpcException traceOtherException(Throwable t, Entry interfaceEntry, Entry methodEntry) {
+ SofaRpcException rpcException;
+ if (t instanceof SofaRpcException) {
+ rpcException = (SofaRpcException) t;
+ } else {
+ rpcException = new SofaRpcException(RpcErrorType.SERVER_FILTER, t);
+ }
+ Tracer.traceEntry(rpcException, interfaceEntry);
+ Tracer.traceEntry(rpcException, methodEntry);
+ return rpcException;
+ }
+}
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilter.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilter.java
new file mode 100644
index 00000000..c881be5a
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilter.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc;
+
+import com.alibaba.csp.sentinel.*;
+import com.alibaba.csp.sentinel.adapter.sofa.rpc.fallback.SofaRpcFallbackRegistry;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alipay.sofa.rpc.common.RpcConstants;
+import com.alipay.sofa.rpc.core.exception.SofaRpcException;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import com.alipay.sofa.rpc.ext.Extension;
+import com.alipay.sofa.rpc.filter.AutoActive;
+import com.alipay.sofa.rpc.filter.FilterInvoker;
+
+import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getInterfaceResourceName;
+import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getMethodResourceName;
+import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getMethodArguments;
+
+/**
+ * SOFARPC service consumer filter for Sentinel, auto activated by default.
+ *
+ * If you want to disable the consumer filter, you can configure:
+ *
ConsumerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
+ *
+ * or add setting in rpc-config.json:
+ * "sofa.rpc.sentinel.enabled": false
+ *
+ * @author cdfive
+ */
+@Extension(value = "consumerSentinel", order = -1000)
+@AutoActive(consumerSide = true)
+public class SentinelSofaRpcConsumerFilter extends AbstractSofaRpcFilter {
+
+ @Override
+ public SofaResponse invoke(FilterInvoker invoker, SofaRequest request) throws SofaRpcException {
+ // Now only support sync invoke.
+ if (request.getInvokeType() != null && !RpcConstants.INVOKER_TYPE_SYNC.equals(request.getInvokeType())) {
+ return invoker.invoke(request);
+ }
+
+ String interfaceResourceName = getInterfaceResourceName(request);
+ String methodResourceName = getMethodResourceName(request);
+
+ Entry interfaceEntry = null;
+ Entry methodEntry = null;
+ try {
+ interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT);
+ methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT, getMethodArguments(request));
+
+ SofaResponse response = invoker.invoke(request);
+
+ traceResponseException(response, interfaceEntry, methodEntry);
+ return response;
+ } catch (BlockException e) {
+ return SofaRpcFallbackRegistry.getConsumerFallback().handle(invoker, request, e);
+ } catch (Throwable t) {
+ throw traceOtherException(t, interfaceEntry, methodEntry);
+ } finally {
+ if (methodEntry != null) {
+ methodEntry.exit(1, getMethodArguments(request));
+ }
+
+ if (interfaceEntry != null) {
+ interfaceEntry.exit();
+ }
+ }
+ }
+}
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilter.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilter.java
new file mode 100644
index 00000000..6ffa95a9
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilter.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc;
+
+import com.alibaba.csp.sentinel.*;
+import com.alibaba.csp.sentinel.adapter.sofa.rpc.fallback.SofaRpcFallbackRegistry;
+import com.alibaba.csp.sentinel.context.ContextUtil;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alipay.sofa.rpc.common.RpcConstants;
+import com.alipay.sofa.rpc.core.exception.SofaRpcException;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import com.alipay.sofa.rpc.ext.Extension;
+import com.alipay.sofa.rpc.filter.AutoActive;
+import com.alipay.sofa.rpc.filter.FilterInvoker;
+
+import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getApplicationName;
+import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getInterfaceResourceName;
+import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getMethodResourceName;
+import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getMethodArguments;
+
+/**
+ * SOFARPC service provider filter for Sentinel, auto activated by default.
+ *
+ * If you want to disable the provider filter, you can configure:
+ * ProviderConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
+ *
+ * or add setting in rpc-config.json file:
+ *
+ * {
+ * "sofa.rpc.sentinel.enabled": false
+ * }
+ *
+ *
+ * @author cdfive
+ */
+@Extension(value = "providerSentinel", order = -1000)
+@AutoActive(providerSide = true)
+public class SentinelSofaRpcProviderFilter extends AbstractSofaRpcFilter {
+
+ @Override
+ public SofaResponse invoke(FilterInvoker invoker, SofaRequest request) throws SofaRpcException {
+ // Now only support sync invoke.
+ if (request.getInvokeType() != null && !RpcConstants.INVOKER_TYPE_SYNC.equals(request.getInvokeType())) {
+ return invoker.invoke(request);
+ }
+
+ String applicationName = getApplicationName(request);
+ String interfaceResourceName = getInterfaceResourceName(request);
+ String methodResourceName = getMethodResourceName(request);
+
+ Entry interfaceEntry = null;
+ Entry methodEntry = null;
+ try {
+ ContextUtil.enter(methodResourceName, applicationName);
+
+ interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN);
+ methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN, getMethodArguments(request));
+
+ SofaResponse response = invoker.invoke(request);
+
+ traceResponseException(response, interfaceEntry, methodEntry);
+ return response;
+ } catch (BlockException e) {
+ return SofaRpcFallbackRegistry.getProviderFallback().handle(invoker, request, e);
+ } catch (Throwable t) {
+ throw traceOtherException(t, interfaceEntry, methodEntry);
+ } finally {
+ if (methodEntry != null) {
+ methodEntry.exit(1, getMethodArguments(request));
+ }
+
+ if (interfaceEntry != null) {
+ interfaceEntry.exit();
+ }
+
+ ContextUtil.exit();
+ }
+ }
+}
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtils.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtils.java
new file mode 100644
index 00000000..f313c8a1
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtils.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc;
+
+import com.alipay.sofa.rpc.common.RemotingConstants;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+
+/**
+ * @author cdfive
+ */
+public class SofaRpcUtils {
+
+ public static String getApplicationName(SofaRequest request) {
+ String appName = (String) request.getRequestProp(RemotingConstants.HEAD_APP_NAME);
+ return appName == null ? "" : appName;
+ }
+
+ public static String getInterfaceResourceName(SofaRequest request) {
+ return request.getInterfaceName();
+ }
+
+ public static String getMethodResourceName(SofaRequest request) {
+ StringBuilder buf = new StringBuilder(64);
+ buf.append(request.getInterfaceName())
+ .append("#")
+ .append(request.getMethodName())
+ .append("(");
+
+ boolean isFirst = true;
+ for (String methodArgSig : request.getMethodArgSigs()) {
+ if (!isFirst) {
+ buf.append(",");
+ } else {
+ isFirst = false;
+ }
+
+ buf.append(methodArgSig);
+ }
+ buf.append(")");
+ return buf.toString();
+ }
+
+ public static Object[] getMethodArguments(SofaRequest request) {
+ return request.getMethodArgs();
+ }
+}
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/config/SofaRpcConfig.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/config/SofaRpcConfig.java
new file mode 100644
index 00000000..b63755ec
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/config/SofaRpcConfig.java
@@ -0,0 +1,9 @@
+package com.alibaba.csp.sentinel.adapter.sofa.rpc.config;
+
+/**
+ * @author cdfive
+ */
+public class SofaRpcConfig {
+
+ public static final String SOFA_RPC_SENTINEL_ENABLED = "sofa.rpc.sentinel.enabled";
+}
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallback.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallback.java
new file mode 100644
index 00000000..a85bb828
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallback.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import com.alipay.sofa.rpc.filter.FilterInvoker;
+
+/**
+ * Default Sentinel fallback handler for SOFARPC services.
+ * Just wrap and throw the exception.
+ *
+ * @author cdfive
+ */
+public class DefaultSofaRpcFallback implements SofaRpcFallback {
+
+ @Override
+ public SofaResponse handle(FilterInvoker invoker, SofaRequest request, BlockException ex) {
+ // Just wrap and throw the exception.
+ throw new SentinelRpcException(ex);
+ }
+}
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallback.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallback.java
new file mode 100644
index 00000000..e025eee8
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallback.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import com.alipay.sofa.rpc.filter.FilterInvoker;
+
+/**
+ * Sentinel fallback handler for SOFARPC services.
+ *
+ * @author cdfive
+ */
+public interface SofaRpcFallback {
+
+ /**
+ * Handle the block exception and provide fallback result.
+ *
+ * @param invoker FilterInvoker
+ * @param request SofaRequest
+ * @param ex block exception
+ * @return fallback result
+ */
+ SofaResponse handle(FilterInvoker invoker, SofaRequest request, BlockException ex);
+}
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistry.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistry.java
new file mode 100644
index 00000000..15361e3b
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistry.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc.fallback;
+
+/**
+ * Global Sentinel fallback registry for SOFARPC services.
+ *
+ * @author cdfive
+ */
+public final class SofaRpcFallbackRegistry {
+
+ private static volatile SofaRpcFallback providerFallback = new DefaultSofaRpcFallback();
+ private static volatile SofaRpcFallback consumerFallback = new DefaultSofaRpcFallback();
+
+ public static SofaRpcFallback getProviderFallback() {
+ return providerFallback;
+ }
+
+ public static void setProviderFallback(SofaRpcFallback providerFallback) {
+ SofaRpcFallbackRegistry.providerFallback = providerFallback;
+ }
+
+ public static SofaRpcFallback getConsumerFallback() {
+ return consumerFallback;
+ }
+
+ public static void setConsumerFallback(SofaRpcFallback consumerFallback) {
+ SofaRpcFallbackRegistry.consumerFallback = consumerFallback;
+ }
+
+ private SofaRpcFallbackRegistry() {}
+}
+
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.filter.Filter b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.filter.Filter
new file mode 100644
index 00000000..6c12ce2d
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.filter.Filter
@@ -0,0 +1,3 @@
+# name # order
+com.alibaba.csp.sentinel.adapter.sofa.rpc.SentinelSofaRpcProviderFilter # -1000
+com.alibaba.csp.sentinel.adapter.sofa.rpc.SentinelSofaRpcConsumerFilter # -1000
\ No newline at end of file
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilterTest.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilterTest.java
new file mode 100644
index 00000000..5d1d5303
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilterTest.java
@@ -0,0 +1,109 @@
+package com.alibaba.csp.sentinel.adapter.sofa.rpc;
+
+import com.alibaba.csp.sentinel.adapter.sofa.rpc.config.SofaRpcConfig;
+import com.alipay.sofa.rpc.codec.Serializer;
+import com.alipay.sofa.rpc.common.RpcConfigs;
+import com.alipay.sofa.rpc.config.ConsumerConfig;
+import com.alipay.sofa.rpc.config.ProviderConfig;
+import com.alipay.sofa.rpc.filter.FilterInvoker;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.lang.reflect.Method;
+
+import static org.junit.Assert.*;
+
+/**
+ * Test cases for {@link AbstractSofaRpcFilter}.
+ *
+ * @author cdfive
+ */
+public class AbstractSofaRpcFilterTest {
+
+ @Before
+ public void setUp() {
+ removeRpcConfig(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED);
+ }
+
+ @After
+ public void cleanUp() {
+ removeRpcConfig(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED);
+ }
+
+ @Test
+ public void testNeedToLoadProvider() {
+ SentinelSofaRpcProviderFilter providerFilter = new SentinelSofaRpcProviderFilter();
+ ProviderConfig providerConfig = new ProviderConfig();
+ providerConfig.setInterfaceId(Serializer.class.getName());
+ providerConfig.setId("AAA");
+ FilterInvoker invoker = new FilterInvoker(null, null, providerConfig);
+ assertTrue(providerFilter.needToLoad(invoker));
+
+ providerConfig.setParameter(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "false");
+ assertFalse(providerFilter.needToLoad(invoker));
+
+ providerConfig.setParameter(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "");
+ assertTrue(providerFilter.needToLoad(invoker));
+
+ RpcConfigs.putValue(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "false");
+ assertFalse(providerFilter.needToLoad(invoker));
+ }
+
+ @Test
+ public void testNeedToLoadConsumer() {
+ SentinelSofaRpcConsumerFilter consumerFilter = new SentinelSofaRpcConsumerFilter();
+ ConsumerConfig consumerConfig = new ConsumerConfig();
+ consumerConfig.setInterfaceId(Serializer.class.getName());
+ consumerConfig.setId("BBB");
+ FilterInvoker invoker = new FilterInvoker(null, null, consumerConfig);
+ assertTrue(consumerFilter.needToLoad(invoker));
+
+ consumerConfig.setParameter(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "false");
+ assertFalse(consumerFilter.needToLoad(invoker));
+
+ consumerConfig.setParameter(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "");
+ assertTrue(consumerFilter.needToLoad(invoker));
+
+ RpcConfigs.putValue(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "false");
+ assertFalse(consumerFilter.needToLoad(invoker));
+ }
+
+ @Test
+ public void testNeedToLoadProviderAndConsumer() {
+ SentinelSofaRpcProviderFilter providerFilter = new SentinelSofaRpcProviderFilter();
+ ProviderConfig providerConfig = new ProviderConfig();
+ providerConfig.setInterfaceId(Serializer.class.getName());
+ providerConfig.setId("AAA");
+ FilterInvoker providerInvoker = new FilterInvoker(null, null, providerConfig);
+ assertTrue(providerFilter.needToLoad(providerInvoker));
+
+ SentinelSofaRpcConsumerFilter consumerFilter = new SentinelSofaRpcConsumerFilter();
+ ConsumerConfig consumerConfig = new ConsumerConfig();
+ consumerConfig.setInterfaceId(Serializer.class.getName());
+ consumerConfig.setId("BBB");
+ FilterInvoker consumerInvoker = new FilterInvoker(null, null, consumerConfig);
+ assertTrue(consumerFilter.needToLoad(consumerInvoker));
+
+ providerConfig.setParameter(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "false");
+ assertFalse(providerFilter.needToLoad(providerInvoker));
+ assertTrue(consumerFilter.needToLoad(consumerInvoker));
+
+ providerConfig.setParameter(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "");
+ assertTrue(providerFilter.needToLoad(providerInvoker));
+
+ RpcConfigs.putValue(SofaRpcConfig.SOFA_RPC_SENTINEL_ENABLED, "false");
+ assertFalse(providerFilter.needToLoad(providerInvoker));
+ assertFalse(consumerFilter.needToLoad(consumerInvoker));
+ }
+
+ private void removeRpcConfig(String key) {
+ try {
+ Method removeValueMethod = RpcConfigs.class.getDeclaredMethod("removeValue", String.class);
+ removeValueMethod.setAccessible(true);
+ removeValueMethod.invoke(null, key);
+ } catch (Exception e) {
+ // Empty
+ }
+ }
+}
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/BaseTest.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/BaseTest.java
new file mode 100644
index 00000000..9f2a7508
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/BaseTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc;
+
+import com.alibaba.csp.sentinel.Constants;
+import com.alibaba.csp.sentinel.CtSph;
+import com.alibaba.csp.sentinel.context.Context;
+import com.alibaba.csp.sentinel.context.ContextUtil;
+import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
+
+import java.lang.reflect.Method;
+
+/**
+ * Base test class, provide common methods for sub test class.
+ *
+ * Note: Only for test. DO NOT USE IN PRODUCTION!
+ *
+ * @author cdfive
+ */
+public class BaseTest {
+
+ /**
+ * Clean up resources.
+ */
+ protected static void cleanUpAll() {
+ Context context = ContextUtil.getContext();
+ if (context != null) {
+ context.setCurEntry(null);
+ ContextUtil.exit();
+ }
+
+ Constants.ROOT.removeChildList();
+
+ ClusterBuilderSlot.getClusterNodeMap().clear();
+
+ // Clear chainMap in CtSph
+ try {
+ Method resetChainMapMethod = CtSph.class.getDeclaredMethod("resetChainMap");
+ resetChainMapMethod.setAccessible(true);
+ resetChainMapMethod.invoke(null);
+ } catch (Exception e) {
+ // Empty
+ }
+ }
+}
\ No newline at end of file
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilterTest.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilterTest.java
new file mode 100644
index 00000000..1c0b333a
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilterTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc;
+
+import com.alibaba.csp.sentinel.Constants;
+import com.alibaba.csp.sentinel.Entry;
+import com.alibaba.csp.sentinel.EntryType;
+import com.alibaba.csp.sentinel.context.Context;
+import com.alibaba.csp.sentinel.context.ContextUtil;
+import com.alibaba.csp.sentinel.node.ClusterNode;
+import com.alibaba.csp.sentinel.node.DefaultNode;
+import com.alibaba.csp.sentinel.node.Node;
+import com.alibaba.csp.sentinel.node.StatisticNode;
+import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
+import com.alipay.sofa.rpc.common.RpcConstants;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import com.alipay.sofa.rpc.filter.FilterInvoker;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * Test cases for {@link SentinelSofaRpcConsumerFilter}.
+ *
+ * @author cdfive
+ */
+public class SentinelSofaRpcConsumerFilterTest extends BaseTest {
+
+ @Before
+ public void setUp() {
+ cleanUpAll();
+ }
+
+ @After
+ public void cleanUp() {
+ cleanUpAll();
+ }
+
+ @Test
+ public void testInvokeSentinelWorks() {
+ SentinelSofaRpcConsumerFilter filter = new SentinelSofaRpcConsumerFilter();
+
+ final String interfaceResourceName = "com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService";
+ final String methodResourceName = "com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService#sayHello(java.lang.String,int)";
+
+ SofaRequest request = mock(SofaRequest.class);
+ when(request.getInvokeType()).thenReturn(RpcConstants.INVOKER_TYPE_SYNC);
+ when(request.getInterfaceName()).thenReturn(interfaceResourceName);
+ when(request.getMethodName()).thenReturn("sayHello");
+ when(request.getMethodArgSigs()).thenReturn(new String[]{"java.lang.String", "int"});
+ when(request.getMethodArgs()).thenReturn(new Object[]{"Sentinel", 2020});
+
+ FilterInvoker filterInvoker = mock(FilterInvoker.class);
+ when(filterInvoker.invoke(request)).thenAnswer(new Answer() {
+ @Override
+ public SofaResponse answer(InvocationOnMock invocationOnMock) throws Throwable {
+ verifyInvocationStructure(interfaceResourceName, methodResourceName);
+ SofaResponse response = new SofaResponse();
+ response.setAppResponse("Hello Sentinel 2020");
+ return response;
+ }
+ });
+
+ // Before invoke
+ assertNull(ContextUtil.getContext());
+
+ // Do invoke
+ SofaResponse response = filter.invoke(filterInvoker, request);
+ assertEquals("Hello Sentinel 2020", response.getAppResponse());
+ verify(filterInvoker).invoke(request);
+
+ // After invoke, make sure exit context
+ assertNull(ContextUtil.getContext());
+ }
+
+ /**
+ * Verify Sentinel invocation structure in memory:
+ * EntranceNode(defaultContextName)
+ * --InterfaceNode(interfaceName)
+ * ----MethodNode(resourceName)
+ */
+ private void verifyInvocationStructure(String interfaceResourceName, String methodResourceName) {
+ Context context = ContextUtil.getContext();
+ assertNotNull(context);
+
+ // As not call ContextUtil.enter(methodResourceName, applicationName) in SentinelSofaRpcConsumerFilter, use default context
+ // In actual project, a consumer is usually also a provider, the context will be created by SentinelSofaRpcProviderFilter
+ // If consumer is on the top of SOFARPC invocation chain, use default context
+ assertEquals(Constants.CONTEXT_DEFAULT_NAME, context.getName());
+ assertEquals("", context.getOrigin());
+
+ DefaultNode entranceNode = context.getEntranceNode();
+ ResourceWrapper entranceResource = entranceNode.getId();
+ assertEquals(Constants.CONTEXT_DEFAULT_NAME, entranceResource.getName());
+ assertSame(EntryType.IN, entranceResource.getEntryType());
+
+ // As SphU.entry(interfaceResourceName, EntryType.OUT);
+ Set childList = entranceNode.getChildList();
+ assertEquals(1, childList.size());
+ DefaultNode interfaceNode = (DefaultNode) childList.iterator().next();
+ ResourceWrapper interfaceResource = interfaceNode.getId();
+ assertEquals(interfaceResourceName, interfaceResource.getName());
+ assertSame(EntryType.OUT, interfaceResource.getEntryType());
+
+ // As SphU.entry(methodResourceName, EntryType.OUT);
+ childList = interfaceNode.getChildList();
+ assertEquals(1, childList.size());
+ DefaultNode methodNode = (DefaultNode) childList.iterator().next();
+ ResourceWrapper methodResource = methodNode.getId();
+ assertEquals(methodResourceName, methodResource.getName());
+ assertSame(EntryType.OUT, methodResource.getEntryType());
+
+ // Verify curEntry
+ Entry curEntry = context.getCurEntry();
+ assertSame(methodNode, curEntry.getCurNode());
+ assertSame(interfaceNode, curEntry.getLastNode());
+ // As context origin is not "", no originNode should be created in curEntry
+ assertNull(curEntry.getOriginNode());
+
+ // Verify clusterNode
+ ClusterNode methodClusterNode = methodNode.getClusterNode();
+ ClusterNode interfaceClusterNode = interfaceNode.getClusterNode();
+ // Different resource->Different ProcessorSlot->Different ClusterNode
+ assertNotSame(methodClusterNode, interfaceClusterNode);
+
+ // As context origin is "", the StatisticNode should not be created in originCountMap of ClusterNode
+ Map methodOriginCountMap = methodClusterNode.getOriginCountMap();
+ assertEquals(0, methodOriginCountMap.size());
+
+ Map interfaceOriginCountMap = interfaceClusterNode.getOriginCountMap();
+ assertEquals(0, interfaceOriginCountMap.size());
+ }
+}
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilterTest.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilterTest.java
new file mode 100644
index 00000000..5673aa96
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilterTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc;
+
+import com.alibaba.csp.sentinel.Entry;
+import com.alibaba.csp.sentinel.EntryType;
+import com.alibaba.csp.sentinel.context.Context;
+import com.alibaba.csp.sentinel.context.ContextUtil;
+import com.alibaba.csp.sentinel.node.ClusterNode;
+import com.alibaba.csp.sentinel.node.DefaultNode;
+import com.alibaba.csp.sentinel.node.Node;
+import com.alibaba.csp.sentinel.node.StatisticNode;
+import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
+import com.alipay.sofa.rpc.common.RpcConstants;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import com.alipay.sofa.rpc.filter.FilterInvoker;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * Test cases for {@link SentinelSofaRpcProviderFilter}.
+ *
+ * @author cdfive
+ */
+public class SentinelSofaRpcProviderFilterTest extends BaseTest {
+
+ @Before
+ public void setUp() {
+ cleanUpAll();
+ }
+
+ @After
+ public void cleanUp() {
+ cleanUpAll();
+ }
+
+ @Test
+ public void testInvokeSentinelWorks() {
+ SentinelSofaRpcProviderFilter filter = new SentinelSofaRpcProviderFilter();
+
+ final String applicationName = "demo-provider";
+ final String interfaceResourceName = "com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService";
+ final String methodResourceName = "com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService#sayHello(java.lang.String,int)";
+
+ SofaRequest request = mock(SofaRequest.class);
+ when(request.getRequestProp("app")).thenReturn(applicationName);
+ when(request.getInvokeType()).thenReturn(RpcConstants.INVOKER_TYPE_SYNC);
+ when(request.getInterfaceName()).thenReturn(interfaceResourceName);
+ when(request.getMethodName()).thenReturn("sayHello");
+ when(request.getMethodArgSigs()).thenReturn(new String[]{"java.lang.String", "int"});
+ when(request.getMethodArgs()).thenReturn(new Object[]{"Sentinel", 2020});
+
+ FilterInvoker filterInvoker = mock(FilterInvoker.class);
+ when(filterInvoker.invoke(request)).thenAnswer(new Answer() {
+ @Override
+ public SofaResponse answer(InvocationOnMock invocationOnMock) throws Throwable {
+ verifyInvocationStructure(applicationName, interfaceResourceName, methodResourceName);
+ SofaResponse response = new SofaResponse();
+ response.setAppResponse("Hello Sentinel 2020");
+ return response;
+ }
+ });
+
+ // Before invoke
+ assertNull(ContextUtil.getContext());
+
+ // Do invoke
+ SofaResponse response = filter.invoke(filterInvoker, request);
+ assertEquals("Hello Sentinel 2020", response.getAppResponse());
+ verify(filterInvoker).invoke(request);
+
+ // After invoke, make sure exit context
+ assertNull(ContextUtil.getContext());
+ }
+
+ /**
+ * Verify Sentinel invocation structure in memory:
+ * EntranceNode(methodResourceName)
+ * --InterfaceNode(interfaceResourceName)
+ * ----MethodNode(methodResourceName)
+ */
+ private void verifyInvocationStructure(String applicationName, String interfaceResourceName, String methodResourceName) {
+ Context context = ContextUtil.getContext();
+ assertNotNull(context);
+
+ assertEquals(methodResourceName, context.getName());
+ assertEquals(applicationName, context.getOrigin());
+
+ DefaultNode entranceNode = context.getEntranceNode();
+ ResourceWrapper entranceResource = entranceNode.getId();
+ assertEquals(methodResourceName, entranceResource.getName());
+ assertSame(EntryType.IN, entranceResource.getEntryType());
+
+ // As SphU.entry(interfaceResourceName, EntryType.IN);
+ Set childList = entranceNode.getChildList();
+ assertEquals(1, childList.size());
+ DefaultNode interfaceNode = (DefaultNode) childList.iterator().next();
+ ResourceWrapper interfaceResource = interfaceNode.getId();
+ assertEquals(interfaceResourceName, interfaceResource.getName());
+ assertSame(EntryType.IN, interfaceResource.getEntryType());
+
+ // As SphU.entry(methodResourceName, EntryType.IN, 1, methodArguments);
+ childList = interfaceNode.getChildList();
+ assertEquals(1, childList.size());
+ DefaultNode methodNode = (DefaultNode) childList.iterator().next();
+ ResourceWrapper methodResource = methodNode.getId();
+ assertEquals(methodResourceName, methodResource.getName());
+ assertSame(EntryType.IN, methodResource.getEntryType());
+
+ // Verify curEntry
+ Entry curEntry = context.getCurEntry();
+ assertSame(methodNode, curEntry.getCurNode());
+ assertSame(interfaceNode, curEntry.getLastNode());
+ // As context origin is not "", originNode should be created
+ assertNotNull(curEntry.getOriginNode());
+
+ // Verify clusterNode
+ ClusterNode methodClusterNode = methodNode.getClusterNode();
+ ClusterNode interfaceClusterNode = interfaceNode.getClusterNode();
+ // Different resource->Different ProcessorSlot->Different ClusterNode
+ assertNotSame(methodClusterNode, interfaceClusterNode);
+
+ // As context origin is not "", the StatisticNode should be created in originCountMap of ClusterNode
+ Map methodOriginCountMap = methodClusterNode.getOriginCountMap();
+ assertEquals(1, methodOriginCountMap.size());
+ assertTrue(methodOriginCountMap.containsKey(applicationName));
+ Map interfaceOriginCountMap = interfaceClusterNode.getOriginCountMap();
+ assertEquals(1, interfaceOriginCountMap.size());
+ assertTrue(interfaceOriginCountMap.containsKey(applicationName));
+ }
+}
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtilsTest.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtilsTest.java
new file mode 100644
index 00000000..f9f019a8
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtilsTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc;
+
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Test cases for {@link SofaRpcUtils}.
+ *
+ * @author cdfive
+ */
+public class SofaRpcUtilsTest {
+
+ @Test
+ public void testGetApplicationName() {
+ SofaRequest request = new SofaRequest();
+ String applicationName = SofaRpcUtils.getApplicationName(request);
+ assertEquals("", applicationName);
+
+ request.addRequestProp("app", "test-app");
+ applicationName = SofaRpcUtils.getApplicationName(request);
+ assertEquals("test-app", applicationName);
+ }
+
+ @Test
+ public void testGetInterfaceResourceName() {
+ SofaRequest request = new SofaRequest();
+ request.setInterfaceName("com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService");
+ String interfaceResourceName = SofaRpcUtils.getInterfaceResourceName(request);
+ assertEquals("com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService", interfaceResourceName);
+ }
+
+ @Test
+ public void testGetMethodResourceName() {
+ SofaRequest request = new SofaRequest();
+ request.setInterfaceName("com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService");
+ request.setMethodName("sayHello");
+ request.setMethodArgSigs(new String[]{"java.lang.String", "int"});
+ String methodResourceName = SofaRpcUtils.getMethodResourceName(request);
+ assertEquals("com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService#sayHello(java.lang.String,int)", methodResourceName);
+ }
+
+ @Test
+ public void testGetMethodArguments() {
+ SofaRequest request = new SofaRequest();
+ request.setMethodArgs(new Object[]{"Sentinel", 2020});
+ Object[] arguments = SofaRpcUtils.getMethodArguments(request);
+ assertEquals(arguments.length, 2);
+ assertEquals("Sentinel", arguments[0]);
+ assertEquals(2020, arguments[1]);
+ }
+}
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallbackTest.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallbackTest.java
new file mode 100644
index 00000000..af707727
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallbackTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * Test cases for {@link DefaultSofaRpcFallback}.
+ *
+ * @author cdfive
+ */
+public class DefaultSofaRpcFallbackTest {
+
+ @Test
+ public void testHandle() {
+ SofaRpcFallback sofaRpcFallback = new DefaultSofaRpcFallback();
+ BlockException blockException = mock(BlockException.class);
+
+ boolean throwSentinelRpcException = false;
+ boolean causeIsBlockException = false;
+ try {
+ sofaRpcFallback.handle(null, null, blockException);
+ } catch (Exception e) {
+ throwSentinelRpcException = e instanceof SentinelRpcException;
+ causeIsBlockException = e.getCause() instanceof BlockException;
+ }
+ assertTrue(throwSentinelRpcException);
+ assertTrue(causeIsBlockException);
+ }
+}
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistryTest.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistryTest.java
new file mode 100644
index 00000000..15930d10
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistryTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import com.alipay.sofa.rpc.filter.FilterInvoker;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Test cases for {@link SofaRpcFallbackRegistry}.
+ *
+ * @author cdfive
+ */
+public class SofaRpcFallbackRegistryTest {
+
+ @Test
+ public void testDefaultfallback() {
+ // Test get default provider fallback
+ SofaRpcFallback providerFallback = SofaRpcFallbackRegistry.getProviderFallback();
+ assertNotNull(providerFallback);
+ assertTrue(providerFallback instanceof DefaultSofaRpcFallback);
+
+ // Test get default consumer fallback
+ SofaRpcFallback consumerFallback = SofaRpcFallbackRegistry.getConsumerFallback();
+ assertNotNull(consumerFallback);
+ assertTrue(consumerFallback instanceof DefaultSofaRpcFallback);
+ }
+
+ @Test
+ public void testCustomFallback() {
+ // Test invoke custom provider fallback
+ SofaRpcFallbackRegistry.setProviderFallback(new SofaRpcFallback() {
+ @Override
+ public SofaResponse handle(FilterInvoker invoker, SofaRequest request, BlockException ex) {
+ SofaResponse response = new SofaResponse();
+ response.setAppResponse("test provider response");
+ return response;
+ }
+ });
+ SofaResponse providerResponse = SofaRpcFallbackRegistry.getProviderFallback().handle(null, null, null);
+ assertNotNull(providerResponse);
+ assertEquals("test provider response", providerResponse.getAppResponse());
+
+ // Test invoke custom consumer fallback
+ SofaRpcFallbackRegistry.setConsumerFallback(new SofaRpcFallback() {
+ @Override
+ public SofaResponse handle(FilterInvoker invoker, SofaRequest request, BlockException ex) {
+ SofaResponse response = new SofaResponse();
+ response.setAppResponse("test consumer response");
+ return response;
+ }
+ });
+ SofaResponse consumerResponse = SofaRpcFallbackRegistry.getConsumerFallback().handle(null, null, null);
+ assertNotNull(consumerResponse);
+ assertEquals("test consumer response", consumerResponse.getAppResponse());
+ }
+}
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/service/DemoService.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/service/DemoService.java
new file mode 100644
index 00000000..d767fd15
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/service/DemoService.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc.service;
+
+/**
+ * @author cdfive
+ */
+public interface DemoService {
+
+ String sayHello(String name, int year);
+}
diff --git a/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/service/impl/DemoServiceImpl.java b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/service/impl/DemoServiceImpl.java
new file mode 100644
index 00000000..e87d7f37
--- /dev/null
+++ b/sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/service/impl/DemoServiceImpl.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc.service.impl;
+
+import com.alibaba.csp.sentinel.adapter.sofa.rpc.service.DemoService;
+
+/**
+ * @author cdfive
+ */
+public class DemoServiceImpl implements DemoService {
+
+ @Override
+ public String sayHello(String name, int year) {
+ return "Hello " + name + " " + year;
+ }
+}
diff --git a/sentinel-demo/pom.xml b/sentinel-demo/pom.xml
index 1f055d29..2e03da0e 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-sofa-rpc
sentinel-demo-spring-cloud-gateway
sentinel-demo-zuul-gateway
sentinel-demo-etcd-datasource
diff --git a/sentinel-demo/sentinel-demo-sofa-rpc/README.md b/sentinel-demo/sentinel-demo-sofa-rpc/README.md
new file mode 100644
index 00000000..ddf08319
--- /dev/null
+++ b/sentinel-demo/sentinel-demo-sofa-rpc/README.md
@@ -0,0 +1,42 @@
+# Sentinel SOFARPC Demo
+
+Sentinel 提供了与 SOFARPC 整合的模块 - `sentinel-sofa-rpc-adapter`,主要包括针对 Service Provider 和 Service Consumer 实现的 Filter。使用时用户只需引入以下模块(以 Maven 为例):
+
+```xml
+
+ com.alibaba.csp
+ sentinel-sofa-rpc-adapter
+ x.y.z
+
+```
+
+引入此依赖后,SOFARPC 的服务接口和方法(包括调用端和服务端)就会成为 Sentinel 中的资源,在配置了规则后就可以自动享受到 Sentinel 的防护能力。
+
+> **注:若希望接入 Dashboard,请参考demo中的注释添加VM参数,只引入`sentinel-sofa-rpc-adapter`无法接入控制台!**
+
+若不希望开启 Sentinel SOFARPC Adapter 中的某个 Filter,可以手动关闭对应的 Filter,比如:
+
+```java
+providerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
+consumerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
+```
+
+或者在`rpc-config.json`文件中设置,它的优先级要低一些。
+
+```json
+{
+ "sofa.rpc.sentinel.enabled": true
+}
+```
+
+# 运行Demo
+
+1. 启动控制台,运行`DashboardApplication`
+
+2. 启动Provider,运行`DemoProvider`(VM参数:`-Dproject.name=DemoProvider -Dcsp.sentinel.dashboard.server=localhost:8080`)
+
+3. 启动Consumer,运行`DemoConsumer`(VM参数:`-Dproject.name=DemoConsumer -Dcsp.sentinel.dashboard.server=localhost:8080`)
+
+通过控制台实时监控、簇点链路菜单观察接口调用、资源情况;对资源设置不同流控规则,进行观察和调试。
+
+参考:[Sentinel控制台](https://github.com/alibaba/Sentinel/wiki/控制台).
\ No newline at end of file
diff --git a/sentinel-demo/sentinel-demo-sofa-rpc/pom.xml b/sentinel-demo/sentinel-demo-sofa-rpc/pom.xml
new file mode 100644
index 00000000..3eb808c6
--- /dev/null
+++ b/sentinel-demo/sentinel-demo-sofa-rpc/pom.xml
@@ -0,0 +1,44 @@
+
+
+
+ sentinel-demo
+ com.alibaba.csp
+ 1.7.2-SNAPSHOT
+
+ 4.0.0
+
+ sentinel-demo-sofa-rpc
+
+
+ 5.6.4
+ 1.7.21
+
+
+
+
+ com.alibaba.csp
+ sentinel-sofa-rpc-adapter
+ ${project.version}
+
+
+
+ com.alibaba.csp
+ sentinel-transport-simple-http
+ ${project.version}
+
+
+
+ com.alipay.sofa
+ sofa-rpc-all
+ ${sofa-rpc-all.version}
+
+
+
+ org.slf4j
+ slf4j-log4j12
+ ${slf4j-log4j12.version}
+
+
+
\ No newline at end of file
diff --git a/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/DemoConsumer.java b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/DemoConsumer.java
new file mode 100644
index 00000000..a4e31649
--- /dev/null
+++ b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/DemoConsumer.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc;
+
+import com.alibaba.csp.sentinel.demo.sofa.rpc.service.DemoService;
+import com.alipay.sofa.rpc.common.RpcConstants;
+import com.alipay.sofa.rpc.config.ApplicationConfig;
+import com.alipay.sofa.rpc.config.ConsumerConfig;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Demo consumer of SOFARPC.
+ *
+ * Interact with Sentinel Dashboard, add the following VM arguments:
+ *
+ * -Dproject.name=DemoProvider -Dcsp.sentinel.dashboard.server=localhost:8080
+ *
+ *
+ * @author cdfive
+ */
+public class DemoConsumer {
+
+ public static void main(String[] args) throws Exception {
+ ApplicationConfig application = new ApplicationConfig().setAppName("DemoConsumer");
+
+ ConsumerConfig consumerConfig = new ConsumerConfig()
+ .setApplication(application)
+ .setInterfaceId(DemoService.class.getName())
+ .setProtocol("bolt")
+ .setDirectUrl("bolt://127.0.0.1:12001")
+ .setInvokeType(RpcConstants.INVOKER_TYPE_SYNC);
+
+ // 设置是否启用Sentinel,默认启用
+ // 也可在rpc-config.json全局设置
+// consumerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
+
+ DemoService helloService = consumerConfig.refer();
+
+ System.out.println("DemoConsumer started!");
+
+ long sleepMs = 5;
+ int total = 5000;
+ int index = 0;
+ System.out.println("Total call " + total + " times and sleep " + sleepMs + "ms after each call.");
+
+ while (true) {
+ try {
+ index++;
+ String result = helloService.sayHello(index, "SOFARPC", 2020);
+ System.out.println("[" + index + "][Consumer]receive response: " + result);
+ } catch (Exception e) {
+ System.out.println("[" + index + "][Consumer]receive exception: " + e.getMessage());
+ }
+
+ TimeUnit.MILLISECONDS.sleep(sleepMs);
+
+ if (index == total) {
+ break;
+ }
+ }
+
+ System.out.println("DemoConsumer exit!");
+ System.exit(0);
+ }
+}
\ No newline at end of file
diff --git a/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/DemoProvider.java b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/DemoProvider.java
new file mode 100644
index 00000000..35415242
--- /dev/null
+++ b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/DemoProvider.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc;
+
+import com.alibaba.csp.sentinel.demo.sofa.rpc.service.DemoService;
+import com.alibaba.csp.sentinel.demo.sofa.rpc.service.impl.DemoServiceImpl;
+import com.alipay.sofa.rpc.config.ProviderConfig;
+import com.alipay.sofa.rpc.config.ServerConfig;
+
+/**
+ * Demo provider of SOFARPC
+ *
+ * Interact with Sentinel Dashboard, add the following VM arguments:
+ *
+ * -Dproject.name=DemoProvider -Dcsp.sentinel.dashboard.server=localhost:8080
+ *
+ *
+ * @author cdfive
+ */
+public class DemoProvider {
+
+ public static void main(String[] args) {
+ ServerConfig serverConfig = new ServerConfig()
+ .setProtocol("bolt")
+ .setPort(12001)
+ .setDaemon(false);
+
+ ProviderConfig providerConfig = new ProviderConfig()
+ .setInterfaceId(DemoService.class.getName())
+ .setRef(new DemoServiceImpl())
+ .setServer(serverConfig);
+
+ // 设置是否启用Sentinel,默认启用
+ // 也可在rpc-config.json全局设置
+// providerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
+
+ providerConfig.export();
+
+ System.out.println("DemoProvider started!");
+ }
+}
\ No newline at end of file
diff --git a/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/service/DemoService.java b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/service/DemoService.java
new file mode 100644
index 00000000..a1a6318c
--- /dev/null
+++ b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/service/DemoService.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc.service;
+
+/**
+ * @author cdfive
+ */
+public interface DemoService {
+
+ String sayHello(Integer index, String name, int year);
+}
\ No newline at end of file
diff --git a/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/service/impl/DemoServiceImpl.java b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/service/impl/DemoServiceImpl.java
new file mode 100644
index 00000000..5a842eaa
--- /dev/null
+++ b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/java/com/alibaba/csp/sentinel/demo/sofa/rpc/service/impl/DemoServiceImpl.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 1999-2018 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.sofa.rpc.service.impl;
+
+import com.alibaba.csp.sentinel.demo.sofa.rpc.service.DemoService;
+
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author cdfive
+ */
+public class DemoServiceImpl implements DemoService {
+
+ @Override
+ public String sayHello(Integer index, String name, int year) {
+ System.out.println("[" + index + "][Provider]receive request: " + name + "," + year);
+
+ int sleepMs = ThreadLocalRandom.current().nextInt(50);
+ try {
+ TimeUnit.MILLISECONDS.sleep(sleepMs);
+ } catch (InterruptedException e) {
+ System.err.println(e.getMessage());
+ }
+
+ return "Hello " + name + " " + year + "[" + sleepMs + "ms]";
+ }
+}
\ No newline at end of file
diff --git a/sentinel-demo/sentinel-demo-sofa-rpc/src/main/resources/log4j.xml b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/resources/log4j.xml
new file mode 100755
index 00000000..e95634f1
--- /dev/null
+++ b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/resources/log4j.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sentinel-demo/sentinel-demo-sofa-rpc/src/main/resources/sofa-rpc/rpc-config.json b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/resources/sofa-rpc/rpc-config.json
new file mode 100644
index 00000000..4c5458b2
--- /dev/null
+++ b/sentinel-demo/sentinel-demo-sofa-rpc/src/main/resources/sofa-rpc/rpc-config.json
@@ -0,0 +1,6 @@
+{
+ "rpc.config.order": 999,
+ "logger.impl": "com.alipay.sofa.rpc.log.SLF4JLoggerImpl",
+ // 是否启用Sentinel,不设置默认为true
+ "sofa.rpc.sentinel.enabled": true
+}
\ No newline at end of file