From be4d058bf83ccb43a6bf763b3374945046f3bbab Mon Sep 17 00:00:00 2001 From: cdfive <31885791+cdfive@users.noreply.github.com> Date: Thu, 26 Mar 2020 12:38:01 +0800 Subject: [PATCH] refactor: Make the ProcessorSlot itself as SPI and deprecate legacy slot chain builder (#411) * Make slots loaded by SPI, mark all slots with @SpiOrder from -10000 to -1000, improve comment * Reserve gateway and param slot chain builder (just extends DefaultSlotChainBuilder) and mark them as @Deprecated --- .../gateway/common/slot/GatewayFlowSlot.java | 2 + .../common/slot/GatewaySlotChainBuilder.java | 41 +---- ...ibaba.csp.sentinel.slotchain.ProcessorSlot | 1 + ...ba.csp.sentinel.slotchain.SlotChainBuilder | 1 - .../slots/DefaultSlotChainBuilder.java | 34 ++-- .../slots/block/authority/AuthoritySlot.java | 2 + .../slots/block/degrade/DegradeSlot.java | 2 + .../sentinel/slots/block/flow/FlowSlot.java | 10 +- .../clusterbuilder/ClusterBuilderSlot.java | 2 + .../csp/sentinel/slots/logger/LogSlot.java | 2 + .../slots/nodeselector/NodeSelectorSlot.java | 2 + .../slots/statistic/StatisticSlot.java | 2 + .../csp/sentinel/slots/system/SystemSlot.java | 2 + .../alibaba/csp/sentinel/util/SpiLoader.java | 38 +++++ ...ibaba.csp.sentinel.slotchain.ProcessorSlot | 9 ++ .../slots/DefaultSlotChainBuilderTest.java | 89 +++++++++++ .../csp/sentinel/util/SpiLoaderTest.java | 146 ++++++++++++++++++ .../slots/HotParamSlotChainBuilder.java | 34 +--- .../slots/block/flow/param/ParamFlowSlot.java | 6 +- ...ibaba.csp.sentinel.slotchain.ProcessorSlot | 1 + ...ba.csp.sentinel.slotchain.SlotChainBuilder | 1 - 21 files changed, 342 insertions(+), 85 deletions(-) create mode 100644 sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.ProcessorSlot delete mode 100644 sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.SlotChainBuilder create mode 100644 sentinel-core/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.ProcessorSlot create mode 100644 sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/DefaultSlotChainBuilderTest.java create mode 100644 sentinel-core/src/test/java/com/alibaba/csp/sentinel/util/SpiLoaderTest.java create mode 100644 sentinel-extension/sentinel-parameter-flow-control/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.ProcessorSlot delete mode 100644 sentinel-extension/sentinel-parameter-flow-control/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.SlotChainBuilder diff --git a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/slot/GatewayFlowSlot.java b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/slot/GatewayFlowSlot.java index 15151729..b0932b7c 100644 --- a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/slot/GatewayFlowSlot.java +++ b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/slot/GatewayFlowSlot.java @@ -27,11 +27,13 @@ import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowChecker; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule; import com.alibaba.csp.sentinel.slots.block.flow.param.ParameterMetricStorage; +import com.alibaba.csp.sentinel.spi.SpiOrder; /** * @author Eric Zhao * @since 1.6.1 */ +@SpiOrder(-4000) public class GatewayFlowSlot extends AbstractLinkedProcessorSlot { @Override diff --git a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/slot/GatewaySlotChainBuilder.java b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/slot/GatewaySlotChainBuilder.java index 383e4653..204b4619 100644 --- a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/slot/GatewaySlotChainBuilder.java +++ b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/slot/GatewaySlotChainBuilder.java @@ -15,43 +15,18 @@ */ package com.alibaba.csp.sentinel.adapter.gateway.common.slot; -import com.alibaba.csp.sentinel.slotchain.DefaultProcessorSlotChain; -import com.alibaba.csp.sentinel.slotchain.ProcessorSlotChain; -import com.alibaba.csp.sentinel.slotchain.SlotChainBuilder; -import com.alibaba.csp.sentinel.slots.block.authority.AuthoritySlot; -import com.alibaba.csp.sentinel.slots.block.degrade.DegradeSlot; -import com.alibaba.csp.sentinel.slots.block.flow.FlowSlot; -import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowSlot; -import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot; -import com.alibaba.csp.sentinel.slots.logger.LogSlot; -import com.alibaba.csp.sentinel.slots.nodeselector.NodeSelectorSlot; -import com.alibaba.csp.sentinel.slots.statistic.StatisticSlot; -import com.alibaba.csp.sentinel.slots.system.SystemSlot; +import com.alibaba.csp.sentinel.slots.DefaultSlotChainBuilder; /** * @author Eric Zhao * @since 1.6.1 + * + * @deprecated since 1.7.2, we can use @SpiOrder(-4000) to adjust the order of {@link GatewayFlowSlot}, + * this class is reserved for compatibility with older versions. + * @see GatewayFlowSlot + * @see DefaultSlotChainBuilder */ -public class GatewaySlotChainBuilder implements SlotChainBuilder { - - @Override - public ProcessorSlotChain build() { - ProcessorSlotChain chain = new DefaultProcessorSlotChain(); - // Prepare slot - chain.addLast(new NodeSelectorSlot()); - chain.addLast(new ClusterBuilderSlot()); - // Stat slot - chain.addLast(new LogSlot()); - chain.addLast(new StatisticSlot()); - // Rule checking slot - chain.addLast(new AuthoritySlot()); - chain.addLast(new SystemSlot()); - chain.addLast(new GatewayFlowSlot()); - - chain.addLast(new ParamFlowSlot()); - chain.addLast(new FlowSlot()); - chain.addLast(new DegradeSlot()); +@Deprecated +public class GatewaySlotChainBuilder extends DefaultSlotChainBuilder { - return chain; - } } diff --git a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.ProcessorSlot b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.ProcessorSlot new file mode 100644 index 00000000..190da2e8 --- /dev/null +++ b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.ProcessorSlot @@ -0,0 +1 @@ +com.alibaba.csp.sentinel.adapter.gateway.common.slot.GatewayFlowSlot \ No newline at end of file diff --git a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.SlotChainBuilder b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.SlotChainBuilder deleted file mode 100644 index 5f9fde56..00000000 --- a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.SlotChainBuilder +++ /dev/null @@ -1 +0,0 @@ -com.alibaba.csp.sentinel.adapter.gateway.common.slot.GatewaySlotChainBuilder \ No newline at end of file diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/DefaultSlotChainBuilder.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/DefaultSlotChainBuilder.java index 56aa851a..797206bb 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/DefaultSlotChainBuilder.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/DefaultSlotChainBuilder.java @@ -15,17 +15,15 @@ */ package com.alibaba.csp.sentinel.slots; +import com.alibaba.csp.sentinel.log.RecordLog; +import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot; import com.alibaba.csp.sentinel.slotchain.DefaultProcessorSlotChain; +import com.alibaba.csp.sentinel.slotchain.ProcessorSlot; import com.alibaba.csp.sentinel.slotchain.ProcessorSlotChain; import com.alibaba.csp.sentinel.slotchain.SlotChainBuilder; -import com.alibaba.csp.sentinel.slots.block.authority.AuthoritySlot; -import com.alibaba.csp.sentinel.slots.block.degrade.DegradeSlot; -import com.alibaba.csp.sentinel.slots.block.flow.FlowSlot; -import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot; -import com.alibaba.csp.sentinel.slots.logger.LogSlot; -import com.alibaba.csp.sentinel.slots.nodeselector.NodeSelectorSlot; -import com.alibaba.csp.sentinel.slots.statistic.StatisticSlot; -import com.alibaba.csp.sentinel.slots.system.SystemSlot; +import com.alibaba.csp.sentinel.util.SpiLoader; + +import java.util.List; /** * Builder for a default {@link ProcessorSlotChain}. @@ -38,16 +36,18 @@ public class DefaultSlotChainBuilder implements SlotChainBuilder { @Override public ProcessorSlotChain build() { ProcessorSlotChain chain = new DefaultProcessorSlotChain(); - chain.addLast(new NodeSelectorSlot()); - chain.addLast(new ClusterBuilderSlot()); - chain.addLast(new LogSlot()); - chain.addLast(new StatisticSlot()); - chain.addLast(new AuthoritySlot()); - chain.addLast(new SystemSlot()); - chain.addLast(new FlowSlot()); - chain.addLast(new DegradeSlot()); + + // Note: the instances of ProcessorSlot should be different, since they are not stateless. + List sortedSlotList = SpiLoader.loadDifferentInstanceListSorted(ProcessorSlot.class); + for (ProcessorSlot slot : sortedSlotList) { + if (!(slot instanceof AbstractLinkedProcessorSlot)) { + RecordLog.warn("The ProcessorSlot(" + slot.getClass().getCanonicalName() + ") is not an instance of AbstractLinkedProcessorSlot, can't be added into ProcessorSlotChain"); + continue; + } + + chain.addLast((AbstractLinkedProcessorSlot) slot); + } return chain; } - } diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/authority/AuthoritySlot.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/authority/AuthoritySlot.java index f7920baa..617521a6 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/authority/AuthoritySlot.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/authority/AuthoritySlot.java @@ -23,6 +23,7 @@ import com.alibaba.csp.sentinel.node.DefaultNode; import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot; import com.alibaba.csp.sentinel.slotchain.ProcessorSlot; import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; +import com.alibaba.csp.sentinel.spi.SpiOrder; /** * A {@link ProcessorSlot} that dedicates to {@link AuthorityRule} checking. @@ -30,6 +31,7 @@ import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; * @author leyou * @author Eric Zhao */ +@SpiOrder(-6000) public class AuthoritySlot extends AbstractLinkedProcessorSlot { @Override diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/degrade/DegradeSlot.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/degrade/DegradeSlot.java index f76d81f8..8e8dd191 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/degrade/DegradeSlot.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/degrade/DegradeSlot.java @@ -20,12 +20,14 @@ import com.alibaba.csp.sentinel.node.DefaultNode; import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot; import com.alibaba.csp.sentinel.slotchain.ProcessorSlot; import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; +import com.alibaba.csp.sentinel.spi.SpiOrder; /** * A {@link ProcessorSlot} dedicates to {@link DegradeRule} checking. * * @author leyou */ +@SpiOrder(-1000) public class DegradeSlot extends AbstractLinkedProcessorSlot { @Override diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlot.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlot.java index f99987f7..d05d51c8 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlot.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlot.java @@ -15,18 +15,19 @@ */ package com.alibaba.csp.sentinel.slots.block.flow; -import java.util.Collection; -import java.util.List; -import java.util.Map; - import com.alibaba.csp.sentinel.context.Context; import com.alibaba.csp.sentinel.node.DefaultNode; import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot; import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; import com.alibaba.csp.sentinel.slots.block.BlockException; +import com.alibaba.csp.sentinel.spi.SpiOrder; import com.alibaba.csp.sentinel.util.AssertUtil; import com.alibaba.csp.sentinel.util.function.Function; +import java.util.Collection; +import java.util.List; +import java.util.Map; + /** *

* Combined the runtime statistics collected from the previous @@ -136,6 +137,7 @@ import com.alibaba.csp.sentinel.util.function.Function; * @author jialiang.linjl * @author Eric Zhao */ +@SpiOrder(-2000) public class FlowSlot extends AbstractLinkedProcessorSlot { private final FlowRuleChecker checker; diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/clusterbuilder/ClusterBuilderSlot.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/clusterbuilder/ClusterBuilderSlot.java index b4ee5918..62ea366a 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/clusterbuilder/ClusterBuilderSlot.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/clusterbuilder/ClusterBuilderSlot.java @@ -30,6 +30,7 @@ import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot; import com.alibaba.csp.sentinel.slotchain.ProcessorSlotChain; import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper; +import com.alibaba.csp.sentinel.spi.SpiOrder; /** *

@@ -44,6 +45,7 @@ import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper; * * @author jialiang.linjl */ +@SpiOrder(-9000) public class ClusterBuilderSlot extends AbstractLinkedProcessorSlot { /** diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/logger/LogSlot.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/logger/LogSlot.java index 802690a9..a7515b01 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/logger/LogSlot.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/logger/LogSlot.java @@ -21,11 +21,13 @@ import com.alibaba.csp.sentinel.node.DefaultNode; import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot; import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; import com.alibaba.csp.sentinel.slots.block.BlockException; +import com.alibaba.csp.sentinel.spi.SpiOrder; /** * A {@link com.alibaba.csp.sentinel.slotchain.ProcessorSlot} that is response for logging block exceptions * to provide concrete logs for troubleshooting. */ +@SpiOrder(-8000) public class LogSlot extends AbstractLinkedProcessorSlot { @Override diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/nodeselector/NodeSelectorSlot.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/nodeselector/NodeSelectorSlot.java index f09f19e7..c965137f 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/nodeselector/NodeSelectorSlot.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/nodeselector/NodeSelectorSlot.java @@ -22,6 +22,7 @@ import com.alibaba.csp.sentinel.node.DefaultNode; import com.alibaba.csp.sentinel.node.EntranceNode; import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot; import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; +import com.alibaba.csp.sentinel.spi.SpiOrder; import java.util.HashMap; import java.util.Map; @@ -122,6 +123,7 @@ import java.util.Map; * @see EntranceNode * @see ContextUtil */ +@SpiOrder(-10000) public class NodeSelectorSlot extends AbstractLinkedProcessorSlot { /** diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/StatisticSlot.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/StatisticSlot.java index 09affecc..96005d31 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/StatisticSlot.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/StatisticSlot.java @@ -21,6 +21,7 @@ import com.alibaba.csp.sentinel.config.SentinelConfig; import com.alibaba.csp.sentinel.slotchain.ProcessorSlotEntryCallback; import com.alibaba.csp.sentinel.slotchain.ProcessorSlotExitCallback; import com.alibaba.csp.sentinel.slots.block.flow.PriorityWaitException; +import com.alibaba.csp.sentinel.spi.SpiOrder; import com.alibaba.csp.sentinel.util.TimeUtil; import com.alibaba.csp.sentinel.Constants; import com.alibaba.csp.sentinel.EntryType; @@ -47,6 +48,7 @@ import com.alibaba.csp.sentinel.slots.block.BlockException; * @author jialiang.linjl * @author Eric Zhao */ +@SpiOrder(-7000) public class StatisticSlot extends AbstractLinkedProcessorSlot { @Override diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemSlot.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemSlot.java index 1f67e426..5912e622 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemSlot.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemSlot.java @@ -20,6 +20,7 @@ import com.alibaba.csp.sentinel.node.DefaultNode; import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot; import com.alibaba.csp.sentinel.slotchain.ProcessorSlot; import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; +import com.alibaba.csp.sentinel.spi.SpiOrder; /** * A {@link ProcessorSlot} that dedicates to {@link SystemRule} checking. @@ -27,6 +28,7 @@ import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; * @author jialiang.linjl * @author leyou */ +@SpiOrder(-5000) public class SystemSlot extends AbstractLinkedProcessorSlot { @Override diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/util/SpiLoader.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/util/SpiLoader.java index 3aff826b..a677084e 100644 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/util/SpiLoader.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/util/SpiLoader.java @@ -129,6 +129,7 @@ public final class SpiLoader { } /** + * Load and sorted SPI instance list. * Load the SPI instance list for provided SPI interface. * * @param clazz class of the SPI @@ -161,6 +162,8 @@ public final class SpiLoader { /** * Load the sorted SPI instance list for provided SPI interface. * + * Note: each call return new instances. + * * @param clazz class of the SPI * @param SPI type * @return sorted SPI instance list @@ -196,6 +199,41 @@ public final class SpiLoader { } } + /** + * Load the sorted and different SPI instance list for provided SPI interface. + * + * Note: each call return new instances. + * + * @param clazz class of the SPI + * @param SPI type + * @return sorted and different SPI instance list + * @since 1.7.2 + */ + public static List loadDifferentInstanceListSorted(Class clazz) { + try { + // Not use SERVICE_LOADER_MAP, to make sure the instances loaded are different. + ServiceLoader serviceLoader = ServiceLoaderUtil.getServiceLoader(clazz); + + List> orderWrappers = new ArrayList<>(); + for (T spi : serviceLoader) { + int order = SpiOrderResolver.resolveOrder(spi); + // Since SPI is lazy initialized in ServiceLoader, we use online sort algorithm here. + SpiOrderResolver.insertSorted(orderWrappers, spi, order); + RecordLog.info("[SpiLoader] Found {0} SPI: {1} with order " + order, clazz.getSimpleName(), + spi.getClass().getCanonicalName()); + } + List list = new ArrayList<>(); + for (int i = 0; i < orderWrappers.size(); i++) { + list.add(i, orderWrappers.get(i).spi); + } + return list; + } catch (Throwable t) { + RecordLog.warn("[SpiLoader] ERROR: loadDifferentInstanceListSorted failed", t); + t.printStackTrace(); + return new ArrayList<>(); + } + } + private static class SpiOrderResolver { private static void insertSorted(List> list, T spi, int order) { int idx = 0; diff --git a/sentinel-core/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.ProcessorSlot b/sentinel-core/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.ProcessorSlot new file mode 100644 index 00000000..f4a3cf79 --- /dev/null +++ b/sentinel-core/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.ProcessorSlot @@ -0,0 +1,9 @@ +# Sentinel default ProcessorSlots +com.alibaba.csp.sentinel.slots.nodeselector.NodeSelectorSlot +com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot +com.alibaba.csp.sentinel.slots.logger.LogSlot +com.alibaba.csp.sentinel.slots.statistic.StatisticSlot +com.alibaba.csp.sentinel.slots.system.SystemSlot +com.alibaba.csp.sentinel.slots.block.authority.AuthoritySlot +com.alibaba.csp.sentinel.slots.block.flow.FlowSlot +com.alibaba.csp.sentinel.slots.block.degrade.DegradeSlot \ No newline at end of file diff --git a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/DefaultSlotChainBuilderTest.java b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/DefaultSlotChainBuilderTest.java new file mode 100644 index 00000000..ecdea6da --- /dev/null +++ b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/DefaultSlotChainBuilderTest.java @@ -0,0 +1,89 @@ +/* + * 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.slots; + +import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot; +import com.alibaba.csp.sentinel.slotchain.ProcessorSlotChain; +import com.alibaba.csp.sentinel.slots.block.authority.AuthoritySlot; +import com.alibaba.csp.sentinel.slots.block.degrade.DegradeSlot; +import com.alibaba.csp.sentinel.slots.block.flow.FlowSlot; +import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot; +import com.alibaba.csp.sentinel.slots.logger.LogSlot; +import com.alibaba.csp.sentinel.slots.nodeselector.NodeSelectorSlot; +import com.alibaba.csp.sentinel.slots.statistic.StatisticSlot; +import com.alibaba.csp.sentinel.slots.system.SystemSlot; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Test cases for {@link DefaultSlotChainBuilder}. + * + * @author cdfive + */ +public class DefaultSlotChainBuilderTest { + + @Test + public void testBuild() { + DefaultSlotChainBuilder builder = new DefaultSlotChainBuilder(); + ProcessorSlotChain slotChain = builder.build(); + assertNotNull(slotChain); + + // Verify the order of slot + AbstractLinkedProcessorSlot next = slotChain.getNext(); + assertTrue(next instanceof NodeSelectorSlot); + + // Store the first NodeSelectorSlot instance + NodeSelectorSlot nodeSelectorSlot = (NodeSelectorSlot) next; + + next = next.getNext(); + assertTrue(next instanceof ClusterBuilderSlot); + + next = next.getNext(); + assertTrue(next instanceof LogSlot); + + next = next.getNext(); + assertTrue(next instanceof StatisticSlot); + + next = next.getNext(); + assertTrue(next instanceof AuthoritySlot); + + next = next.getNext(); + assertTrue(next instanceof SystemSlot); + + next = next.getNext(); + assertTrue(next instanceof FlowSlot); + + next = next.getNext(); + assertTrue(next instanceof DegradeSlot); + + next = next.getNext(); + assertNull(next); + + // Build again to verify different instances + ProcessorSlotChain slotChain2 = builder.build(); + assertNotNull(slotChain2); + // Verify the two ProcessorSlotChain instances are different + assertNotSame(slotChain, slotChain2); + + next = slotChain2.getNext(); + assertTrue(next instanceof NodeSelectorSlot); + // Store the second NodeSelectorSlot instance + NodeSelectorSlot nodeSelectorSlot2 = (NodeSelectorSlot) next; + // Verify the two NodeSelectorSlot instances are different + assertNotSame(nodeSelectorSlot, nodeSelectorSlot2); + } +} diff --git a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/util/SpiLoaderTest.java b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/util/SpiLoaderTest.java new file mode 100644 index 00000000..ba353fa2 --- /dev/null +++ b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/util/SpiLoaderTest.java @@ -0,0 +1,146 @@ +/* + * 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.util; + +import com.alibaba.csp.sentinel.slotchain.ProcessorSlot; +import com.alibaba.csp.sentinel.slotchain.SlotChainBuilder; +import com.alibaba.csp.sentinel.slots.DefaultSlotChainBuilder; +import com.alibaba.csp.sentinel.slots.block.authority.AuthoritySlot; +import com.alibaba.csp.sentinel.slots.block.degrade.DegradeSlot; +import com.alibaba.csp.sentinel.slots.block.flow.FlowSlot; +import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot; +import com.alibaba.csp.sentinel.slots.logger.LogSlot; +import com.alibaba.csp.sentinel.slots.nodeselector.NodeSelectorSlot; +import com.alibaba.csp.sentinel.slots.statistic.StatisticSlot; +import com.alibaba.csp.sentinel.slots.system.SystemSlot; +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.*; + +/** + * Test cases for {@link SpiLoader}. + * + * @author cdfive + */ +public class SpiLoaderTest { + + @Test + public void testLoadFirstInstance() { + ProcessorSlot processorSlot = SpiLoader.loadFirstInstance(ProcessorSlot.class); + assertNotNull(processorSlot); + + SlotChainBuilder slotChainBuilder = SpiLoader.loadFirstInstance(SlotChainBuilder.class); + assertNotNull(slotChainBuilder); + assertTrue(slotChainBuilder instanceof DefaultSlotChainBuilder); + } + + @Test + public void testLoadHighestPriorityInstance() { + ProcessorSlot processorSlot = SpiLoader.loadHighestPriorityInstance(ProcessorSlot.class); + assertNotNull(processorSlot); + + // NodeSelectorSlot is highest order with @SpiOrder(-9000), among all slots + assertTrue(processorSlot instanceof NodeSelectorSlot); + } + + @Test + public void testLoadInstanceList() { + List slots = SpiLoader.loadInstanceList(ProcessorSlot.class); + assertNotNull(slots); + + // Total 8 default slot in sentinel-core + assertEquals(8, slots.size()); + + // Store the first slot of slots + ProcessorSlot firstSlot = slots.get(0); + + // Call loadInstanceList again + List slots2 = SpiLoader.loadInstanceList(ProcessorSlot.class); + assertNotSame(slots, slots2); + + // Store the first slot of slots + ProcessorSlot firstSlot2 = slots2.get(0); + + // As SERVICE_LOADER_MAP in SpiLoader cached the instance, so they're same instances + assertSame(firstSlot, firstSlot2); + } + + @Test + public void testLoadInstanceListSorted() { + List sortedSlots = SpiLoader.loadInstanceListSorted(ProcessorSlot.class); + assertNotNull(sortedSlots); + + // Total 8 default slot in sentinel-core + assertEquals(8, sortedSlots.size()); + + // Verify the order of slot + int index = 0; + assertTrue(sortedSlots.get(index++) instanceof NodeSelectorSlot); + assertTrue(sortedSlots.get(index++) instanceof ClusterBuilderSlot); + assertTrue(sortedSlots.get(index++) instanceof LogSlot); + assertTrue(sortedSlots.get(index++) instanceof StatisticSlot); + assertTrue(sortedSlots.get(index++) instanceof AuthoritySlot); + assertTrue(sortedSlots.get(index++) instanceof SystemSlot); + assertTrue(sortedSlots.get(index++) instanceof FlowSlot); + assertTrue(sortedSlots.get(index++) instanceof DegradeSlot); + + // Verify each call return different instances + List sortedSlots2 = SpiLoader.loadInstanceListSorted(ProcessorSlot.class); + assertNotSame(sortedSlots, sortedSlots2); + assertEquals(sortedSlots.size(), sortedSlots2.size()); + for (int i = 0; i < sortedSlots.size(); i++) { + ProcessorSlot slot = sortedSlots.get(i); + ProcessorSlot slot2 = sortedSlots2.get(i); + assertEquals(slot.getClass(), slot2.getClass()); + } + } + + @Test + public void testLoadDifferentInstanceListSorted() { + List sortedSlots = SpiLoader.loadInstanceListSorted(ProcessorSlot.class); + assertNotNull(sortedSlots); + + // Total 8 default slot in sentinel-core + assertEquals(8, sortedSlots.size()); + + // Verify the order of slot + int index = 0; + assertTrue(sortedSlots.get(index++) instanceof NodeSelectorSlot); + assertTrue(sortedSlots.get(index++) instanceof ClusterBuilderSlot); + assertTrue(sortedSlots.get(index++) instanceof LogSlot); + assertTrue(sortedSlots.get(index++) instanceof StatisticSlot); + assertTrue(sortedSlots.get(index++) instanceof AuthoritySlot); + assertTrue(sortedSlots.get(index++) instanceof SystemSlot); + assertTrue(sortedSlots.get(index++) instanceof FlowSlot); + assertTrue(sortedSlots.get(index++) instanceof DegradeSlot); + + // Verify each call return different instances + List sortedSlots2 = SpiLoader.loadDifferentInstanceListSorted(ProcessorSlot.class); + assertNotSame(sortedSlots, sortedSlots2); + assertEquals(sortedSlots.size(), sortedSlots2.size()); + for (int i = 0; i < sortedSlots.size(); i++) { + ProcessorSlot slot = sortedSlots.get(i); + ProcessorSlot slot2 = sortedSlots2.get(i); + assertEquals(slot.getClass(), slot2.getClass()); + + // Verify the instances are different + assertNotSame(slot, slot2); + assertNotEquals(slot, slot2); + } + } +} diff --git a/sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/HotParamSlotChainBuilder.java b/sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/HotParamSlotChainBuilder.java index baf8d8ad..d44aab3d 100644 --- a/sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/HotParamSlotChainBuilder.java +++ b/sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/HotParamSlotChainBuilder.java @@ -15,38 +15,18 @@ */ package com.alibaba.csp.sentinel.slots; -import com.alibaba.csp.sentinel.slotchain.DefaultProcessorSlotChain; -import com.alibaba.csp.sentinel.slotchain.ProcessorSlotChain; -import com.alibaba.csp.sentinel.slotchain.SlotChainBuilder; -import com.alibaba.csp.sentinel.slots.block.authority.AuthoritySlot; -import com.alibaba.csp.sentinel.slots.block.degrade.DegradeSlot; -import com.alibaba.csp.sentinel.slots.block.flow.FlowSlot; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowSlot; -import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot; -import com.alibaba.csp.sentinel.slots.logger.LogSlot; -import com.alibaba.csp.sentinel.slots.nodeselector.NodeSelectorSlot; -import com.alibaba.csp.sentinel.slots.statistic.StatisticSlot; -import com.alibaba.csp.sentinel.slots.system.SystemSlot; /** * @author Eric Zhao * @since 0.2.0 + * + * @deprecated since 1.7.2, we can use @SpiOrder(-3000) to adjust the order of {@link ParamFlowSlot}, + * this class is reserved for compatibility with older versions. + * @see ParamFlowSlot + * @see DefaultSlotChainBuilder */ -public class HotParamSlotChainBuilder implements SlotChainBuilder { - - @Override - public ProcessorSlotChain build() { - ProcessorSlotChain chain = new DefaultProcessorSlotChain(); - chain.addLast(new NodeSelectorSlot()); - chain.addLast(new ClusterBuilderSlot()); - chain.addLast(new LogSlot()); - chain.addLast(new StatisticSlot()); - chain.addLast(new AuthoritySlot()); - chain.addLast(new SystemSlot()); - chain.addLast(new ParamFlowSlot()); - chain.addLast(new FlowSlot()); - chain.addLast(new DegradeSlot()); +@Deprecated +public class HotParamSlotChainBuilder extends DefaultSlotChainBuilder { - return chain; - } } diff --git a/sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowSlot.java b/sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowSlot.java index 7da682cf..8bf0dff0 100644 --- a/sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowSlot.java +++ b/sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowSlot.java @@ -15,13 +15,14 @@ */ package com.alibaba.csp.sentinel.slots.block.flow.param; -import java.util.List; - import com.alibaba.csp.sentinel.context.Context; import com.alibaba.csp.sentinel.node.DefaultNode; import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot; import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; import com.alibaba.csp.sentinel.slots.block.BlockException; +import com.alibaba.csp.sentinel.spi.SpiOrder; + +import java.util.List; /** * A processor slot that is responsible for flow control by frequent ("hot spot") parameters. @@ -30,6 +31,7 @@ import com.alibaba.csp.sentinel.slots.block.BlockException; * @author Eric Zhao * @since 0.2.0 */ +@SpiOrder(-3000) public class ParamFlowSlot extends AbstractLinkedProcessorSlot { @Override diff --git a/sentinel-extension/sentinel-parameter-flow-control/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.ProcessorSlot b/sentinel-extension/sentinel-parameter-flow-control/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.ProcessorSlot new file mode 100644 index 00000000..8832f16b --- /dev/null +++ b/sentinel-extension/sentinel-parameter-flow-control/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.ProcessorSlot @@ -0,0 +1 @@ +com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowSlot \ No newline at end of file diff --git a/sentinel-extension/sentinel-parameter-flow-control/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.SlotChainBuilder b/sentinel-extension/sentinel-parameter-flow-control/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.SlotChainBuilder deleted file mode 100644 index a0354c1e..00000000 --- a/sentinel-extension/sentinel-parameter-flow-control/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.SlotChainBuilder +++ /dev/null @@ -1 +0,0 @@ -com.alibaba.csp.sentinel.slots.HotParamSlotChainBuilder \ No newline at end of file