Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the slot as the SPI interface and add a @Order annotation for define slot order #411

Merged
merged 8 commits into from
Mar 26, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@
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<DefaultNode> {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

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.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;
Expand All @@ -31,8 +31,13 @@
/**
* @author Eric Zhao
* @since 1.6.1
*
* @deprecated since 1.7.2, we can use @SpiOrder(-4000) to adjust the order of slots,
* this class is reserved for compatibility with older versions.
* @see {@link GatewayFlowSlot}
*/
public class GatewaySlotChainBuilder implements SlotChainBuilder {
@Deprecated
public class GatewaySlotChainBuilder extends DefaultSlotChainBuilder {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh if you take my advice keeping an empty legacy one you should make it a real EMPTY one.
According to the new DefaultSlotChainBuilder i think there is no need keeping overriding of build() here, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry for misunderstanding the point.It has been fixed, please check.


@Override
public ProcessorSlotChain build() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.alibaba.csp.sentinel.adapter.gateway.common.slot.GatewayFlowSlot

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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}.
Expand All @@ -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<ProcessorSlot> 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;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@
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.
*
* @author leyou
* @author Eric Zhao
*/
@SpiOrder(-6000)
public class AuthoritySlot extends AbstractLinkedProcessorSlot<DefaultNode> {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
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<DefaultNode> {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
* <p>
* Combined the runtime statistics collected from the previous
Expand Down Expand Up @@ -136,6 +137,7 @@
* @author jialiang.linjl
* @author Eric Zhao
*/
@SpiOrder(-2000)
public class FlowSlot extends AbstractLinkedProcessorSlot<DefaultNode> {

private final FlowRuleChecker checker;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
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;

/**
* <p>
Expand All @@ -44,6 +45,7 @@
*
* @author jialiang.linjl
*/
@SpiOrder(-9000)
public class ClusterBuilderSlot extends AbstractLinkedProcessorSlot<DefaultNode> {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@
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<DefaultNode> {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
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;
Expand Down Expand Up @@ -122,6 +123,7 @@
* @see EntranceNode
* @see ContextUtil
*/
@SpiOrder(-10000)
public class NodeSelectorSlot extends AbstractLinkedProcessorSlot<Object> {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
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;
Expand All @@ -47,6 +48,7 @@
* @author jialiang.linjl
* @author Eric Zhao
*/
@SpiOrder(-7000)
public class StatisticSlot extends AbstractLinkedProcessorSlot<DefaultNode> {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
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.
*
* @author jialiang.linjl
* @author leyou
*/
@SpiOrder(-5000)
public class SystemSlot extends AbstractLinkedProcessorSlot<DefaultNode> {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ public static <T> T loadHighestPriorityInstance(Class<T> clazz) {
}

/**
* Load and sorted SPI instance list.
* Load the SPI instance list for provided SPI interface.
*
* @param clazz class of the SPI
Expand Down Expand Up @@ -161,6 +162,8 @@ public static <T> List<T> loadInstanceList(Class<T> clazz) {
/**
* Load the sorted SPI instance list for provided SPI interface.
*
* Note: each call return new instances.
*
* @param clazz class of the SPI
* @param <T> SPI type
* @return sorted SPI instance list
Expand Down Expand Up @@ -196,6 +199,41 @@ public static <T> List<T> loadInstanceListSorted(Class<T> clazz) {
}
}

/**
* 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 <T> SPI type
* @return sorted and different SPI instance list
* @since 1.7.2
*/
public static <T> List<T> loadDifferentInstanceListSorted(Class<T> clazz) {
try {
// Not use SERVICE_LOADER_MAP, to make sure the instances loaded are different.
ServiceLoader<T> serviceLoader = ServiceLoaderUtil.getServiceLoader(clazz);

List<SpiOrderWrapper<T>> 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<T> 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 <T> void insertSorted(List<SpiOrderWrapper<T>> list, T spi, int order) {
int idx = 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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);
}
}
Loading