- Support extensible `SlotChainBuilder` using SPI mechanism - Add a `SlotChainProvider` to load slot chain builder and create new slot chains Signed-off-by: Eric Zhao <sczyh16@gmail.com>master
@@ -28,6 +28,7 @@ import com.alibaba.csp.sentinel.slotchain.MethodResourceWrapper; | |||||
import com.alibaba.csp.sentinel.slotchain.ProcessorSlot; | import com.alibaba.csp.sentinel.slotchain.ProcessorSlot; | ||||
import com.alibaba.csp.sentinel.slotchain.ProcessorSlotChain; | import com.alibaba.csp.sentinel.slotchain.ProcessorSlotChain; | ||||
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; | import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; | ||||
import com.alibaba.csp.sentinel.slotchain.SlotChainProvider; | |||||
import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper; | import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper; | ||||
import com.alibaba.csp.sentinel.slots.block.BlockException; | import com.alibaba.csp.sentinel.slots.block.BlockException; | ||||
import com.alibaba.csp.sentinel.slots.block.Rule; | import com.alibaba.csp.sentinel.slots.block.Rule; | ||||
@@ -133,7 +134,7 @@ public class CtSph implements Sph { | |||||
return null; | return null; | ||||
} | } | ||||
chain = Env.slotsChainbuilder.build(); | |||||
chain = SlotChainProvider.newSlotChain(); | |||||
Map<ResourceWrapper, ProcessorSlotChain> newMap = new HashMap<ResourceWrapper, ProcessorSlotChain>( | Map<ResourceWrapper, ProcessorSlotChain> newMap = new HashMap<ResourceWrapper, ProcessorSlotChain>( | ||||
chainMap.size() + 1); | chainMap.size() + 1); | ||||
newMap.putAll(chainMap); | newMap.putAll(chainMap); | ||||
@@ -18,15 +18,12 @@ package com.alibaba.csp.sentinel; | |||||
import com.alibaba.csp.sentinel.init.InitExecutor; | import com.alibaba.csp.sentinel.init.InitExecutor; | ||||
import com.alibaba.csp.sentinel.node.DefaultNodeBuilder; | import com.alibaba.csp.sentinel.node.DefaultNodeBuilder; | ||||
import com.alibaba.csp.sentinel.node.NodeBuilder; | import com.alibaba.csp.sentinel.node.NodeBuilder; | ||||
import com.alibaba.csp.sentinel.slots.DefaultSlotsChainBuilder; | |||||
import com.alibaba.csp.sentinel.slots.SlotsChainBuilder; | |||||
/** | /** | ||||
* @author jialiang.linjl | * @author jialiang.linjl | ||||
*/ | */ | ||||
public class Env { | public class Env { | ||||
public static final SlotsChainBuilder slotsChainbuilder = new DefaultSlotsChainBuilder(); | |||||
public static final NodeBuilder nodeBuilder = new DefaultNodeBuilder(); | public static final NodeBuilder nodeBuilder = new DefaultNodeBuilder(); | ||||
public static final Sph sph = new CtSph(); | public static final Sph sph = new CtSph(); | ||||
@@ -13,20 +13,21 @@ | |||||
* See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | ||||
* limitations under the License. | * limitations under the License. | ||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.slots; | |||||
import com.alibaba.csp.sentinel.slotchain.ProcessorSlotChain; | |||||
package com.alibaba.csp.sentinel.slotchain; | |||||
/** | /** | ||||
* The builder for processor slot chain. | |||||
* | |||||
* @author qinan.qn | * @author qinan.qn | ||||
* @author leyou | * @author leyou | ||||
* @author Eric Zhao | |||||
*/ | */ | ||||
public interface SlotsChainBuilder { | |||||
public interface SlotChainBuilder { | |||||
/** | /** | ||||
* Helper method to create processor slot chain. | |||||
* Build the processor slot chain. | |||||
* | * | ||||
* @return a processor slot that chain some slots together. | |||||
* @return a processor slot that chain some slots together | |||||
*/ | */ | ||||
ProcessorSlotChain build(); | ProcessorSlotChain build(); | ||||
} | } |
@@ -0,0 +1,78 @@ | |||||
/* | |||||
* 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.slotchain; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
import java.util.ServiceLoader; | |||||
import com.alibaba.csp.sentinel.log.RecordLog; | |||||
import com.alibaba.csp.sentinel.slots.DefaultSlotChainBuilder; | |||||
/** | |||||
* A provider for creating slot chains via resolved slot chain builder SPI. | |||||
* | |||||
* @author Eric Zhao | |||||
* @since 0.2.0 | |||||
*/ | |||||
public final class SlotChainProvider { | |||||
private static volatile SlotChainBuilder builder = null; | |||||
private static final ServiceLoader<SlotChainBuilder> LOADER = ServiceLoader.load(SlotChainBuilder.class); | |||||
/** | |||||
* The load and pick process is not thread-safe, but it's okay since the method should be only invoked | |||||
* via {@code lookProcessChain} in {@link com.alibaba.csp.sentinel.CtSph} under lock. | |||||
* | |||||
* @return new created slot chain | |||||
*/ | |||||
public static ProcessorSlotChain newSlotChain() { | |||||
if (builder != null) { | |||||
return builder.build(); | |||||
} | |||||
resolveSlotChainBuilder(); | |||||
if (builder == null) { | |||||
RecordLog.warn("[SlotChainProvider] Wrong state when resolving slot chain builder, using default"); | |||||
builder = new DefaultSlotChainBuilder(); | |||||
} | |||||
return builder.build(); | |||||
} | |||||
private static void resolveSlotChainBuilder() { | |||||
List<SlotChainBuilder> list = new ArrayList<SlotChainBuilder>(); | |||||
boolean hasOther = false; | |||||
for (SlotChainBuilder builder : LOADER) { | |||||
if (builder.getClass() != DefaultSlotChainBuilder.class) { | |||||
hasOther = true; | |||||
list.add(builder); | |||||
} | |||||
} | |||||
if (hasOther) { | |||||
builder = list.get(0); | |||||
} else { | |||||
// No custom builder, using default. | |||||
builder = new DefaultSlotChainBuilder(); | |||||
} | |||||
RecordLog.info("[SlotChainProvider] Global slot chain builder resolved: " | |||||
+ builder.getClass().getCanonicalName()); | |||||
} | |||||
private SlotChainProvider() {} | |||||
} |
@@ -17,6 +17,7 @@ package com.alibaba.csp.sentinel.slots; | |||||
import com.alibaba.csp.sentinel.slotchain.DefaultProcessorSlotChain; | import com.alibaba.csp.sentinel.slotchain.DefaultProcessorSlotChain; | ||||
import com.alibaba.csp.sentinel.slotchain.ProcessorSlotChain; | 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.authority.AuthoritySlot; | ||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeSlot; | 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.FlowSlot; | ||||
@@ -32,7 +33,7 @@ import com.alibaba.csp.sentinel.slots.system.SystemSlot; | |||||
* @author qinan.qn | * @author qinan.qn | ||||
* @author leyou | * @author leyou | ||||
*/ | */ | ||||
public class DefaultSlotsChainBuilder implements SlotsChainBuilder { | |||||
public class DefaultSlotChainBuilder implements SlotChainBuilder { | |||||
@Override | @Override | ||||
public ProcessorSlotChain build() { | public ProcessorSlotChain build() { |
@@ -0,0 +1,2 @@ | |||||
# Default slot chain builder | |||||
com.alibaba.csp.sentinel.slots.DefaultSlotChainBuilder |