Support extensible slot chain builder using SPI mechanism (#145)

- 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>
This commit is contained in:
Eric Zhao 2018-09-12 13:53:43 +08:00 committed by GitHub
parent d142a07a39
commit ca2f4d9fae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 91 additions and 11 deletions

View File

@ -28,6 +28,7 @@ import com.alibaba.csp.sentinel.slotchain.MethodResourceWrapper;
import com.alibaba.csp.sentinel.slotchain.ProcessorSlot;
import com.alibaba.csp.sentinel.slotchain.ProcessorSlotChain;
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.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.Rule;
@ -133,7 +134,7 @@ public class CtSph implements Sph {
return null;
}
chain = Env.slotsChainbuilder.build();
chain = SlotChainProvider.newSlotChain();
Map<ResourceWrapper, ProcessorSlotChain> newMap = new HashMap<ResourceWrapper, ProcessorSlotChain>(
chainMap.size() + 1);
newMap.putAll(chainMap);

View File

@ -18,15 +18,12 @@ package com.alibaba.csp.sentinel;
import com.alibaba.csp.sentinel.init.InitExecutor;
import com.alibaba.csp.sentinel.node.DefaultNodeBuilder;
import com.alibaba.csp.sentinel.node.NodeBuilder;
import com.alibaba.csp.sentinel.slots.DefaultSlotsChainBuilder;
import com.alibaba.csp.sentinel.slots.SlotsChainBuilder;
/**
* @author jialiang.linjl
*/
public class Env {
public static final SlotsChainBuilder slotsChainbuilder = new DefaultSlotsChainBuilder();
public static final NodeBuilder nodeBuilder = new DefaultNodeBuilder();
public static final Sph sph = new CtSph();

View File

@ -13,20 +13,21 @@
* 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.ProcessorSlotChain;
package com.alibaba.csp.sentinel.slotchain;
/**
* The builder for processor slot chain.
*
* @author qinan.qn
* @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();
}

View File

@ -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() {}
}

View File

@ -17,6 +17,7 @@ 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;
@ -32,7 +33,7 @@ import com.alibaba.csp.sentinel.slots.system.SystemSlot;
* @author qinan.qn
* @author leyou
*/
public class DefaultSlotsChainBuilder implements SlotsChainBuilder {
public class DefaultSlotChainBuilder implements SlotChainBuilder {
@Override
public ProcessorSlotChain build() {

View File

@ -0,0 +1,2 @@
# Default slot chain builder
com.alibaba.csp.sentinel.slots.DefaultSlotChainBuilder