Dubbo service consumer filter for Sentinel. Auto activated by default.
+ * + * If you want to disable the consumer filter, you can configure: + *+ * <dubbo:consumer filter="-sentinel.dubbo.consumer.filter"/> + *+ * + * @author Carpenter Lee + * @author Eric Zhao + */ +@Activate(group = "consumer") +public class SentinelDubboConsumerFilter implements Filter { + + public SentinelDubboConsumerFilter() { + RecordLog.info("Sentinel Apache Dubbo consumer filter initialized"); + } + + @Override + public Result invoke(Invoker> invoker, Invocation invocation) throws RpcException { + Entry interfaceEntry = null; + Entry methodEntry = null; + try { + String resourceName = DubboUtils.getResourceName(invoker, invocation); + interfaceEntry = SphU.entry(invoker.getInterface().getName(), EntryType.OUT); + methodEntry = SphU.entry(resourceName, EntryType.OUT); + + Result result = invoker.invoke(invocation); + if (result.hasException()) { + Throwable e = result.getException(); + // Record common exception. + Tracer.traceEntry(e, interfaceEntry); + Tracer.traceEntry(e, methodEntry); + } + return result; + } catch (BlockException e) { + return DubboFallbackRegistry.getConsumerFallback().handle(invoker, invocation, e); + } catch (RpcException e) { + Tracer.traceEntry(e, interfaceEntry); + Tracer.traceEntry(e, methodEntry); + throw e; + } finally { + if (methodEntry != null) { + methodEntry.exit(); + } + if (interfaceEntry != null) { + interfaceEntry.exit(); + } + } + } +} diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilter.java b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilter.java new file mode 100755 index 0000000000..2020832a0b --- /dev/null +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilter.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.dubbo; + +import com.alibaba.csp.sentinel.Entry; +import com.alibaba.csp.sentinel.EntryType; +import com.alibaba.csp.sentinel.SphU; +import com.alibaba.csp.sentinel.Tracer; +import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry; +import com.alibaba.csp.sentinel.context.ContextUtil; +import com.alibaba.csp.sentinel.log.RecordLog; +import com.alibaba.csp.sentinel.slots.block.BlockException; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.rpc.Filter; +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.Result; +import org.apache.dubbo.rpc.RpcException; + +/** + *
Apache Dubbo service provider filter that enables integration with Sentinel. Auto activated by default.
+ *Note: this only works for Apache Dubbo 2.7.x or above version.
+ * + * If you want to disable the provider filter, you can configure: + *+ * <dubbo:provider filter="-sentinel.dubbo.provider.filter"/> + *+ * + * @author Carpenter Lee + * @author Eric Zhao + */ +@Activate(group = "provider") +public class SentinelDubboProviderFilter implements Filter { + + public SentinelDubboProviderFilter() { + RecordLog.info("Sentinel Apache Dubbo provider filter initialized"); + } + + @Override + public Result invoke(Invoker> invoker, Invocation invocation) throws RpcException { + // Get origin caller. + String application = DubboUtils.getApplication(invocation, ""); + + Entry interfaceEntry = null; + Entry methodEntry = null; + try { + String resourceName = DubboUtils.getResourceName(invoker, invocation); + String interfaceName = invoker.getInterface().getName(); + // Only need to create entrance context at provider side, as context will take effect + // at entrance of invocation chain only (for inbound traffic). + ContextUtil.enter(resourceName, application); + interfaceEntry = SphU.entry(interfaceName, EntryType.IN); + methodEntry = SphU.entry(resourceName, EntryType.IN, 1, invocation.getArguments()); + + Result result = invoker.invoke(invocation); + if (result.hasException()) { + Throwable e = result.getException(); + // Record common exception. + Tracer.traceEntry(e, interfaceEntry); + Tracer.traceEntry(e, methodEntry); + } + return result; + } catch (BlockException e) { + return DubboFallbackRegistry.getProviderFallback().handle(invoker, invocation, e); + } catch (RpcException e) { + Tracer.traceEntry(e, interfaceEntry); + Tracer.traceEntry(e, methodEntry); + throw e; + } finally { + if (methodEntry != null) { + methodEntry.exit(1, invocation.getArguments()); + } + if (interfaceEntry != null) { + interfaceEntry.exit(); + } + ContextUtil.exit(); + } + } +} diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DefaultDubboFallback.java b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DefaultDubboFallback.java new file mode 100644 index 0000000000..8a4659f7be --- /dev/null +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DefaultDubboFallback.java @@ -0,0 +1,35 @@ +/* + * 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.dubbo.fallback; + +import com.alibaba.csp.sentinel.slots.block.BlockException; +import com.alibaba.csp.sentinel.slots.block.SentinelRpcException; + +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.Result; + +/** + * @author Eric Zhao + */ +public class DefaultDubboFallback implements DubboFallback { + + @Override + public Result handle(Invoker> invoker, Invocation invocation, BlockException ex) { + // Just wrap and throw the exception. + throw new SentinelRpcException(ex); + } +} diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallback.java b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallback.java new file mode 100644 index 0000000000..133232c384 --- /dev/null +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallback.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.adapter.dubbo.fallback; + +import com.alibaba.csp.sentinel.slots.block.BlockException; + +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.Result; + +/** + * Fallback handler for Dubbo services. + * + * @author Eric Zhao + */ +@FunctionalInterface +public interface DubboFallback { + + /** + * Handle the block exception and provide fallback result. + * + * @param invoker Dubbo invoker + * @param invocation Dubbo invocation + * @param ex block exception + * @return fallback result + */ + Result handle(Invoker> invoker, Invocation invocation, BlockException ex); +} diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallbackRegistry.java b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallbackRegistry.java new file mode 100644 index 0000000000..78c3a0b191 --- /dev/null +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallbackRegistry.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.adapter.dubbo.fallback; + +import com.alibaba.csp.sentinel.util.AssertUtil; + +/** + *
Global fallback registry for Dubbo.
+ * + *+ * Note: Circuit breaking is mainly designed for consumer. The provider should not + * give fallback result in most circumstances. + *
+ * + * @author Eric Zhao + */ +public final class DubboFallbackRegistry { + + private static volatile DubboFallback consumerFallback = new DefaultDubboFallback(); + private static volatile DubboFallback providerFallback = new DefaultDubboFallback(); + + public static DubboFallback getConsumerFallback() { + return consumerFallback; + } + + public static void setConsumerFallback(DubboFallback consumerFallback) { + AssertUtil.notNull(consumerFallback, "consumerFallback cannot be null"); + DubboFallbackRegistry.consumerFallback = consumerFallback; + } + + public static DubboFallback getProviderFallback() { + return providerFallback; + } + + public static void setProviderFallback(DubboFallback providerFallback) { + AssertUtil.notNull(providerFallback, "providerFallback cannot be null"); + DubboFallbackRegistry.providerFallback = providerFallback; + } + + private DubboFallbackRegistry() {} +} diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.Filter b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.Filter new file mode 100755 index 0000000000..292a4b2591 --- /dev/null +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/resources/META-INF/dubbo/org.apache.dubbo.rpc.Filter @@ -0,0 +1,3 @@ +sentinel.dubbo.provider.filter=com.alibaba.csp.sentinel.adapter.dubbo.SentinelDubboProviderFilter +sentinel.dubbo.consumer.filter=com.alibaba.csp.sentinel.adapter.dubbo.SentinelDubboConsumerFilter +dubbo.application.context.name.filter=com.alibaba.csp.sentinel.adapter.dubbo.DubboAppContextFilter diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/BaseTest.java b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/BaseTest.java new file mode 100644 index 0000000000..a61f3b4c80 --- /dev/null +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/BaseTest.java @@ -0,0 +1,40 @@ +/* + * 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; + +import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot; + +import org.apache.dubbo.rpc.RpcContext; + +/** + * Base test class, provide common methods for subClass + * The package is same as CtSph, to call CtSph.resetChainMap() method for test + * + * Note: Only for test. DO NOT USE IN PRODUCTION! + * + * @author cdfive + */ +public class BaseTest { + + /** + * Clean up resources for context, clusterNodeMap, processorSlotChainMap + */ + protected static void cleanUpAll() { + RpcContext.removeContext(); + ClusterBuilderSlot.getClusterNodeMap().clear(); + CtSph.resetChainMap(); + } +} \ No newline at end of file diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboAppContextFilterTest.java b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboAppContextFilterTest.java new file mode 100644 index 0000000000..8c8721e1e8 --- /dev/null +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboAppContextFilterTest.java @@ -0,0 +1,75 @@ +/* + * 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.dubbo; + +import com.alibaba.csp.sentinel.BaseTest; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.RpcContext; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +/** + * @author cdfive + */ +public class DubboAppContextFilterTest extends BaseTest { + + private DubboAppContextFilter filter = new DubboAppContextFilter(); + + @Before + public void setUp() { + cleanUpAll(); + } + + @After + public void cleanUp() { + cleanUpAll(); + } + + @Test + public void testInvokeApplicationKey() { + Invoker invoker = mock(Invoker.class); + Invocation invocation = mock(Invocation.class); + URL url = URL.valueOf("test://test:111/test?application=serviceA"); + when(invoker.getUrl()).thenReturn(url); + + filter.invoke(invoker, invocation); + verify(invoker).invoke(invocation); + + String application = RpcContext.getContext().getAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY); + assertEquals("serviceA", application); + } + + @Test + public void testInvokeNullApplicationKey() { + Invoker invoker = mock(Invoker.class); + Invocation invocation = mock(Invocation.class); + URL url = URL.valueOf("test://test:111/test?application="); + when(invoker.getUrl()).thenReturn(url); + + filter.invoke(invoker, invocation); + verify(invoker).invoke(invocation); + + String application = RpcContext.getContext().getAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY); + assertNull(application); + } +} diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtilsTest.java b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtilsTest.java new file mode 100644 index 0000000000..8d3636f180 --- /dev/null +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtilsTest.java @@ -0,0 +1,75 @@ +/* + * 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.dubbo; + +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.Invoker; +import org.junit.Test; + +import java.lang.reflect.Method; +import java.util.HashMap; + +import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.*; + +/** + * @author cdfive + */ +public class DubboUtilsTest { + + @Test + public void testGetApplication() { + Invocation invocation = mock(Invocation.class); + when(invocation.getAttachments()).thenReturn(new HashMap<>()); + when(invocation.getAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, "")) + .thenReturn("consumerA"); + + String application = DubboUtils.getApplication(invocation, ""); + verify(invocation).getAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, ""); + + assertEquals("consumerA", application); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetApplicationNoAttachments() { + Invocation invocation = mock(Invocation.class); + when(invocation.getAttachments()).thenReturn(null); + when(invocation.getAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, "")) + .thenReturn("consumerA"); + + DubboUtils.getApplication(invocation, ""); + + fail("No attachments in invocation, IllegalArgumentException should be thrown!"); + } + + @Test + public void testGetResourceName() { + Invoker invoker = mock(Invoker.class); + when(invoker.getInterface()).thenReturn(DemoService.class); + + Invocation invocation = mock(Invocation.class); + Method method = DemoService.class.getMethods()[0]; + when(invocation.getMethodName()).thenReturn(method.getName()); + when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes()); + + String resourceName = DubboUtils.getResourceName(invoker, invocation); + + assertEquals("com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName); + } +} diff --git a/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilterTest.java b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilterTest.java new file mode 100644 index 0000000000..e4b30b95e0 --- /dev/null +++ b/sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilterTest.java @@ -0,0 +1,142 @@ +/* + * 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.dubbo; + +import com.alibaba.csp.sentinel.BaseTest; +import com.alibaba.csp.sentinel.Constants; +import com.alibaba.csp.sentinel.Entry; +import com.alibaba.csp.sentinel.EntryType; +import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService; +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 org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.Result; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +/** + * @author cdfive + */ +public class SentinelDubboConsumerFilterTest extends BaseTest { + + private SentinelDubboConsumerFilter filter = new SentinelDubboConsumerFilter(); + + @Before + public void setUp() { + cleanUpAll(); + } + + @After + public void cleanUp() { + cleanUpAll(); + } + + @Test + public void testInvoke() { + final Invoker invoker = mock(Invoker.class); + when(invoker.getInterface()).thenReturn(DemoService.class); + + final Invocation invocation = mock(Invocation.class); + Method method = DemoService.class.getMethods()[0]; + when(invocation.getMethodName()).thenReturn(method.getName()); + when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes()); + + final Result result = mock(Result.class); + when(result.hasException()).thenReturn(false); + when(invoker.invoke(invocation)).thenAnswer(invocationOnMock -> { + verifyInvocationStructure(invoker, invocation); + return result; + }); + + filter.invoke(invoker, invocation); + verify(invoker).invoke(invocation); + + Context context = ContextUtil.getContext(); + assertNull(context); + } + + /** + * Simply verify invocation structure in memory: + * EntranceNode(defaultContextName) + * --InterfaceNode(interfaceName) + * ----MethodNode(resourceName) + */ + private void verifyInvocationStructure(Invoker invoker, Invocation invocation) { + Context context = ContextUtil.getContext(); + assertNotNull(context); + + // As not call ContextUtil.enter(resourceName, application) in SentinelDubboConsumerFilter, use default context + // In actual project, a consumer is usually also a provider, the context will be created by SentinelDubboProviderFilter + // If consumer is on the top of Dubbo RPC invocation chain, use default context + String resourceName = DubboUtils.getResourceName(invoker, invocation); + 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.getType()); + + // As SphU.entry(interfaceName, EntryType.OUT); + Set+ * -Djava.net.preferIPv4Stack=true + * -Dcsp.sentinel.api.port=8721 + * -Dproject.name=dubbo-consumer-demo + *+ * + * @author Eric Zhao + */ +public class FooConsumerBootstrap { + + public static void main(String[] args) { + AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(); + consumerContext.register(ConsumerConfiguration.class); + consumerContext.refresh(); + + FooServiceConsumer service = consumerContext.getBean(FooServiceConsumer.class); + + for (int i = 0; i < 15; i++) { + try { + String message = service.sayHello("Eric"); + System.out.println("Success: " + message); + } catch (SentinelRpcException ex) { + System.out.println("Blocked"); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } +} diff --git a/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/FooProviderBootstrap.java b/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/FooProviderBootstrap.java new file mode 100644 index 0000000000..a23c0ed05e --- /dev/null +++ b/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/FooProviderBootstrap.java @@ -0,0 +1,63 @@ +/* + * 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.apache.dubbo; + +import java.util.Collections; + +import com.alibaba.csp.sentinel.demo.apache.dubbo.provider.ProviderConfiguration; +import com.alibaba.csp.sentinel.init.InitExecutor; +import com.alibaba.csp.sentinel.slots.block.RuleConstant; +import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; +import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +/** + * Provider demo for Apache Dubbo 2.7.x or above. Please add the following VM arguments: + *
+ * -Djava.net.preferIPv4Stack=true + * -Dcsp.sentinel.api.port=8720 + * -Dproject.name=dubbo-provider-demo + *+ * + * @author Eric Zhao + */ +public class FooProviderBootstrap { + + private static final String INTERFACE_RES_KEY = FooService.class.getName(); + private static final String RES_KEY = INTERFACE_RES_KEY + ":sayHello(java.lang.String)"; + + public static void main(String[] args) { + // Users don't need to manually call this method. + // Only for eager initialization. + InitExecutor.doInit(); + + initFlowRule(); + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(ProviderConfiguration.class); + context.refresh(); + + System.out.println("Service provider is ready"); + } + + private static void initFlowRule() { + FlowRule flowRule = new FlowRule(INTERFACE_RES_KEY) + .setCount(10) + .setGrade(RuleConstant.FLOW_GRADE_QPS); + FlowRuleManager.loadRules(Collections.singletonList(flowRule)); + } +} diff --git a/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/FooService.java b/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/FooService.java new file mode 100644 index 0000000000..dcdabc8c7c --- /dev/null +++ b/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/FooService.java @@ -0,0 +1,26 @@ +/* + * 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.apache.dubbo; + +/** + * @author Eric Zhao + */ +public interface FooService { + + String sayHello(String name); + + String doAnother(); +} diff --git a/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/consumer/ConsumerConfiguration.java b/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/consumer/ConsumerConfiguration.java new file mode 100644 index 0000000000..6e356dfcaf --- /dev/null +++ b/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/consumer/ConsumerConfiguration.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.demo.apache.dubbo.consumer; + + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ConsumerConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author Eric Zhao + */ +@Configuration +@DubboComponentScan +public class ConsumerConfiguration { + @Bean + public ApplicationConfig applicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("demo-consumer"); + return applicationConfig; + } + + @Bean + public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress("multicast://224.5.6.7:1234"); + return registryConfig; + } + + @Bean + public ConsumerConfig consumerConfig() { + ConsumerConfig consumerConfig = new ConsumerConfig(); + // Uncomment below line if you don't want to enable Sentinel for Dubbo service consumers. + // consumerConfig.setFilter("-sentinel.dubbo.consumer.filter"); + return consumerConfig; + } + + @Bean + public FooServiceConsumer annotationDemoServiceConsumer() { + return new FooServiceConsumer(); + } +} diff --git a/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/consumer/FooServiceConsumer.java b/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/consumer/FooServiceConsumer.java new file mode 100644 index 0000000000..f83d98a008 --- /dev/null +++ b/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/consumer/FooServiceConsumer.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.demo.apache.dubbo.consumer; + +import com.alibaba.csp.sentinel.demo.apache.dubbo.FooService; + +import org.apache.dubbo.config.annotation.Reference; + +/** + * @author Eric Zhao + */ +public class FooServiceConsumer { + + @Reference(url = "dubbo://127.0.0.1:25758", timeout = 3000) + private FooService fooService; + + public String sayHello(String name) { + return fooService.sayHello(name); + } + + public String doAnother() { + return fooService.doAnother(); + } +} diff --git a/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/provider/FooServiceImpl.java b/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/provider/FooServiceImpl.java new file mode 100644 index 0000000000..bd92567aa9 --- /dev/null +++ b/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/provider/FooServiceImpl.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.demo.apache.dubbo.provider; + +import java.time.LocalDateTime; + +import com.alibaba.csp.sentinel.demo.apache.dubbo.FooService; + +import org.apache.dubbo.config.annotation.Service; + +/** + * @author Eric Zhao + */ +@Service +public class FooServiceImpl implements FooService { + + @Override + public String sayHello(String name) { + return String.format("Hello, %s at %s", name, LocalDateTime.now()); + } + + @Override + public String doAnother() { + return LocalDateTime.now().toString(); + } +} diff --git a/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/provider/ProviderConfiguration.java b/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/provider/ProviderConfiguration.java new file mode 100644 index 0000000000..ecb4539d15 --- /dev/null +++ b/sentinel-demo/sentinel-demo-apache-dubbo/src/main/java/com/alibaba/csp/sentinel/demo/apache/dubbo/provider/ProviderConfiguration.java @@ -0,0 +1,53 @@ +/* + * 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.apache.dubbo.provider; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author Eric Zhao + */ +@Configuration +@DubboComponentScan +public class ProviderConfiguration { + + @Bean + public ApplicationConfig applicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("demo-provider"); + return applicationConfig; + } + + @Bean + public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress("multicast://224.5.6.7:1234"); + return registryConfig; + } + + @Bean + public ProtocolConfig protocolConfig() { + ProtocolConfig protocolConfig = new ProtocolConfig(); + protocolConfig.setName("dubbo"); + protocolConfig.setPort(25758); + return protocolConfig; + } +}