init
This commit is contained in:
		
							
								
								
									
										72
									
								
								sentinel/sentinel-adapter/sentinel-dubbo-adapter/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								sentinel/sentinel-adapter/sentinel-dubbo-adapter/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
			
		||||
# Sentinel Dubbo Adapter
 | 
			
		||||
 | 
			
		||||
> Note: 中文文档请见[此处](https://github.com/alibaba/Sentinel/wiki/主流框架的适配#dubbo)。
 | 
			
		||||
 | 
			
		||||
Sentinel Dubbo Adapter provides service consumer filter and provider filter
 | 
			
		||||
for [Dubbo](https://dubbo.apache.org/en-us/) services.
 | 
			
		||||
 | 
			
		||||
**Note: This adapter only supports legacy Dubbo 2.6.x version and below.**
 | 
			
		||||
For new Apache Dubbo 2.7.x or above version, please use `sentinel-apache-dubbo-adapter` module instead.
 | 
			
		||||
 | 
			
		||||
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](http://dubbo.apache.org/en-us/docs/dev/impls/filter.html).
 | 
			
		||||
 | 
			
		||||
## 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`.
 | 
			
		||||
>
 | 
			
		||||
> Since 1.8.0, the adapter provides support for customizing origin parsing logic. You may register your own `DubboOriginParser`
 | 
			
		||||
> implementation to `DubboAdapterGlobalConfig`.
 | 
			
		||||
 | 
			
		||||
## Global fallback
 | 
			
		||||
 | 
			
		||||
Sentinel Dubbo 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 `DubboFallback` interface
 | 
			
		||||
and then register to `DubboAdapterGlobalConfig`.
 | 
			
		||||
If no fallback is configured, Sentinel will wrap the `BlockException` as the fallback result.
 | 
			
		||||
 | 
			
		||||
Besides, we can also leverage [Dubbo mock mechanism](http://dubbo.apache.org/en-us/docs/user/demos/local-mock.html) to provide fallback implementation of degraded Dubbo services.
 | 
			
		||||
							
								
								
									
										48
									
								
								sentinel/sentinel-adapter/sentinel-dubbo-adapter/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								sentinel/sentinel-adapter/sentinel-dubbo-adapter/pom.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
<?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">
 | 
			
		||||
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>com.alibaba.csp</groupId>
 | 
			
		||||
        <artifactId>sentinel-adapter</artifactId>
 | 
			
		||||
        <version>1.8.3</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
    <modelVersion>4.0.0</modelVersion>
 | 
			
		||||
    <artifactId>sentinel-dubbo-adapter</artifactId>
 | 
			
		||||
    <packaging>jar</packaging>
 | 
			
		||||
 | 
			
		||||
    <properties>
 | 
			
		||||
        <dubbo.version>2.6.6</dubbo.version>
 | 
			
		||||
    </properties>
 | 
			
		||||
 | 
			
		||||
    <dependencies>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.alibaba.csp</groupId>
 | 
			
		||||
            <artifactId>sentinel-core</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.alibaba</groupId>
 | 
			
		||||
            <artifactId>dubbo</artifactId>
 | 
			
		||||
            <version>${dubbo.version}</version>
 | 
			
		||||
            <scope>provided</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>junit</groupId>
 | 
			
		||||
            <artifactId>junit</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.mockito</groupId>
 | 
			
		||||
            <artifactId>mockito-core</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.alibaba</groupId>
 | 
			
		||||
            <artifactId>fastjson</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
    </dependencies>
 | 
			
		||||
</project>
 | 
			
		||||
@@ -0,0 +1,66 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.util.StringUtil;
 | 
			
		||||
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 getMethodResourceName(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();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected String getMethodResourceName(Invoker<?> invoker, Invocation invocation, String prefix) {
 | 
			
		||||
        if (StringUtil.isBlank(prefix)) {
 | 
			
		||||
            return getMethodResourceName(invoker, invocation);
 | 
			
		||||
        }
 | 
			
		||||
        StringBuilder buf = new StringBuilder(64);
 | 
			
		||||
        return buf.append(prefix)
 | 
			
		||||
            .append(getMethodResourceName(invoker, invocation))
 | 
			
		||||
            .toString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected String getInterfaceName(Invoker<?> invoker) {
 | 
			
		||||
        return invoker.getInterface().getName();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected String getInterfaceName(Invoker<?> invoker, String prefix) {
 | 
			
		||||
        if (StringUtil.isBlank(prefix)) {
 | 
			
		||||
            return getInterfaceName(invoker);
 | 
			
		||||
        }
 | 
			
		||||
        return prefix + getInterfaceName(invoker);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,108 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.adapter.dubbo.fallback.DefaultDubboFallback;
 | 
			
		||||
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallback;
 | 
			
		||||
import com.alibaba.csp.sentinel.adapter.dubbo.origin.DefaultDubboOriginParser;
 | 
			
		||||
import com.alibaba.csp.sentinel.adapter.dubbo.origin.DubboOriginParser;
 | 
			
		||||
import com.alibaba.csp.sentinel.config.SentinelConfig;
 | 
			
		||||
import com.alibaba.csp.sentinel.util.AssertUtil;
 | 
			
		||||
import com.alibaba.csp.sentinel.util.StringUtil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * <p>Global config and callback registry of Dubbo legacy adapter.</p>
 | 
			
		||||
 *
 | 
			
		||||
 * @author lianglin
 | 
			
		||||
 * @author Eric Zhao
 | 
			
		||||
 * @since 1.7.0
 | 
			
		||||
 */
 | 
			
		||||
public final class DubboAdapterGlobalConfig {
 | 
			
		||||
 | 
			
		||||
    private static final String TRUE_STR = "true";
 | 
			
		||||
 | 
			
		||||
    public static final String DUBBO_RES_NAME_WITH_PREFIX_KEY = "csp.sentinel.dubbo.resource.use.prefix";
 | 
			
		||||
    public static final String DUBBO_PROVIDER_RES_NAME_PREFIX_KEY = "csp.sentinel.dubbo.resource.provider.prefix";
 | 
			
		||||
    public static final String DUBBO_CONSUMER_RES_NAME_PREFIX_KEY = "csp.sentinel.dubbo.resource.consumer.prefix";
 | 
			
		||||
 | 
			
		||||
    private static final String DEFAULT_DUBBO_PROVIDER_PREFIX = "dubbo:provider:";
 | 
			
		||||
    private static final String DEFAULT_DUBBO_CONSUMER_PREFIX = "dubbo:consumer:";
 | 
			
		||||
 | 
			
		||||
    private static volatile DubboFallback consumerFallback = new DefaultDubboFallback();
 | 
			
		||||
    private static volatile DubboFallback providerFallback = new DefaultDubboFallback();
 | 
			
		||||
    private static volatile DubboOriginParser originParser = new DefaultDubboOriginParser();
 | 
			
		||||
 | 
			
		||||
    public static boolean isUsePrefix() {
 | 
			
		||||
        return TRUE_STR.equalsIgnoreCase(SentinelConfig.getConfig(DUBBO_RES_NAME_WITH_PREFIX_KEY));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String getDubboProviderPrefix() {
 | 
			
		||||
        if (isUsePrefix()) {
 | 
			
		||||
            String config = SentinelConfig.getConfig(DUBBO_PROVIDER_RES_NAME_PREFIX_KEY);
 | 
			
		||||
            return StringUtil.isNotBlank(config) ? config : DEFAULT_DUBBO_PROVIDER_PREFIX;
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String getDubboConsumerPrefix() {
 | 
			
		||||
        if (isUsePrefix()) {
 | 
			
		||||
            String config = SentinelConfig.getConfig(DUBBO_CONSUMER_RES_NAME_PREFIX_KEY);
 | 
			
		||||
            return StringUtil.isNotBlank(config) ? config : DEFAULT_DUBBO_CONSUMER_PREFIX;
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static DubboFallback getConsumerFallback() {
 | 
			
		||||
        return consumerFallback;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void setConsumerFallback(DubboFallback consumerFallback) {
 | 
			
		||||
        AssertUtil.notNull(consumerFallback, "consumerFallback cannot be null");
 | 
			
		||||
        DubboAdapterGlobalConfig.consumerFallback = consumerFallback;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static DubboFallback getProviderFallback() {
 | 
			
		||||
        return providerFallback;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void setProviderFallback(DubboFallback providerFallback) {
 | 
			
		||||
        AssertUtil.notNull(providerFallback, "providerFallback cannot be null");
 | 
			
		||||
        DubboAdapterGlobalConfig.providerFallback = providerFallback;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the origin parser of Dubbo adapter.
 | 
			
		||||
     *
 | 
			
		||||
     * @return the origin parser
 | 
			
		||||
     * @since 1.8.0
 | 
			
		||||
     */
 | 
			
		||||
    public static DubboOriginParser getOriginParser() {
 | 
			
		||||
        return originParser;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the origin parser of Dubbo adapter.
 | 
			
		||||
     *
 | 
			
		||||
     * @param originParser the origin parser
 | 
			
		||||
     * @since 1.8.0
 | 
			
		||||
     */
 | 
			
		||||
    public static void setOriginParser(DubboOriginParser originParser) {
 | 
			
		||||
        AssertUtil.notNull(originParser, "originParser cannot be null");
 | 
			
		||||
        DubboAdapterGlobalConfig.originParser = originParser;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private DubboAdapterGlobalConfig() {}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,45 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.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;
 | 
			
		||||
 | 
			
		||||
import static com.alibaba.dubbo.common.Constants.CONSUMER;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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;
 | 
			
		||||
 | 
			
		||||
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() {}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,87 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.ResourceTypeConstants;
 | 
			
		||||
import com.alibaba.csp.sentinel.SphU;
 | 
			
		||||
import com.alibaba.csp.sentinel.Tracer;
 | 
			
		||||
import com.alibaba.csp.sentinel.log.RecordLog;
 | 
			
		||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
import static com.alibaba.dubbo.common.Constants.CONSUMER;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * <p>Dubbo service consumer filter for Sentinel. Auto activated by default.</p>
 | 
			
		||||
 *
 | 
			
		||||
 * If you want to disable the consumer filter, you can configure:
 | 
			
		||||
 * <pre>
 | 
			
		||||
 * <dubbo:consumer filter="-sentinel.dubbo.consumer.filter"/>
 | 
			
		||||
 * </pre>
 | 
			
		||||
 *
 | 
			
		||||
 * @author leyou
 | 
			
		||||
 * @author Eric Zhao
 | 
			
		||||
 */
 | 
			
		||||
@Activate(group = CONSUMER)
 | 
			
		||||
public class SentinelDubboConsumerFilter extends AbstractDubboFilter implements Filter {
 | 
			
		||||
 | 
			
		||||
    public SentinelDubboConsumerFilter() {
 | 
			
		||||
        RecordLog.info("Sentinel Dubbo consumer filter initialized");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
 | 
			
		||||
        Entry interfaceEntry = null;
 | 
			
		||||
        Entry methodEntry = null;
 | 
			
		||||
        try {
 | 
			
		||||
            String prefix = DubboAdapterGlobalConfig.getDubboConsumerPrefix();
 | 
			
		||||
            String interfaceResourceName = getInterfaceName(invoker, prefix);
 | 
			
		||||
            String methodResourceName = getMethodResourceName(invoker, invocation, prefix);
 | 
			
		||||
            interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT);
 | 
			
		||||
            methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC,
 | 
			
		||||
                EntryType.OUT, 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 DubboAdapterGlobalConfig.getConsumerFallback().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();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,96 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.ResourceTypeConstants;
 | 
			
		||||
import com.alibaba.csp.sentinel.SphU;
 | 
			
		||||
import com.alibaba.csp.sentinel.Tracer;
 | 
			
		||||
import com.alibaba.csp.sentinel.context.ContextUtil;
 | 
			
		||||
import com.alibaba.csp.sentinel.log.RecordLog;
 | 
			
		||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
import static com.alibaba.dubbo.common.Constants.PROVIDER;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * <p>Dubbo service provider filter for Sentinel. Auto activated by default.</p>
 | 
			
		||||
 *
 | 
			
		||||
 * If you want to disable the provider filter, you can configure:
 | 
			
		||||
 * <pre>
 | 
			
		||||
 * <dubbo:provider filter="-sentinel.dubbo.provider.filter"/>
 | 
			
		||||
 * </pre>
 | 
			
		||||
 *
 | 
			
		||||
 * @author leyou
 | 
			
		||||
 * @author Eric Zhao
 | 
			
		||||
 */
 | 
			
		||||
@Activate(group = PROVIDER)
 | 
			
		||||
public class SentinelDubboProviderFilter extends AbstractDubboFilter implements Filter {
 | 
			
		||||
 | 
			
		||||
    public SentinelDubboProviderFilter() {
 | 
			
		||||
        RecordLog.info("Sentinel Dubbo provider filter initialized");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
 | 
			
		||||
        // Get origin caller.
 | 
			
		||||
        String origin = DubboAdapterGlobalConfig.getOriginParser().parse(invoker, invocation);
 | 
			
		||||
        if (null == origin) {
 | 
			
		||||
            origin = "";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Entry interfaceEntry = null;
 | 
			
		||||
        Entry methodEntry = null;
 | 
			
		||||
        try {
 | 
			
		||||
            String prefix = DubboAdapterGlobalConfig.getDubboProviderPrefix();
 | 
			
		||||
            String methodResourceName = getMethodResourceName(invoker, invocation, prefix);
 | 
			
		||||
            String interfaceName = getInterfaceName(invoker, prefix);
 | 
			
		||||
            ContextUtil.enter(methodResourceName, origin);
 | 
			
		||||
            interfaceEntry = SphU.entry(interfaceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN);
 | 
			
		||||
            methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC,
 | 
			
		||||
                EntryType.IN, 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 DubboAdapterGlobalConfig.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();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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.dubbo.fallback;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
 | 
			
		||||
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invocation;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invoker;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Result;
 | 
			
		||||
import com.alibaba.dubbo.rpc.RpcResult;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Eric Zhao
 | 
			
		||||
 */
 | 
			
		||||
public class DefaultDubboFallback implements DubboFallback {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Result handle(Invoker<?> invoker, Invocation invocation, BlockException ex) {
 | 
			
		||||
        // Just wrap the exception. edit by wzg923 2020/9/23
 | 
			
		||||
        RpcResult result = new RpcResult();
 | 
			
		||||
        result.setException(new SentinelRpcException(ex.toRuntimeException()));
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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.dubbo.fallback;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invocation;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invoker;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Result;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Fallback handler for Dubbo services.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Eric Zhao
 | 
			
		||||
 */
 | 
			
		||||
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);
 | 
			
		||||
}
 | 
			
		||||
@@ -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.dubbo.fallback;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.adapter.dubbo.DubboAdapterGlobalConfig;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * <p>Global fallback registry for Dubbo.</p>
 | 
			
		||||
 *
 | 
			
		||||
 * @author Eric Zhao
 | 
			
		||||
 * @deprecated use {@link DubboAdapterGlobalConfig} instead.
 | 
			
		||||
 */
 | 
			
		||||
@Deprecated
 | 
			
		||||
public final class DubboFallbackRegistry {
 | 
			
		||||
 | 
			
		||||
    public static DubboFallback getConsumerFallback() {
 | 
			
		||||
        return DubboAdapterGlobalConfig.getConsumerFallback();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void setConsumerFallback(DubboFallback consumerFallback) {
 | 
			
		||||
        DubboAdapterGlobalConfig.setConsumerFallback(consumerFallback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static DubboFallback getProviderFallback() {
 | 
			
		||||
        return DubboAdapterGlobalConfig.getProviderFallback();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void setProviderFallback(DubboFallback providerFallback) {
 | 
			
		||||
        DubboAdapterGlobalConfig.setProviderFallback(providerFallback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private DubboFallbackRegistry() {}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,35 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 1999-2020 Alibaba Group Holding Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      https://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.origin;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.adapter.dubbo.DubboUtils;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invocation;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invoker;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Default Dubbo origin parser.
 | 
			
		||||
 *
 | 
			
		||||
 * @author tiecheng
 | 
			
		||||
 * @since 1.8.0
 | 
			
		||||
 */
 | 
			
		||||
public class DefaultDubboOriginParser implements DubboOriginParser {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String parse(Invoker<?> invoker, Invocation invocation) {
 | 
			
		||||
        return DubboUtils.getApplication(invocation, "");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 1999-2020 Alibaba Group Holding Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      https://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.origin;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invocation;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invoker;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Customized origin parser for Dubbo provider filter.
 | 
			
		||||
 *
 | 
			
		||||
 * @author tiecheng
 | 
			
		||||
 * @since 1.8.0
 | 
			
		||||
 */
 | 
			
		||||
public interface DubboOriginParser {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses the origin (caller) from Dubbo invocation.
 | 
			
		||||
     *
 | 
			
		||||
     * @param invoker    Dubbo invoker
 | 
			
		||||
     * @param invocation Dubbo invocation
 | 
			
		||||
     * @return the parsed origin
 | 
			
		||||
     */
 | 
			
		||||
    String parse(Invoker<?> invoker, Invocation invocation);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -0,0 +1,24 @@
 | 
			
		||||
package com.alibaba.csp.sentinel;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
 | 
			
		||||
import com.alibaba.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();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,89 @@
 | 
			
		||||
package com.alibaba.csp.sentinel.adapter.dubbo;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService;
 | 
			
		||||
import com.alibaba.csp.sentinel.config.SentinelConfig;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invocation;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invoker;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Result;
 | 
			
		||||
import com.alibaba.dubbo.rpc.RpcException;
 | 
			
		||||
import org.junit.After;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Method;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.assertEquals;
 | 
			
		||||
import static org.mockito.Mockito.mock;
 | 
			
		||||
import static org.mockito.Mockito.when;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author cdfive
 | 
			
		||||
 */
 | 
			
		||||
public class AbstractDubboFilterTest {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    public void setUp() {
 | 
			
		||||
        SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "true");
 | 
			
		||||
        SentinelConfig.setConfig(DubboAdapterGlobalConfig.DUBBO_PROVIDER_RES_NAME_PREFIX_KEY, "");
 | 
			
		||||
        SentinelConfig.setConfig(DubboAdapterGlobalConfig.DUBBO_CONSUMER_RES_NAME_PREFIX_KEY, "");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @After
 | 
			
		||||
    public void tearDown() {
 | 
			
		||||
        SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "false");
 | 
			
		||||
        SentinelConfig.setConfig(DubboAdapterGlobalConfig.DUBBO_PROVIDER_RES_NAME_PREFIX_KEY, "");
 | 
			
		||||
        SentinelConfig.setConfig(DubboAdapterGlobalConfig.DUBBO_CONSUMER_RES_NAME_PREFIX_KEY, "");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private AbstractDubboFilter filter = new AbstractDubboFilter() {
 | 
			
		||||
        @Override
 | 
			
		||||
        public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @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 = filter.getMethodResourceName(invoker, invocation);
 | 
			
		||||
 | 
			
		||||
        assertEquals("com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetResourceNameWithPrefix() {
 | 
			
		||||
        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());
 | 
			
		||||
 | 
			
		||||
        //test with default prefix
 | 
			
		||||
        String resourceName = filter.getMethodResourceName(invoker, invocation, DubboAdapterGlobalConfig.getDubboProviderPrefix());
 | 
			
		||||
        System.out.println("resourceName =  " + resourceName);
 | 
			
		||||
        assertEquals("dubbo:provider:com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName);
 | 
			
		||||
        resourceName = filter.getMethodResourceName(invoker, invocation, DubboAdapterGlobalConfig.getDubboConsumerPrefix());
 | 
			
		||||
        assertEquals("dubbo:consumer:com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        //test with custom prefix
 | 
			
		||||
        SentinelConfig.setConfig(DubboAdapterGlobalConfig.DUBBO_PROVIDER_RES_NAME_PREFIX_KEY, "my:dubbo:provider:");
 | 
			
		||||
        SentinelConfig.setConfig(DubboAdapterGlobalConfig.DUBBO_CONSUMER_RES_NAME_PREFIX_KEY, "my:dubbo:consumer:");
 | 
			
		||||
        resourceName = filter.getMethodResourceName(invoker, invocation, DubboAdapterGlobalConfig.getDubboProviderPrefix());
 | 
			
		||||
        assertEquals("my:dubbo:provider:com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName);
 | 
			
		||||
        resourceName = filter.getMethodResourceName(invoker, invocation, DubboAdapterGlobalConfig.getDubboConsumerPrefix());
 | 
			
		||||
        assertEquals("my:dubbo:consumer:com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,59 @@
 | 
			
		||||
package com.alibaba.csp.sentinel.adapter.dubbo;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.BaseTest;
 | 
			
		||||
import com.alibaba.dubbo.common.URL;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invocation;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invoker;
 | 
			
		||||
import com.alibaba.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.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.DUBBO_APPLICATION_KEY);
 | 
			
		||||
        assertNull(application);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,39 @@
 | 
			
		||||
package com.alibaba.csp.sentinel.adapter.dubbo;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invocation;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
 | 
			
		||||
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<String, String>());
 | 
			
		||||
        when(invocation.getAttachment(DubboUtils.DUBBO_APPLICATION_KEY, "")).thenReturn("consumerA");
 | 
			
		||||
 | 
			
		||||
        String application = DubboUtils.getApplication(invocation, "");
 | 
			
		||||
        verify(invocation).getAttachment(DubboUtils.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.DUBBO_APPLICATION_KEY, "")).thenReturn("consumerA");
 | 
			
		||||
 | 
			
		||||
        DubboUtils.getApplication(invocation, "");
 | 
			
		||||
 | 
			
		||||
        fail("No attachments in invocation, IllegalArgumentException should be thrown!");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,131 @@
 | 
			
		||||
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 com.alibaba.dubbo.rpc.Invocation;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invoker;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Result;
 | 
			
		||||
import org.junit.After;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.mockito.invocation.InvocationOnMock;
 | 
			
		||||
import org.mockito.stubbing.Answer;
 | 
			
		||||
 | 
			
		||||
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(new Answer<Object>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
 | 
			
		||||
                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 = filter.getMethodResourceName(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.getEntryType());
 | 
			
		||||
 | 
			
		||||
        // As SphU.entry(interfaceName, EntryType.OUT);
 | 
			
		||||
        Set<Node> childList = entranceNode.getChildList();
 | 
			
		||||
        assertEquals(1, childList.size());
 | 
			
		||||
        DefaultNode interfaceNode = (DefaultNode) childList.iterator().next();
 | 
			
		||||
        ResourceWrapper interfaceResource = interfaceNode.getId();
 | 
			
		||||
        assertEquals(DemoService.class.getName(), interfaceResource.getName());
 | 
			
		||||
        assertSame(EntryType.OUT, interfaceResource.getEntryType());
 | 
			
		||||
 | 
			
		||||
        // As SphU.entry(resourceName, EntryType.OUT);
 | 
			
		||||
        childList = interfaceNode.getChildList();
 | 
			
		||||
        assertEquals(1, childList.size());
 | 
			
		||||
        DefaultNode methodNode = (DefaultNode) childList.iterator().next();
 | 
			
		||||
        ResourceWrapper methodResource = methodNode.getId();
 | 
			
		||||
        assertEquals(resourceName, methodResource.getName());
 | 
			
		||||
        assertSame(EntryType.OUT, methodResource.getEntryType());
 | 
			
		||||
 | 
			
		||||
        // Verify curEntry
 | 
			
		||||
        Entry curEntry = context.getCurEntry();
 | 
			
		||||
        assertSame(methodNode, curEntry.getCurNode());
 | 
			
		||||
        assertSame(interfaceNode, curEntry.getLastNode());
 | 
			
		||||
        assertNull(curEntry.getOriginNode());// As context origin is not "", no originNode should be created in curEntry
 | 
			
		||||
 | 
			
		||||
        // Verify clusterNode
 | 
			
		||||
        ClusterNode methodClusterNode = methodNode.getClusterNode();
 | 
			
		||||
        ClusterNode interfaceClusterNode = interfaceNode.getClusterNode();
 | 
			
		||||
        assertNotSame(methodClusterNode, interfaceClusterNode);// Different resource->Different ProcessorSlot->Different ClusterNode
 | 
			
		||||
 | 
			
		||||
        // As context origin is "", the StatisticNode should not be created in originCountMap of ClusterNode
 | 
			
		||||
        Map<String, StatisticNode> methodOriginCountMap = methodClusterNode.getOriginCountMap();
 | 
			
		||||
        assertEquals(0, methodOriginCountMap.size());
 | 
			
		||||
 | 
			
		||||
        Map<String, StatisticNode> interfaceOriginCountMap = interfaceClusterNode.getOriginCountMap();
 | 
			
		||||
        assertEquals(0, interfaceOriginCountMap.size());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,133 @@
 | 
			
		||||
package com.alibaba.csp.sentinel.adapter.dubbo;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.BaseTest;
 | 
			
		||||
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 com.alibaba.dubbo.rpc.Invocation;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invoker;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Result;
 | 
			
		||||
import org.junit.After;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.mockito.invocation.InvocationOnMock;
 | 
			
		||||
import org.mockito.stubbing.Answer;
 | 
			
		||||
 | 
			
		||||
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 SentinelDubboProviderFilterTest extends BaseTest {
 | 
			
		||||
 | 
			
		||||
    private SentinelDubboProviderFilter filter = new SentinelDubboProviderFilter();
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    public void setUp() {
 | 
			
		||||
        cleanUpAll();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @After
 | 
			
		||||
    public void cleanUp() {
 | 
			
		||||
        cleanUpAll();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testInvoke() {
 | 
			
		||||
        final String originApplication = "consumerA";
 | 
			
		||||
 | 
			
		||||
        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());
 | 
			
		||||
        when(invocation.getAttachment(DubboUtils.DUBBO_APPLICATION_KEY, "")).thenReturn(originApplication);
 | 
			
		||||
 | 
			
		||||
        final Result result = mock(Result.class);
 | 
			
		||||
        when(result.hasException()).thenReturn(false);
 | 
			
		||||
        when(invoker.invoke(invocation)).thenAnswer(new Answer<Object>() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
 | 
			
		||||
                verifyInvocationStructure(originApplication, 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(resourceName)
 | 
			
		||||
     * --InterfaceNode(interfaceName)
 | 
			
		||||
     * ----MethodNode(resourceName)
 | 
			
		||||
     */
 | 
			
		||||
    private void verifyInvocationStructure(String originApplication, Invoker invoker, Invocation invocation) {
 | 
			
		||||
        Context context = ContextUtil.getContext();
 | 
			
		||||
        assertNotNull(context);
 | 
			
		||||
 | 
			
		||||
        // As ContextUtil.enter(resourceName, application) in SentinelDubboProviderFilter
 | 
			
		||||
        String resourceName = filter.getMethodResourceName(invoker, invocation);
 | 
			
		||||
        assertEquals(resourceName, context.getName());
 | 
			
		||||
        assertEquals(originApplication, context.getOrigin());
 | 
			
		||||
 | 
			
		||||
        DefaultNode entranceNode = context.getEntranceNode();
 | 
			
		||||
        ResourceWrapper entranceResource = entranceNode.getId();
 | 
			
		||||
        assertEquals(resourceName, entranceResource.getName());
 | 
			
		||||
        assertSame(EntryType.IN, entranceResource.getEntryType());
 | 
			
		||||
 | 
			
		||||
        // As SphU.entry(interfaceName, EntryType.IN);
 | 
			
		||||
        Set<Node> childList = entranceNode.getChildList();
 | 
			
		||||
        assertEquals(1, childList.size());
 | 
			
		||||
        DefaultNode interfaceNode = (DefaultNode) childList.iterator().next();
 | 
			
		||||
        ResourceWrapper interfaceResource = interfaceNode.getId();
 | 
			
		||||
        assertEquals(DemoService.class.getName(), interfaceResource.getName());
 | 
			
		||||
        assertSame(EntryType.IN, interfaceResource.getEntryType());
 | 
			
		||||
 | 
			
		||||
        // As SphU.entry(resourceName, EntryType.IN, 1, invocation.getArguments());
 | 
			
		||||
        childList = interfaceNode.getChildList();
 | 
			
		||||
        assertEquals(1, childList.size());
 | 
			
		||||
        DefaultNode methodNode = (DefaultNode) childList.iterator().next();
 | 
			
		||||
        ResourceWrapper methodResource = methodNode.getId();
 | 
			
		||||
        assertEquals(resourceName, methodResource.getName());
 | 
			
		||||
        assertSame(EntryType.IN, methodResource.getEntryType());
 | 
			
		||||
 | 
			
		||||
        // Verify curEntry
 | 
			
		||||
        Entry curEntry = context.getCurEntry();
 | 
			
		||||
        assertSame(methodNode, curEntry.getCurNode());
 | 
			
		||||
        assertSame(interfaceNode, curEntry.getLastNode());
 | 
			
		||||
        assertNotNull(curEntry.getOriginNode());// As context origin is not "", originNode should be created
 | 
			
		||||
 | 
			
		||||
        // Verify clusterNode
 | 
			
		||||
        ClusterNode methodClusterNode = methodNode.getClusterNode();
 | 
			
		||||
        ClusterNode interfaceClusterNode = interfaceNode.getClusterNode();
 | 
			
		||||
        assertNotSame(methodClusterNode, interfaceClusterNode);// Different resource->Different ProcessorSlot->Different ClusterNode
 | 
			
		||||
 | 
			
		||||
        // As context origin is not "", the StatisticNode should be created in originCountMap of ClusterNode
 | 
			
		||||
        Map<String, StatisticNode> methodOriginCountMap = methodClusterNode.getOriginCountMap();
 | 
			
		||||
        assertEquals(1, methodOriginCountMap.size());
 | 
			
		||||
        assertTrue(methodOriginCountMap.containsKey(originApplication));
 | 
			
		||||
 | 
			
		||||
        Map<String, StatisticNode> interfaceOriginCountMap = interfaceClusterNode.getOriginCountMap();
 | 
			
		||||
        assertEquals(1, interfaceOriginCountMap.size());
 | 
			
		||||
        assertTrue(interfaceOriginCountMap.containsKey(originApplication));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,57 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.adapter.dubbo.DubboAdapterGlobalConfig;
 | 
			
		||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
 | 
			
		||||
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
 | 
			
		||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invocation;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invoker;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Result;
 | 
			
		||||
import com.alibaba.dubbo.rpc.RpcResult;
 | 
			
		||||
import org.junit.Assert;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Eric Zhao
 | 
			
		||||
 */
 | 
			
		||||
public class DubboFallbackRegistryTest {
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDefaultFallback() {
 | 
			
		||||
        // Test for default fallback.
 | 
			
		||||
        BlockException ex = new FlowException("xxx");
 | 
			
		||||
        Result result = new DefaultDubboFallback().handle(null, null, ex);
 | 
			
		||||
        Assert.assertTrue(result.hasException());
 | 
			
		||||
        Assert.assertEquals(SentinelRpcException.class, result.getException().getClass());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCustomFallback() {
 | 
			
		||||
        BlockException ex = new FlowException("xxx");
 | 
			
		||||
        DubboAdapterGlobalConfig.setConsumerFallback(new DubboFallback() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public Result handle(Invoker<?> invoker, Invocation invocation, BlockException e) {
 | 
			
		||||
                return new RpcResult("Error: " + e.getClass().getName());
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        Result result = DubboAdapterGlobalConfig.getConsumerFallback()
 | 
			
		||||
            .handle(null, null, ex);
 | 
			
		||||
        Assert.assertFalse("The invocation should not fail", result.hasException());
 | 
			
		||||
        Assert.assertEquals("Error: " + ex.getClass().getName(), result.getValue());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,76 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 1999-2020 Alibaba Group Holding Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      https://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.origin;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.adapter.dubbo.DubboAdapterGlobalConfig;
 | 
			
		||||
import com.alibaba.csp.sentinel.adapter.dubbo.DubboUtils;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invocation;
 | 
			
		||||
import com.alibaba.dubbo.rpc.Invoker;
 | 
			
		||||
import com.alibaba.dubbo.rpc.RpcInvocation;
 | 
			
		||||
 | 
			
		||||
import org.junit.After;
 | 
			
		||||
import org.junit.Assert;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author tiecheng
 | 
			
		||||
 */
 | 
			
		||||
public class DubboOriginRegistryTest {
 | 
			
		||||
 | 
			
		||||
    @After
 | 
			
		||||
    public void cleanUp() {
 | 
			
		||||
        DubboAdapterGlobalConfig.setOriginParser(new DefaultDubboOriginParser());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test(expected = IllegalArgumentException.class)
 | 
			
		||||
    public void testDefaultOriginParserFail() {
 | 
			
		||||
        DubboAdapterGlobalConfig.getOriginParser().parse(null, null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDefaultOriginParserSuccess() {
 | 
			
		||||
        RpcInvocation invocation = new RpcInvocation();
 | 
			
		||||
        String dubboName = "sentinel";
 | 
			
		||||
        invocation.setAttachment(DubboUtils.DUBBO_APPLICATION_KEY, dubboName);
 | 
			
		||||
        String origin = DubboAdapterGlobalConfig.getOriginParser().parse(null, invocation);
 | 
			
		||||
        Assert.assertEquals(dubboName, origin);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCustomOriginParser() {
 | 
			
		||||
        DubboAdapterGlobalConfig.setOriginParser(new DubboOriginParser() {
 | 
			
		||||
            @Override
 | 
			
		||||
            public String parse(Invoker<?> invoker, Invocation invocation) {
 | 
			
		||||
                return invocation.getAttachment(DubboUtils.DUBBO_APPLICATION_KEY, "default") + "_" + invocation
 | 
			
		||||
                    .getMethodName();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        RpcInvocation invocation = new RpcInvocation();
 | 
			
		||||
        String origin = DubboAdapterGlobalConfig.getOriginParser().parse(null, invocation);
 | 
			
		||||
        Assert.assertEquals("default_null", origin);
 | 
			
		||||
 | 
			
		||||
        String dubboName = "sentinel";
 | 
			
		||||
        invocation.setAttachment(DubboUtils.DUBBO_APPLICATION_KEY, dubboName);
 | 
			
		||||
        origin = DubboAdapterGlobalConfig.getOriginParser().parse(null, invocation);
 | 
			
		||||
        Assert.assertEquals(dubboName + "_null", origin);
 | 
			
		||||
 | 
			
		||||
        invocation.setMethodName("hello");
 | 
			
		||||
        origin = DubboAdapterGlobalConfig.getOriginParser().parse(null, invocation);
 | 
			
		||||
        Assert.assertEquals(dubboName + "_hello", origin);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,23 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.provider;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author leyou
 | 
			
		||||
 */
 | 
			
		||||
public interface DemoService {
 | 
			
		||||
    String sayHello(String name, int n);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,27 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.provider.impl;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author leyou
 | 
			
		||||
 */
 | 
			
		||||
public class DemoServiceImpl implements DemoService {
 | 
			
		||||
    public String sayHello(String name, int n) {
 | 
			
		||||
        return "Hello " + name + ", " + n;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,18 @@
 | 
			
		||||
<?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.provider.DemoService" ref="demoServiceImp" />
 | 
			
		||||
    <bean id="demoServiceImp" class="com.alibaba.csp.sentinel.adapter.dubbo.provider.impl.DemoServiceImpl"/>
 | 
			
		||||
 | 
			
		||||
    <dubbo:reference id="demoService" interface="com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService"/>
 | 
			
		||||
 | 
			
		||||
</beans>
 | 
			
		||||
@@ -0,0 +1,18 @@
 | 
			
		||||
<?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.provider.DemoService" ref="demoServiceImp" />
 | 
			
		||||
    <bean id="demoServiceImp" class="com.alibaba.csp.sentinel.adapter.dubbo.provider.impl.DemoServiceImpl"/>
 | 
			
		||||
 | 
			
		||||
    <dubbo:reference id="demoService" interface="com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService"/>
 | 
			
		||||
 | 
			
		||||
</beans>
 | 
			
		||||
		Reference in New Issue
	
	Block a user