Initial commit for Sentinel Dubbo Adapter

Signed-off-by: Eric Zhao <sczyh16@gmail.com>
diff --git a/.gitignore b/.gitignore
index a1c2a23..378800f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,23 +1,26 @@
-# Compiled class file
-*.class
+# IntelliJ project files
+.idea/
+*.iml
+out
+gen
 
-# Log file
-*.log
+# Maven
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+!/.mvn/wrapper/maven-wrapper.jar
 
-# BlueJ files
-*.ctxt
+# Eclipse
+.classpath
+.settings/
+.project
 
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
-
-# Package Files #
-*.jar
-*.war
-*.nar
-*.ear
-*.zip
-*.tar.gz
-*.rar
-
-# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
-hs_err_pid*
+# System related
+*.DS_Store
+Thumbs.db
diff --git a/README.md b/README.md
index 9b0be3d..d112457 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,53 @@
-# dubbo-sentinel-support
\ No newline at end of file
+# Sentinel Dubbo Adapter
+
+Sentinel Dubbo Adapter provides service consumer filter and provider filter
+for [Dubbo](http://dubbo.io/) services. 
+
+To use Sentinel Dubbo Adapter, you can simply add the following dependency to your `pom.xml`:
+
+```xml
+<dependency>
+    <groupId>com.alibaba.csp</groupId>
+    <artifactId>sentinel-dubbo-adapter</artifactId>
+    <version>x.y.z</version>
+</dependency>
+```
+
+The Sentinel filters are **enabled by default**. Once you add the dependency,
+the Dubbo 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-dubbo](https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-dubbo).
+
+If you don't want the filters enabled, you can manually disable them. For example:
+
+```xml
+<dubbo:consumer filter="-sentinel.dubbo.consumer.filter"/>
+
+<dubbo:provider filter="-sentinel.dubbo.provider.filter"/>
+```
+
+For more details of Dubbo filter, see [here](https://dubbo.incubator.apache.org/#/docs/dev/impls/filter.md?lang=en-us).
+
+## Dubbo resources
+
+The resource for Dubbo services has two granularities: service interface and service method.
+
+- Service interface:resourceName format is `interfaceName`,e.g. `com.alibaba.csp.sentinel.demo.dubbo.FooService`
+- Service method:resourceName format is `interfaceName:methodSignature`,e.g. `com.alibaba.csp.sentinel.demo.dubbo.FooService:sayHello(java.lang.String)`
+
+## 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 Dubbo Adapter will automatically resolve the Dubbo 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.
+
+> Note: Dubbo consumer does not provide its Dubbo application name when doing RPC,
+so developers should manually put the application name into *attachment* at consumer side,
+then extract it at provider side. Sentinel Dubbo Adapter has implemented a filter (`DubboAppContextFilter`)
+where consumer can carry application name information to provider automatically.
+If the consumer does not use Sentinel Dubbo Adapter but requires flow control based on caller, developers can manually put the application name into attachment with the key `dubboApplication`.
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..a7ed335
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.alibaba.csp</groupId>
+        <artifactId>sentinel-adapter</artifactId>
+        <version>0.1.0</version>
+    </parent>
+    <artifactId>sentinel-dubbo-adapter</artifactId>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>dubbo</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.47</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+
+</project>
\ No newline at end of file
diff --git a/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/AbstractDubboFilter.java b/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/AbstractDubboFilter.java
new file mode 100755
index 0000000..2400b3c
--- /dev/null
+++ b/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/AbstractDubboFilter.java
@@ -0,0 +1,29 @@
+package com.alibaba.csp.sentinel.adapter.dubbo;
+
+import com.alibaba.dubbo.rpc.Filter;
+import com.alibaba.dubbo.rpc.Invocation;
+import com.alibaba.dubbo.rpc.Invoker;
+
+/**
+ * @author leyou
+ */
+abstract class AbstractDubboFilter implements Filter {
+
+    protected String getResourceName(Invoker<?> invoker, Invocation invocation) {
+        StringBuilder buf = new StringBuilder(64);
+        buf.append(invoker.getInterface().getName())
+            .append(":")
+            .append(invocation.getMethodName())
+            .append("(");
+        boolean isFirst = true;
+        for (Class<?> clazz : invocation.getParameterTypes()) {
+            if (!isFirst) {
+                buf.append(",");
+            }
+            buf.append(clazz.getName());
+            isFirst = false;
+        }
+        buf.append(")");
+        return buf.toString();
+    }
+}
diff --git a/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboAppContextFilter.java b/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboAppContextFilter.java
new file mode 100644
index 0000000..36835cc
--- /dev/null
+++ b/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboAppContextFilter.java
@@ -0,0 +1,28 @@
+package com.alibaba.csp.sentinel.adapter.dubbo;
+
+import com.alibaba.dubbo.common.Constants;
+import com.alibaba.dubbo.common.extension.Activate;
+import com.alibaba.dubbo.rpc.Filter;
+import com.alibaba.dubbo.rpc.Invocation;
+import com.alibaba.dubbo.rpc.Invoker;
+import com.alibaba.dubbo.rpc.Result;
+import com.alibaba.dubbo.rpc.RpcContext;
+import com.alibaba.dubbo.rpc.RpcException;
+
+/**
+ * Puts current consumer's application name in the attachment of each invocation.
+ *
+ * @author Eric Zhao
+ */
+@Activate(group = "consumer")
+public class DubboAppContextFilter implements Filter {
+
+    @Override
+    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
+        String application = invoker.getUrl().getParameter(Constants.APPLICATION_KEY);
+        if (application != null) {
+            RpcContext.getContext().setAttachment(DubboUtils.DUBBO_APPLICATION_KEY, application);
+        }
+        return invoker.invoke(invocation);
+    }
+}
diff --git a/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtils.java b/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtils.java
new file mode 100644
index 0000000..73fd51b
--- /dev/null
+++ b/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboUtils.java
@@ -0,0 +1,20 @@
+package com.alibaba.csp.sentinel.adapter.dubbo;
+
+import com.alibaba.dubbo.rpc.Invocation;
+
+/**
+ * @author Eric Zhao
+ */
+public final class DubboUtils {
+
+    public static final String DUBBO_APPLICATION_KEY = "dubboApplication";
+
+    public static String getApplication(Invocation invocation, String defaultValue) {
+        if (invocation == null || invocation.getAttachments() == null) {
+            throw new IllegalArgumentException("Bad invocation instance");
+        }
+        return invocation.getAttachment(DUBBO_APPLICATION_KEY, defaultValue);
+    }
+
+    private DubboUtils() {}
+}
diff --git a/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilter.java b/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilter.java
new file mode 100755
index 0000000..2f79b04
--- /dev/null
+++ b/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboConsumerFilter.java
@@ -0,0 +1,55 @@
+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.context.ContextUtil;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
+import com.alibaba.dubbo.common.extension.Activate;
+import com.alibaba.dubbo.rpc.Filter;
+import com.alibaba.dubbo.rpc.Invocation;
+import com.alibaba.dubbo.rpc.Invoker;
+import com.alibaba.dubbo.rpc.Result;
+import com.alibaba.dubbo.rpc.RpcException;
+
+/**
+ * <p>Dubbo service consumer filter for Sentinel. Auto activated by default.</p>
+ *
+ * If you want to disable the consumer filter, you can configure:
+ * <pre>
+ * &lt;dubbo:consumer filter="-sentinel.dubbo.consumer.filter"/&gt;
+ * </pre>
+ *
+ * @author leyou
+ */
+@Activate(group = "consumer")
+public class SentinelDubboConsumerFilter extends AbstractDubboFilter implements Filter {
+
+    @Override
+    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
+        Entry interfaceEntry = null;
+        Entry methodEntry = null;
+        try {
+            String resourceName = getResourceName(invoker, invocation);
+            ContextUtil.enter(resourceName);
+            interfaceEntry = SphU.entry(invoker.getInterface().getName(), EntryType.OUT);
+            methodEntry = SphU.entry(resourceName, EntryType.OUT);
+            return invoker.invoke(invocation);
+        } catch (BlockException e) {
+            throw new SentinelRpcException(e);
+        } catch (RpcException e) {
+            Tracer.trace(e);
+            throw e;
+        } finally {
+            if (methodEntry != null) {
+                methodEntry.exit();
+            }
+            if (interfaceEntry != null) {
+                interfaceEntry.exit();
+            }
+            ContextUtil.exit();
+        }
+    }
+}
diff --git a/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilter.java b/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilter.java
new file mode 100755
index 0000000..8c3951f
--- /dev/null
+++ b/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/SentinelDubboProviderFilter.java
@@ -0,0 +1,60 @@
+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.context.ContextUtil;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
+import com.alibaba.dubbo.common.extension.Activate;
+import com.alibaba.dubbo.rpc.Filter;
+import com.alibaba.dubbo.rpc.Invocation;
+import com.alibaba.dubbo.rpc.Invoker;
+import com.alibaba.dubbo.rpc.Result;
+import com.alibaba.dubbo.rpc.RpcException;
+
+/**
+ * <p>Dubbo service provider filter for Sentinel. Auto activated by default.</p>
+ *
+ * If you want to disable the provider filter, you can configure:
+ * <pre>
+ * &lt;dubbo:provider filter="-sentinel.dubbo.provider.filter"/&gt;
+ * </pre>
+ *
+ * @author leyou
+ */
+@Activate(group = "provider")
+public class SentinelDubboProviderFilter extends AbstractDubboFilter implements Filter {
+
+    @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 = getResourceName(invoker, invocation);
+            String interfaceName = invoker.getInterface().getName();
+            ContextUtil.enter(resourceName, application);
+            interfaceEntry = SphU.entry(interfaceName, EntryType.IN);
+            methodEntry = SphU.entry(resourceName, EntryType.IN, 1, invocation.getArguments());
+
+            return invoker.invoke(invocation);
+        } catch (BlockException e) {
+            throw new SentinelRpcException(e);
+        } catch (RpcException e) {
+            Tracer.trace(e);
+            throw e;
+        } finally {
+            if (methodEntry != null) {
+                methodEntry.exit(1, invocation.getArguments());
+            }
+            if (interfaceEntry != null) {
+                interfaceEntry.exit();
+            }
+            ContextUtil.exit();
+        }
+    }
+}
diff --git a/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter b/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter
new file mode 100755
index 0000000..af7c961
--- /dev/null
+++ b/src/main/resources/META-INF/dubbo/com.alibaba.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
\ No newline at end of file
diff --git a/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DemoService.java b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DemoService.java
new file mode 100755
index 0000000..8ccc4a0
--- /dev/null
+++ b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DemoService.java
@@ -0,0 +1,8 @@
+package com.alibaba.csp.sentinel.adapter.dubbo;
+
+/**
+ * @author leyou
+ */
+public interface DemoService {
+    String sayHello(String name, int n);
+}
diff --git a/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboConsumerTest.java b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboConsumerTest.java
new file mode 100755
index 0000000..4ba0a4d
--- /dev/null
+++ b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboConsumerTest.java
@@ -0,0 +1,74 @@
+package com.alibaba.csp.sentinel.adapter.dubbo;
+
+import java.util.Arrays;
+
+import com.alibaba.csp.sentinel.node.ClusterNode;
+import com.alibaba.csp.sentinel.slots.block.RuleConstant;
+import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
+import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * 运行该用例的时候需要加入JVM参数:-Djava.net.preferIPv4Stack=true,
+ * 否则可能会抛出{@code java.lang.IllegalStateException: Can't assign requested address}
+ *
+ * @author leyou
+ */
+public class DubboConsumerTest {
+    private final String resource = "com.alibaba.csp.sentinel.adapter.dubbo.DemoService:sayHello(java.lang.String,int)";
+    private final String interfaceResource = "com.alibaba.csp.sentinel.adapter.dubbo.DemoService";
+    private ClassPathXmlApplicationContext context;
+
+    @Before
+    public void init() {
+        context = new ClassPathXmlApplicationContext(
+            new String[] {"spring-dubbo-consumer-filter.xml"});
+        context.start();
+    }
+
+    @Test
+    public void testConsumerFilter() throws Exception {
+        DemoService demoService = (DemoService)context.getBean("demoService");
+        String result = demoService.sayHello("Test dubbo consumer filter", 2);
+        System.out.println("result=" + result);
+        ClusterNode node = ClusterBuilderSlot.getClusterNode(resource);
+        Assert.assertNotNull(node);
+    }
+
+    @Test(expected = SentinelRpcException.class)
+    public void testConsumerBlock() throws Exception {
+        FlowRule flowRule = new FlowRule();
+        flowRule.setResource(resource);
+        flowRule.setCount(10);
+        flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
+        flowRule.setLimitApp("default");
+        FlowRuleManager.loadRules(Arrays.asList(flowRule));
+
+        DemoService demoService = (DemoService)context.getBean("demoService");
+        for (int i = 0; i < 100; i++) {
+            demoService.sayHello("Test dubbo consumer filter", 2);
+        }
+    }
+
+    @Test(expected = SentinelRpcException.class)
+    public void testConsumerBlock2() throws Exception {
+        FlowRule flowRule = new FlowRule();
+        flowRule.setResource(interfaceResource);
+        flowRule.setCount(10);
+        flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
+        flowRule.setLimitApp("default");
+        FlowRuleManager.loadRules(Arrays.asList(flowRule));
+
+        DemoService demoService = (DemoService)context.getBean("demoService");
+        for (int i = 0; i < 100; i++) {
+            demoService.sayHello("Test dubbo consumer filter", 2);
+        }
+    }
+
+}
diff --git a/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboProviderTest.java b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboProviderTest.java
new file mode 100755
index 0000000..8c4657e
--- /dev/null
+++ b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboProviderTest.java
@@ -0,0 +1,32 @@
+package com.alibaba.csp.sentinel.adapter.dubbo;
+
+import com.alibaba.csp.sentinel.node.ClusterNode;
+import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * 运行该用例的时候需要加入JVM参数:-Djava.net.preferIPv4Stack=true,
+ * 否则可能会抛出{@code java.lang.IllegalStateException: Can't assign requested address}
+ *
+ * @author leyou
+ */
+public class DubboProviderTest {
+
+    private final String resource = "com.alibaba.csp.sentinel.adapter.dubbo.DemoService:sayHello(java.lang.String,int)";
+
+    @Test
+    public void testProviderFilter() throws Exception {
+        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
+            new String[] {"spring-dubbo-provider-filter.xml"});
+        context.start();
+        DemoService demoService = (DemoService)context.getBean("demoService");
+        String result = demoService.sayHello("Test dubbo provider filter", 1);
+        System.out.println("result=" + result);
+        ClusterNode node = ClusterBuilderSlot.getClusterNode(resource);
+        Thread.sleep(1000 * 60 * 100);
+        Assert.assertNotNull(node);
+    }
+}
diff --git a/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/DemoServiceImpl.java b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/DemoServiceImpl.java
new file mode 100755
index 0000000..db566e7
--- /dev/null
+++ b/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/provider/DemoServiceImpl.java
@@ -0,0 +1,12 @@
+package com.alibaba.csp.sentinel.adapter.dubbo.provider;
+
+import com.alibaba.csp.sentinel.adapter.dubbo.DemoService;
+
+/**
+ * @author leyou
+ */
+public class DemoServiceImpl implements DemoService {
+    public String sayHello(String name, int n) {
+        return "Hello " + name + ", " + n;
+    }
+}
diff --git a/src/test/resources/spring-dubbo-consumer-filter.xml b/src/test/resources/spring-dubbo-consumer-filter.xml
new file mode 100755
index 0000000..ae0a89d
--- /dev/null
+++ b/src/test/resources/spring-dubbo-consumer-filter.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+       http://www.springframework.org/schema/beans/spring-beans.xsd
+       http://code.alibabatech.com/schema/dubbo
+       http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
+
+    <dubbo:application name="demo-consumer"/>
+    <dubbo:registry address="multicast://224.5.6.7:1234"/>
+    <dubbo:protocol name="dubbo" port="20880"/>
+    <dubbo:service interface="com.alibaba.csp.sentinel.adapter.dubbo.DemoService" ref="demoServiceImp" />
+    <bean id="demoServiceImp" class="com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoServiceImpl"/>
+
+    <dubbo:reference id="demoService" interface="com.alibaba.csp.sentinel.adapter.dubbo.DemoService"/>
+
+    <dubbo:consumer filter="sentinel.dubbo.consumer.filter" />
+
+</beans>
\ No newline at end of file
diff --git a/src/test/resources/spring-dubbo-provider-filter.xml b/src/test/resources/spring-dubbo-provider-filter.xml
new file mode 100755
index 0000000..0990c39
--- /dev/null
+++ b/src/test/resources/spring-dubbo-provider-filter.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+       http://www.springframework.org/schema/beans/spring-beans.xsd
+       http://code.alibabatech.com/schema/dubbo
+       http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
+
+    <dubbo:application name="demo-provider"/>
+    <dubbo:registry address="multicast://224.5.6.7:1234"/>
+    <dubbo:protocol name="dubbo" port="20880"/>
+    <dubbo:service interface="com.alibaba.csp.sentinel.adapter.dubbo.DemoService" ref="demoServiceImp" />
+    <bean id="demoServiceImp" class="com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoServiceImpl"/>
+
+    <dubbo:reference id="demoService" interface="com.alibaba.csp.sentinel.adapter.dubbo.DemoService"/>
+
+    <dubbo:provider filter="sentinel.dubbo.provider.filter" />
+
+</beans>
\ No newline at end of file