* Unify Dubbo callback registry (for fallback and origin parser) into DubboAdapterGlobalConfig * Polish default fallback implementation (wrap exception with RpcResult rather than directly throw it out) Signed-off-by: Eric Zhao <sczyh16@gmail.com>master
@@ -1,6 +1,6 @@ | |||||
# Sentinel Dubbo Adapter | # Sentinel Dubbo Adapter | ||||
> Note: 中文文档请见[此处](https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6%E7%9A%84%E9%80%82%E9%85%8D#dubbo)。 | |||||
> Note: 中文文档请见[此处](https://github.com/alibaba/Sentinel/wiki/主流框架的适配#dubbo)。 | |||||
Sentinel Dubbo Adapter provides service consumer filter and provider filter | Sentinel Dubbo Adapter provides service consumer filter and provider filter | ||||
for [Dubbo](https://dubbo.apache.org/en-us/) services. | for [Dubbo](https://dubbo.apache.org/en-us/) services. | ||||
@@ -52,23 +52,21 @@ If `limitApp` of flow rules is not configured (`default`), flow control will tak | |||||
If `limitApp` of a flow rule is configured with a caller, then the corresponding flow rule will only take effect on the specific caller. | 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, | > 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`. | |||||
> 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 | ## Global fallback | ||||
Sentinel Dubbo Adapter supports global fallback configuration. | Sentinel Dubbo Adapter supports global fallback configuration. | ||||
The global fallback will handle exceptions and give replacement result when blocked by | 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 | flow control, degrade or system load protection. You can implement your own `DubboFallback` interface | ||||
and then register to `DubboFallbackRegistry`. If no fallback is configured, Sentinel will wrap the `BlockException` | |||||
then directly throw it out. | |||||
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. | |||||
## Global dubbo provider origin parse | |||||
Sentinel Dubbo Adapter supports global origin parse for provider. | |||||
You can implement your own `DubboOriginParser` interface | |||||
and then register to `DubboOriginParserRegistry`. If no originParse is configured, Sentinel will user dubbo url property application. | |||||
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. |
@@ -25,12 +25,12 @@ import com.alibaba.dubbo.rpc.Invoker; | |||||
*/ | */ | ||||
abstract class AbstractDubboFilter implements Filter { | abstract class AbstractDubboFilter implements Filter { | ||||
protected String getResourceName(Invoker<?> invoker, Invocation invocation) { | |||||
protected String getMethodResourceName(Invoker<?> invoker, Invocation invocation) { | |||||
StringBuilder buf = new StringBuilder(64); | StringBuilder buf = new StringBuilder(64); | ||||
buf.append(invoker.getInterface().getName()) | buf.append(invoker.getInterface().getName()) | ||||
.append(":") | |||||
.append(invocation.getMethodName()) | |||||
.append("("); | |||||
.append(":") | |||||
.append(invocation.getMethodName()) | |||||
.append("("); | |||||
boolean isFirst = true; | boolean isFirst = true; | ||||
for (Class<?> clazz : invocation.getParameterTypes()) { | for (Class<?> clazz : invocation.getParameterTypes()) { | ||||
if (!isFirst) { | if (!isFirst) { | ||||
@@ -43,15 +43,24 @@ abstract class AbstractDubboFilter implements Filter { | |||||
return buf.toString(); | return buf.toString(); | ||||
} | } | ||||
protected String getResourceName(Invoker<?> invoker, Invocation invocation, String prefix) { | |||||
protected String getMethodResourceName(Invoker<?> invoker, Invocation invocation, String prefix) { | |||||
if (StringUtil.isBlank(prefix)) { | if (StringUtil.isBlank(prefix)) { | ||||
return getResourceName(invoker, invocation); | |||||
return getMethodResourceName(invoker, invocation); | |||||
} | } | ||||
StringBuilder buf = new StringBuilder(64); | StringBuilder buf = new StringBuilder(64); | ||||
return buf.append(prefix) | return buf.append(prefix) | ||||
.append(getResourceName(invoker, invocation)) | |||||
.toString(); | |||||
.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() {} | |||||
} |
@@ -20,8 +20,6 @@ import com.alibaba.csp.sentinel.EntryType; | |||||
import com.alibaba.csp.sentinel.ResourceTypeConstants; | import com.alibaba.csp.sentinel.ResourceTypeConstants; | ||||
import com.alibaba.csp.sentinel.SphU; | import com.alibaba.csp.sentinel.SphU; | ||||
import com.alibaba.csp.sentinel.Tracer; | import com.alibaba.csp.sentinel.Tracer; | ||||
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig; | |||||
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry; | |||||
import com.alibaba.csp.sentinel.log.RecordLog; | import com.alibaba.csp.sentinel.log.RecordLog; | ||||
import com.alibaba.csp.sentinel.slots.block.BlockException; | import com.alibaba.csp.sentinel.slots.block.BlockException; | ||||
import com.alibaba.dubbo.common.extension.Activate; | import com.alibaba.dubbo.common.extension.Activate; | ||||
@@ -56,10 +54,12 @@ public class SentinelDubboConsumerFilter extends AbstractDubboFilter implements | |||||
Entry interfaceEntry = null; | Entry interfaceEntry = null; | ||||
Entry methodEntry = null; | Entry methodEntry = null; | ||||
try { | try { | ||||
String resourceName = getResourceName(invoker, invocation, DubboConfig.getDubboConsumerPrefix()); | |||||
interfaceEntry = SphU.entry(invoker.getInterface().getName(), ResourceTypeConstants.COMMON_RPC, | |||||
EntryType.OUT); | |||||
methodEntry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT, invocation.getArguments()); | |||||
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); | Result result = invoker.invoke(invocation); | ||||
if (result.hasException()) { | if (result.hasException()) { | ||||
@@ -70,7 +70,7 @@ public class SentinelDubboConsumerFilter extends AbstractDubboFilter implements | |||||
} | } | ||||
return result; | return result; | ||||
} catch (BlockException e) { | } catch (BlockException e) { | ||||
return DubboFallbackRegistry.getConsumerFallback().handle(invoker, invocation, e); | |||||
return DubboAdapterGlobalConfig.getConsumerFallback().handle(invoker, invocation, e); | |||||
} catch (RpcException e) { | } catch (RpcException e) { | ||||
Tracer.traceEntry(e, interfaceEntry); | Tracer.traceEntry(e, interfaceEntry); | ||||
Tracer.traceEntry(e, methodEntry); | Tracer.traceEntry(e, methodEntry); | ||||
@@ -20,9 +20,6 @@ import com.alibaba.csp.sentinel.EntryType; | |||||
import com.alibaba.csp.sentinel.ResourceTypeConstants; | import com.alibaba.csp.sentinel.ResourceTypeConstants; | ||||
import com.alibaba.csp.sentinel.SphU; | import com.alibaba.csp.sentinel.SphU; | ||||
import com.alibaba.csp.sentinel.Tracer; | import com.alibaba.csp.sentinel.Tracer; | ||||
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig; | |||||
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry; | |||||
import com.alibaba.csp.sentinel.adapter.dubbo.origin.DubboOriginParserRegistry; | |||||
import com.alibaba.csp.sentinel.context.ContextUtil; | import com.alibaba.csp.sentinel.context.ContextUtil; | ||||
import com.alibaba.csp.sentinel.log.RecordLog; | import com.alibaba.csp.sentinel.log.RecordLog; | ||||
import com.alibaba.csp.sentinel.slots.block.BlockException; | import com.alibaba.csp.sentinel.slots.block.BlockException; | ||||
@@ -56,7 +53,7 @@ public class SentinelDubboProviderFilter extends AbstractDubboFilter implements | |||||
@Override | @Override | ||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { | public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { | ||||
// Get origin caller. | // Get origin caller. | ||||
String origin = DubboOriginParserRegistry.getDubboOriginParser().parse(invoker, invocation); | |||||
String origin = DubboAdapterGlobalConfig.getOriginParser().parse(invoker, invocation); | |||||
if (null == origin) { | if (null == origin) { | ||||
origin = ""; | origin = ""; | ||||
} | } | ||||
@@ -64,11 +61,12 @@ public class SentinelDubboProviderFilter extends AbstractDubboFilter implements | |||||
Entry interfaceEntry = null; | Entry interfaceEntry = null; | ||||
Entry methodEntry = null; | Entry methodEntry = null; | ||||
try { | try { | ||||
String resourceName = getResourceName(invoker, invocation, DubboConfig.getDubboProviderPrefix()); | |||||
String interfaceName = invoker.getInterface().getName(); | |||||
ContextUtil.enter(resourceName, origin); | |||||
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); | interfaceEntry = SphU.entry(interfaceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN); | ||||
methodEntry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_RPC, | |||||
methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, | |||||
EntryType.IN, invocation.getArguments()); | EntryType.IN, invocation.getArguments()); | ||||
Result result = invoker.invoke(invocation); | Result result = invoker.invoke(invocation); | ||||
@@ -80,7 +78,7 @@ public class SentinelDubboProviderFilter extends AbstractDubboFilter implements | |||||
} | } | ||||
return result; | return result; | ||||
} catch (BlockException e) { | } catch (BlockException e) { | ||||
return DubboFallbackRegistry.getProviderFallback().handle(invoker, invocation, e); | |||||
return DubboAdapterGlobalConfig.getProviderFallback().handle(invoker, invocation, e); | |||||
} catch (RpcException e) { | } catch (RpcException e) { | ||||
Tracer.traceEntry(e, interfaceEntry); | Tracer.traceEntry(e, interfaceEntry); | ||||
Tracer.traceEntry(e, methodEntry); | Tracer.traceEntry(e, methodEntry); | ||||
@@ -1,62 +0,0 @@ | |||||
/* | |||||
* 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.config; | |||||
import com.alibaba.csp.sentinel.config.SentinelConfig; | |||||
import com.alibaba.csp.sentinel.util.StringUtil; | |||||
/** | |||||
* <p> | |||||
* Responsible for dubbo service provider, consumer attribute configuration | |||||
* </p> | |||||
* | |||||
* @author lianglin | |||||
* @since 1.7.0 | |||||
*/ | |||||
public final class DubboConfig { | |||||
public static final String DUBBO_USE_PREFIX = "csp.sentinel.dubbo.resource.use.prefix"; | |||||
private static final String TRUE_STR = "true"; | |||||
public static final String DUBBO_PROVIDER_PREFIX = "csp.sentinel.dubbo.resource.provider.prefix"; | |||||
public static final String DUBBO_CONSUMER_PREFIX = "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:"; | |||||
public static boolean isUsePrefix() { | |||||
return TRUE_STR.equalsIgnoreCase(SentinelConfig.getConfig(DUBBO_USE_PREFIX)); | |||||
} | |||||
public static String getDubboProviderPrefix() { | |||||
if (isUsePrefix()) { | |||||
String config = SentinelConfig.getConfig(DUBBO_PROVIDER_PREFIX); | |||||
return StringUtil.isNotBlank(config) ? config : DEFAULT_DUBBO_PROVIDER_PREFIX; | |||||
} | |||||
return null; | |||||
} | |||||
public static String getDubboConsumerPrefix() { | |||||
if (isUsePrefix()) { | |||||
String config = SentinelConfig.getConfig(DUBBO_CONSUMER_PREFIX); | |||||
return StringUtil.isNotBlank(config) ? config : DEFAULT_DUBBO_CONSUMER_PREFIX; | |||||
} | |||||
return null; | |||||
} | |||||
} |
@@ -20,6 +20,7 @@ import com.alibaba.csp.sentinel.slots.block.SentinelRpcException; | |||||
import com.alibaba.dubbo.rpc.Invocation; | import com.alibaba.dubbo.rpc.Invocation; | ||||
import com.alibaba.dubbo.rpc.Invoker; | import com.alibaba.dubbo.rpc.Invoker; | ||||
import com.alibaba.dubbo.rpc.Result; | import com.alibaba.dubbo.rpc.Result; | ||||
import com.alibaba.dubbo.rpc.RpcResult; | |||||
/** | /** | ||||
* @author Eric Zhao | * @author Eric Zhao | ||||
@@ -28,7 +29,7 @@ public class DefaultDubboFallback implements DubboFallback { | |||||
@Override | @Override | ||||
public Result handle(Invoker<?> invoker, Invocation invocation, BlockException ex) { | public Result handle(Invoker<?> invoker, Invocation invocation, BlockException ex) { | ||||
// Just wrap and throw the exception. | |||||
throw new SentinelRpcException(ex); | |||||
// Just wrap the exception. | |||||
return new RpcResult(new SentinelRpcException(ex)); | |||||
} | } | ||||
} | } |
@@ -15,33 +15,31 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.adapter.dubbo.fallback; | package com.alibaba.csp.sentinel.adapter.dubbo.fallback; | ||||
import com.alibaba.csp.sentinel.adapter.dubbo.DubboAdapterGlobalConfig; | |||||
/** | /** | ||||
* Global fallback registry for Dubbo. | |||||
* | |||||
* Note: Degrading is mainly designed for consumer. The provider should not | |||||
* give fallback result in most circumstances. | |||||
* <p>Global fallback registry for Dubbo.</p> | |||||
* | * | ||||
* @author Eric Zhao | * @author Eric Zhao | ||||
* @deprecated use {@link DubboAdapterGlobalConfig} instead. | |||||
*/ | */ | ||||
@Deprecated | |||||
public final class DubboFallbackRegistry { | public final class DubboFallbackRegistry { | ||||
private static volatile DubboFallback consumerFallback = new DefaultDubboFallback(); | |||||
private static volatile DubboFallback providerFallback = new DefaultDubboFallback(); | |||||
public static DubboFallback getConsumerFallback() { | public static DubboFallback getConsumerFallback() { | ||||
return consumerFallback; | |||||
return DubboAdapterGlobalConfig.getConsumerFallback(); | |||||
} | } | ||||
public static void setConsumerFallback(DubboFallback consumerFallback) { | public static void setConsumerFallback(DubboFallback consumerFallback) { | ||||
DubboFallbackRegistry.consumerFallback = consumerFallback; | |||||
DubboAdapterGlobalConfig.setConsumerFallback(consumerFallback); | |||||
} | } | ||||
public static DubboFallback getProviderFallback() { | public static DubboFallback getProviderFallback() { | ||||
return providerFallback; | |||||
return DubboAdapterGlobalConfig.getProviderFallback(); | |||||
} | } | ||||
public static void setProviderFallback(DubboFallback providerFallback) { | public static void setProviderFallback(DubboFallback providerFallback) { | ||||
DubboFallbackRegistry.providerFallback = providerFallback; | |||||
DubboAdapterGlobalConfig.setProviderFallback(providerFallback); | |||||
} | } | ||||
private DubboFallbackRegistry() {} | private DubboFallbackRegistry() {} | ||||
@@ -20,9 +20,10 @@ import com.alibaba.dubbo.rpc.Invocation; | |||||
import com.alibaba.dubbo.rpc.Invoker; | import com.alibaba.dubbo.rpc.Invoker; | ||||
/** | /** | ||||
* Default Dubbo origin parse. | |||||
* Default Dubbo origin parser. | |||||
* | * | ||||
* @author tiecheng | * @author tiecheng | ||||
* @since 1.8.0 | |||||
*/ | */ | ||||
public class DefaultDubboOriginParser implements DubboOriginParser { | public class DefaultDubboOriginParser implements DubboOriginParser { | ||||
@@ -15,23 +15,23 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.adapter.dubbo.origin; | package com.alibaba.csp.sentinel.adapter.dubbo.origin; | ||||
import com.alibaba.csp.sentinel.context.Context; | |||||
import com.alibaba.dubbo.rpc.Invocation; | import com.alibaba.dubbo.rpc.Invocation; | ||||
import com.alibaba.dubbo.rpc.Invoker; | import com.alibaba.dubbo.rpc.Invoker; | ||||
/** | /** | ||||
* Customized origin parse in Dubbo provider filter. {@link Context#getOrigin()} | |||||
* Customized origin parser for Dubbo provider filter. | |||||
* | * | ||||
* @author tiecheng | * @author tiecheng | ||||
* @since 1.8.0 | |||||
*/ | */ | ||||
public interface DubboOriginParser { | public interface DubboOriginParser { | ||||
/** | /** | ||||
* Handle the origin parse. | |||||
* Parses the origin (caller) from Dubbo invocation. | |||||
* | * | ||||
* @param invoker Dubbo invoker | * @param invoker Dubbo invoker | ||||
* @param invocation Dubbo invocation | * @param invocation Dubbo invocation | ||||
* @return parse result | |||||
* @return the parsed origin | |||||
*/ | */ | ||||
String parse(Invoker<?> invoker, Invocation invocation); | String parse(Invoker<?> invoker, Invocation invocation); | ||||
@@ -1,37 +0,0 @@ | |||||
/* | |||||
* 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; | |||||
/** | |||||
* Global origin parser registry for Dubbo. | |||||
* | |||||
* @author tiecheng | |||||
*/ | |||||
public final class DubboOriginParserRegistry { | |||||
private static volatile DubboOriginParser dubboOriginParser = new DefaultDubboOriginParser(); | |||||
public static DubboOriginParser getDubboOriginParser() { | |||||
return dubboOriginParser; | |||||
} | |||||
public static void setDubboOriginParser(DubboOriginParser dubboOriginParser) { | |||||
DubboOriginParserRegistry.dubboOriginParser = dubboOriginParser; | |||||
} | |||||
private DubboOriginParserRegistry() {} | |||||
} |
@@ -1,6 +1,5 @@ | |||||
package com.alibaba.csp.sentinel.adapter.dubbo; | package com.alibaba.csp.sentinel.adapter.dubbo; | ||||
import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboConfig; | |||||
import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService; | import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService; | ||||
import com.alibaba.csp.sentinel.config.SentinelConfig; | import com.alibaba.csp.sentinel.config.SentinelConfig; | ||||
import com.alibaba.dubbo.rpc.Invocation; | import com.alibaba.dubbo.rpc.Invocation; | ||||
@@ -26,15 +25,15 @@ public class AbstractDubboFilterTest { | |||||
@Before | @Before | ||||
public void setUp() { | public void setUp() { | ||||
SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "true"); | SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "true"); | ||||
SentinelConfig.setConfig(DubboConfig.DUBBO_PROVIDER_PREFIX, ""); | |||||
SentinelConfig.setConfig(DubboConfig.DUBBO_CONSUMER_PREFIX, ""); | |||||
SentinelConfig.setConfig(DubboAdapterGlobalConfig.DUBBO_PROVIDER_RES_NAME_PREFIX_KEY, ""); | |||||
SentinelConfig.setConfig(DubboAdapterGlobalConfig.DUBBO_CONSUMER_RES_NAME_PREFIX_KEY, ""); | |||||
} | } | ||||
@After | @After | ||||
public void tearDown() { | public void tearDown() { | ||||
SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "false"); | SentinelConfig.setConfig("csp.sentinel.dubbo.resource.use.prefix", "false"); | ||||
SentinelConfig.setConfig(DubboConfig.DUBBO_PROVIDER_PREFIX, ""); | |||||
SentinelConfig.setConfig(DubboConfig.DUBBO_CONSUMER_PREFIX, ""); | |||||
SentinelConfig.setConfig(DubboAdapterGlobalConfig.DUBBO_PROVIDER_RES_NAME_PREFIX_KEY, ""); | |||||
SentinelConfig.setConfig(DubboAdapterGlobalConfig.DUBBO_CONSUMER_RES_NAME_PREFIX_KEY, ""); | |||||
} | } | ||||
private AbstractDubboFilter filter = new AbstractDubboFilter() { | private AbstractDubboFilter filter = new AbstractDubboFilter() { | ||||
@@ -55,7 +54,7 @@ public class AbstractDubboFilterTest { | |||||
when(invocation.getMethodName()).thenReturn(method.getName()); | when(invocation.getMethodName()).thenReturn(method.getName()); | ||||
when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes()); | when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes()); | ||||
String resourceName = filter.getResourceName(invoker, invocation); | |||||
String resourceName = filter.getMethodResourceName(invoker, invocation); | |||||
assertEquals("com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName); | assertEquals("com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName); | ||||
} | } | ||||
@@ -71,19 +70,19 @@ public class AbstractDubboFilterTest { | |||||
when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes()); | when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes()); | ||||
//test with default prefix | //test with default prefix | ||||
String resourceName = filter.getResourceName(invoker, invocation, DubboConfig.getDubboProviderPrefix()); | |||||
String resourceName = filter.getMethodResourceName(invoker, invocation, DubboAdapterGlobalConfig.getDubboProviderPrefix()); | |||||
System.out.println("resourceName = " + resourceName); | System.out.println("resourceName = " + resourceName); | ||||
assertEquals("dubbo:provider:com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName); | assertEquals("dubbo:provider:com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName); | ||||
resourceName = filter.getResourceName(invoker, invocation, DubboConfig.getDubboConsumerPrefix()); | |||||
resourceName = filter.getMethodResourceName(invoker, invocation, DubboAdapterGlobalConfig.getDubboConsumerPrefix()); | |||||
assertEquals("dubbo:consumer:com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName); | assertEquals("dubbo:consumer:com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName); | ||||
//test with custom prefix | //test with custom prefix | ||||
SentinelConfig.setConfig(DubboConfig.DUBBO_PROVIDER_PREFIX, "my:dubbo:provider:"); | |||||
SentinelConfig.setConfig(DubboConfig.DUBBO_CONSUMER_PREFIX, "my:dubbo:consumer:"); | |||||
resourceName = filter.getResourceName(invoker, invocation, DubboConfig.getDubboProviderPrefix()); | |||||
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); | assertEquals("my:dubbo:provider:com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName); | ||||
resourceName = filter.getResourceName(invoker, invocation, DubboConfig.getDubboConsumerPrefix()); | |||||
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); | assertEquals("my:dubbo:consumer:com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService:sayHello(java.lang.String,int)", resourceName); | ||||
} | } | ||||
@@ -85,7 +85,7 @@ public class SentinelDubboConsumerFilterTest extends BaseTest { | |||||
// As not call ContextUtil.enter(resourceName, application) in SentinelDubboConsumerFilter, use default 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 | // 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 | // If consumer is on the top of Dubbo RPC invocation chain, use default context | ||||
String resourceName = filter.getResourceName(invoker, invocation); | |||||
String resourceName = filter.getMethodResourceName(invoker, invocation); | |||||
assertEquals(Constants.CONTEXT_DEFAULT_NAME, context.getName()); | assertEquals(Constants.CONTEXT_DEFAULT_NAME, context.getName()); | ||||
assertEquals("", context.getOrigin()); | assertEquals("", context.getOrigin()); | ||||
@@ -85,7 +85,7 @@ public class SentinelDubboProviderFilterTest extends BaseTest { | |||||
assertNotNull(context); | assertNotNull(context); | ||||
// As ContextUtil.enter(resourceName, application) in SentinelDubboProviderFilter | // As ContextUtil.enter(resourceName, application) in SentinelDubboProviderFilter | ||||
String resourceName = filter.getResourceName(invoker, invocation); | |||||
String resourceName = filter.getMethodResourceName(invoker, invocation); | |||||
assertEquals(resourceName, context.getName()); | assertEquals(resourceName, context.getName()); | ||||
assertEquals(originApplication, context.getOrigin()); | assertEquals(originApplication, context.getOrigin()); | ||||
@@ -15,6 +15,7 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.adapter.dubbo.fallback; | 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.BlockException; | ||||
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException; | import com.alibaba.csp.sentinel.slots.block.SentinelRpcException; | ||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowException; | import com.alibaba.csp.sentinel.slots.block.flow.FlowException; | ||||
@@ -31,24 +32,25 @@ import org.junit.Test; | |||||
*/ | */ | ||||
public class DubboFallbackRegistryTest { | public class DubboFallbackRegistryTest { | ||||
@Test(expected = SentinelRpcException.class) | |||||
@Test | |||||
public void testDefaultFallback() { | public void testDefaultFallback() { | ||||
// Test for default. | |||||
// Test for default fallback. | |||||
BlockException ex = new FlowException("xxx"); | BlockException ex = new FlowException("xxx"); | ||||
DubboFallbackRegistry.getConsumerFallback() | |||||
.handle(null, null, ex); | |||||
Result result = new DefaultDubboFallback().handle(null, null, ex); | |||||
Assert.assertTrue(result.hasException()); | |||||
Assert.assertEquals(SentinelRpcException.class, result.getException().getClass()); | |||||
} | } | ||||
@Test | @Test | ||||
public void testCustomFallback() { | public void testCustomFallback() { | ||||
BlockException ex = new FlowException("xxx"); | BlockException ex = new FlowException("xxx"); | ||||
DubboFallbackRegistry.setConsumerFallback(new DubboFallback() { | |||||
DubboAdapterGlobalConfig.setConsumerFallback(new DubboFallback() { | |||||
@Override | @Override | ||||
public Result handle(Invoker<?> invoker, Invocation invocation, BlockException e) { | public Result handle(Invoker<?> invoker, Invocation invocation, BlockException e) { | ||||
return new RpcResult("Error: " + e.getClass().getName()); | return new RpcResult("Error: " + e.getClass().getName()); | ||||
} | } | ||||
}); | }); | ||||
Result result = DubboFallbackRegistry.getConsumerFallback() | |||||
Result result = DubboAdapterGlobalConfig.getConsumerFallback() | |||||
.handle(null, null, ex); | .handle(null, null, ex); | ||||
Assert.assertFalse("The invocation should not fail", result.hasException()); | Assert.assertFalse("The invocation should not fail", result.hasException()); | ||||
Assert.assertEquals("Error: " + ex.getClass().getName(), result.getValue()); | Assert.assertEquals("Error: " + ex.getClass().getName(), result.getValue()); | ||||
@@ -15,10 +15,12 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.adapter.dubbo.origin; | 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.csp.sentinel.adapter.dubbo.DubboUtils; | ||||
import com.alibaba.dubbo.rpc.Invocation; | import com.alibaba.dubbo.rpc.Invocation; | ||||
import com.alibaba.dubbo.rpc.Invoker; | import com.alibaba.dubbo.rpc.Invoker; | ||||
import com.alibaba.dubbo.rpc.RpcInvocation; | import com.alibaba.dubbo.rpc.RpcInvocation; | ||||
import org.junit.After; | import org.junit.After; | ||||
import org.junit.Assert; | import org.junit.Assert; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
@@ -30,12 +32,12 @@ public class DubboOriginRegistryTest { | |||||
@After | @After | ||||
public void cleanUp() { | public void cleanUp() { | ||||
DubboOriginParserRegistry.setDubboOriginParser(new DefaultDubboOriginParser()); | |||||
DubboAdapterGlobalConfig.setOriginParser(new DefaultDubboOriginParser()); | |||||
} | } | ||||
@Test(expected = IllegalArgumentException.class) | @Test(expected = IllegalArgumentException.class) | ||||
public void testDefaultOriginParserFail() { | public void testDefaultOriginParserFail() { | ||||
DubboOriginParserRegistry.getDubboOriginParser().parse(null, null); | |||||
DubboAdapterGlobalConfig.getOriginParser().parse(null, null); | |||||
} | } | ||||
@Test | @Test | ||||
@@ -43,13 +45,13 @@ public class DubboOriginRegistryTest { | |||||
RpcInvocation invocation = new RpcInvocation(); | RpcInvocation invocation = new RpcInvocation(); | ||||
String dubboName = "sentinel"; | String dubboName = "sentinel"; | ||||
invocation.setAttachment(DubboUtils.DUBBO_APPLICATION_KEY, dubboName); | invocation.setAttachment(DubboUtils.DUBBO_APPLICATION_KEY, dubboName); | ||||
String origin = DubboOriginParserRegistry.getDubboOriginParser().parse(null, invocation); | |||||
String origin = DubboAdapterGlobalConfig.getOriginParser().parse(null, invocation); | |||||
Assert.assertEquals(dubboName, origin); | Assert.assertEquals(dubboName, origin); | ||||
} | } | ||||
@Test | @Test | ||||
public void testCustomOriginParser() { | public void testCustomOriginParser() { | ||||
DubboOriginParserRegistry.setDubboOriginParser(new DubboOriginParser() { | |||||
DubboAdapterGlobalConfig.setOriginParser(new DubboOriginParser() { | |||||
@Override | @Override | ||||
public String parse(Invoker<?> invoker, Invocation invocation) { | public String parse(Invoker<?> invoker, Invocation invocation) { | ||||
return invocation.getAttachment(DubboUtils.DUBBO_APPLICATION_KEY, "default") + "_" + invocation | return invocation.getAttachment(DubboUtils.DUBBO_APPLICATION_KEY, "default") + "_" + invocation | ||||
@@ -58,16 +60,16 @@ public class DubboOriginRegistryTest { | |||||
}); | }); | ||||
RpcInvocation invocation = new RpcInvocation(); | RpcInvocation invocation = new RpcInvocation(); | ||||
String origin = DubboOriginParserRegistry.getDubboOriginParser().parse(null, invocation); | |||||
String origin = DubboAdapterGlobalConfig.getOriginParser().parse(null, invocation); | |||||
Assert.assertEquals("default_null", origin); | Assert.assertEquals("default_null", origin); | ||||
String dubboName = "sentinel"; | String dubboName = "sentinel"; | ||||
invocation.setAttachment(DubboUtils.DUBBO_APPLICATION_KEY, dubboName); | invocation.setAttachment(DubboUtils.DUBBO_APPLICATION_KEY, dubboName); | ||||
origin = DubboOriginParserRegistry.getDubboOriginParser().parse(null, invocation); | |||||
origin = DubboAdapterGlobalConfig.getOriginParser().parse(null, invocation); | |||||
Assert.assertEquals(dubboName + "_null", origin); | Assert.assertEquals(dubboName + "_null", origin); | ||||
invocation.setMethodName("hello"); | invocation.setMethodName("hello"); | ||||
origin = DubboOriginParserRegistry.getDubboOriginParser().parse(null, invocation); | |||||
origin = DubboAdapterGlobalConfig.getOriginParser().parse(null, invocation); | |||||
Assert.assertEquals(dubboName + "_hello", origin); | Assert.assertEquals(dubboName + "_hello", origin); | ||||
} | } | ||||
@@ -19,16 +19,14 @@ import java.util.Collections; | |||||
import java.util.concurrent.ExecutorService; | import java.util.concurrent.ExecutorService; | ||||
import java.util.concurrent.Executors; | import java.util.concurrent.Executors; | ||||
import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallbackRegistry; | |||||
import com.alibaba.csp.sentinel.adapter.dubbo.DubboAdapterGlobalConfig; | |||||
import com.alibaba.csp.sentinel.concurrent.NamedThreadFactory; | import com.alibaba.csp.sentinel.concurrent.NamedThreadFactory; | ||||
import com.alibaba.csp.sentinel.demo.dubbo.consumer.ConsumerConfiguration; | import com.alibaba.csp.sentinel.demo.dubbo.consumer.ConsumerConfiguration; | ||||
import com.alibaba.csp.sentinel.demo.dubbo.consumer.FooServiceConsumer; | import com.alibaba.csp.sentinel.demo.dubbo.consumer.FooServiceConsumer; | ||||
import com.alibaba.csp.sentinel.init.InitExecutor; | |||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant; | import com.alibaba.csp.sentinel.slots.block.RuleConstant; | ||||
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException; | 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.FlowRule; | ||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; | import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; | ||||
import com.alibaba.dubbo.rpc.Result; | |||||
import com.alibaba.dubbo.rpc.RpcResult; | import com.alibaba.dubbo.rpc.RpcResult; | ||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; | import org.springframework.context.annotation.AnnotationConfigApplicationContext; | ||||
@@ -88,7 +86,7 @@ public class FooConsumerBootstrap { | |||||
// Register fallback handler for consumer. | // Register fallback handler for consumer. | ||||
// If you only want to handle degrading, you need to | // If you only want to handle degrading, you need to | ||||
// check the type of BlockException. | // check the type of BlockException. | ||||
DubboFallbackRegistry.setConsumerFallback((a, b, ex) -> | |||||
DubboAdapterGlobalConfig.setConsumerFallback((a, b, ex) -> | |||||
new RpcResult("Error: " + ex.getClass().getTypeName())); | new RpcResult("Error: " + ex.getClass().getTypeName())); | ||||
} | } | ||||
} | } |