Skip to content

Commit

Permalink
Refactor SpiLoader and enhance SPI mechanism (alibaba#1383)
Browse files Browse the repository at this point in the history
* Add `@Spi` annotation as the general annotation for SPI definition.
* Add isDefault in @SPI, add loadDefaultInstance and improve loadFirstInstanceOrDefault method, improve test cases
* Add SpiLoaderException class for thrown when something goes wrong while loading Provider
* Rearrange packages of base SPI mechanism

NOTE: this PR contains breaking changes regarding API.
  • Loading branch information
cdfive authored and taz committed Aug 14, 2021
1 parent 82fe4e9 commit ac3bebc
Show file tree
Hide file tree
Showing 50 changed files with 1,124 additions and 619 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import com.alibaba.csp.sentinel.property.PropertyListener;
import com.alibaba.csp.sentinel.property.SentinelProperty;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.csp.sentinel.util.SpiLoader;
import com.alibaba.csp.sentinel.spi.SpiLoader;
import com.alibaba.csp.sentinel.util.StringUtil;

/**
Expand Down Expand Up @@ -59,7 +59,7 @@ public final class GatewayApiDefinitionManager {
}

private static void initializeApiChangeObserverSpi() {
List<ApiDefinitionChangeObserver> listeners = SpiLoader.loadInstanceList(ApiDefinitionChangeObserver.class);
List<ApiDefinitionChangeObserver> listeners = SpiLoader.of(ApiDefinitionChangeObserver.class).loadInstanceList();
for (ApiDefinitionChangeObserver e : listeners) {
API_CHANGE_OBSERVERS.put(e.getClass().getCanonicalName(), e);
RecordLog.info("[GatewayApiDefinitionManager] ApiDefinitionChangeObserver added: {}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +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;
import com.alibaba.csp.sentinel.spi.Spi;

/**
* @author Eric Zhao
* @since 1.6.1
*/
@SpiOrder(-4000)
@Spi(order = -4000)
public class GatewayFlowSlot extends AbstractLinkedProcessorSlot<DefaultNode> {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
* @author Eric Zhao
* @since 1.6.1
*
* @deprecated since 1.7.2, we can use @SpiOrder(-4000) to adjust the order of {@link GatewayFlowSlot},
* @deprecated since 1.7.2, we can use @Spi(order = -4000) to adjust the order of {@link GatewayFlowSlot},
* this class is reserved for compatibility with older versions.
*
* @see GatewayFlowSlot
* @see DefaultSlotChainBuilder
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
package com.alibaba.csp.sentinel.cluster.client.codec;

import com.alibaba.csp.sentinel.util.SpiLoader;
import com.alibaba.csp.sentinel.spi.SpiLoader;
import com.alibaba.csp.sentinel.cluster.codec.request.RequestEntityWriter;
import com.alibaba.csp.sentinel.cluster.codec.response.ResponseEntityDecoder;
import com.alibaba.csp.sentinel.log.RecordLog;
Expand All @@ -34,15 +34,15 @@ public final class ClientEntityCodecProvider {
}

private static void resolveInstance() {
RequestEntityWriter writer = SpiLoader.loadFirstInstance(RequestEntityWriter.class);
RequestEntityWriter writer = SpiLoader.of(RequestEntityWriter.class).loadFirstInstance();
if (writer == null) {
RecordLog.warn("[ClientEntityCodecProvider] No existing request entity writer, resolve failed");
} else {
requestEntityWriter = writer;
RecordLog.info("[ClientEntityCodecProvider] Request entity writer resolved: {}",
requestEntityWriter.getClass().getCanonicalName());
}
ResponseEntityDecoder decoder = SpiLoader.loadFirstInstance(ResponseEntityDecoder.class);
ResponseEntityDecoder decoder = SpiLoader.of(ResponseEntityDecoder.class).loadFirstInstance();
if (decoder == null) {
RecordLog.warn("[ClientEntityCodecProvider] No existing response entity decoder, resolve failed");
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.alibaba.csp.sentinel.cluster.flow.rule.ClusterParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.spi.Spi;

import java.util.Collection;

Expand All @@ -31,6 +32,7 @@
* @author Eric Zhao
* @since 1.4.0
*/
@Spi(isDefault = true)
public class DefaultTokenService implements TokenService {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@
package com.alibaba.csp.sentinel.cluster.server;

import com.alibaba.csp.sentinel.cluster.TokenService;
import com.alibaba.csp.sentinel.cluster.flow.DefaultTokenService;
import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.util.SpiLoader;
import com.alibaba.csp.sentinel.spi.SpiLoader;

/**
* @author Eric Zhao
Expand All @@ -37,7 +36,7 @@ public static TokenService getService() {
}

private static void resolveTokenServiceSpi() {
service = SpiLoader.loadFirstInstanceOrDefault(TokenService.class, DefaultTokenService.class);
service = SpiLoader.of(TokenService.class).loadFirstInstanceOrDefault();
if (service != null) {
RecordLog.info("[TokenServiceProvider] Global token service resolved: "
+ service.getClass().getCanonicalName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import com.alibaba.csp.sentinel.cluster.codec.request.RequestEntityDecoder;
import com.alibaba.csp.sentinel.cluster.codec.response.ResponseEntityWriter;
import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.util.SpiLoader;
import com.alibaba.csp.sentinel.spi.SpiLoader;

/**
* @author Eric Zhao
Expand All @@ -34,15 +34,15 @@ public final class ServerEntityCodecProvider {
}

private static void resolveInstance() {
ResponseEntityWriter writer = SpiLoader.loadFirstInstance(ResponseEntityWriter.class);
ResponseEntityWriter writer = SpiLoader.of(ResponseEntityWriter.class).loadFirstInstance();
if (writer == null) {
RecordLog.warn("[ServerEntityCodecProvider] No existing response entity writer, resolve failed");
} else {
responseEntityWriter = writer;
RecordLog.info("[ServerEntityCodecProvider] Response entity writer resolved: {}",
responseEntityWriter.getClass().getCanonicalName());
}
RequestEntityDecoder decoder = SpiLoader.loadFirstInstance(RequestEntityDecoder.class);
RequestEntityDecoder decoder = SpiLoader.of(RequestEntityDecoder.class).loadFirstInstance();
if (decoder == null) {
RecordLog.warn("[ServerEntityCodecProvider] No existing request entity decoder, resolve failed");
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
*/
package com.alibaba.csp.sentinel.cluster.server.processor;

import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;

import com.alibaba.csp.sentinel.cluster.annotation.RequestType;
import com.alibaba.csp.sentinel.spi.ServiceLoaderUtil;
import com.alibaba.csp.sentinel.spi.SpiLoader;
import com.alibaba.csp.sentinel.util.AssertUtil;

/**
Expand All @@ -31,15 +31,13 @@ public final class RequestProcessorProvider {

private static final Map<Integer, RequestProcessor> PROCESSOR_MAP = new ConcurrentHashMap<>();

private static final ServiceLoader<RequestProcessor> SERVICE_LOADER = ServiceLoaderUtil.getServiceLoader(
RequestProcessor.class);

static {
loadAndInit();
}

private static void loadAndInit() {
for (RequestProcessor processor : SERVICE_LOADER) {
List<RequestProcessor> processors = SpiLoader.of(RequestProcessor.class).loadInstanceList();
for (RequestProcessor processor : processors) {
Integer type = parseRequestType(processor);
if (type != null) {
PROCESSOR_MAP.put(type, processor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,17 @@ public final class Constants {
*/
public static volatile boolean ON = true;

/**
* Order of default processor slots
*/
public static final int ORDER_NODE_SELECTOR_SLOT = -10000;
public static final int ORDER_CLUSTER_BUILDER_SLOT = -9000;
public static final int ORDER_LOG_SLOT = -8000;
public static final int ORDER_STATISTIC_SLOT = -7000;
public static final int ORDER_AUTHORITY_SLOT = -6000;
public static final int ORDER_SYSTEM_SLOT = -5000;
public static final int ORDER_FLOW_SLOT = -2000;
public static final int ORDER_DEGRADE_SLOT = -1000;

private Constants() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
package com.alibaba.csp.sentinel.cluster.client;

import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.util.SpiLoader;
import com.alibaba.csp.sentinel.spi.SpiLoader;

/**
* Provider for a universal {@link ClusterTokenClient} instance.
Expand All @@ -38,7 +38,7 @@ public static ClusterTokenClient getClient() {
}

private static void resolveTokenClientInstance() {
ClusterTokenClient resolvedClient = SpiLoader.loadFirstInstance(ClusterTokenClient.class);
ClusterTokenClient resolvedClient = SpiLoader.of(ClusterTokenClient.class).loadFirstInstance();
if (resolvedClient == null) {
RecordLog.info(
"[TokenClientProvider] No existing cluster token client, cluster client mode will not be activated");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
package com.alibaba.csp.sentinel.cluster.server;

import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.util.SpiLoader;
import com.alibaba.csp.sentinel.spi.SpiLoader;

/**
* @author Eric Zhao
Expand All @@ -31,7 +31,7 @@ public final class EmbeddedClusterTokenServerProvider {
}

private static void resolveInstance() {
EmbeddedClusterTokenServer s = SpiLoader.loadFirstInstance(EmbeddedClusterTokenServer.class);
EmbeddedClusterTokenServer s = SpiLoader.of(EmbeddedClusterTokenServer.class).loadFirstInstance();
if (s == null) {
RecordLog.warn("[EmbeddedClusterTokenServerProvider] No existing cluster token server, cluster server mode will not be activated");
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ public final class SentinelConfig {
*/
public static final int APP_TYPE_COMMON = 0;

/**
* Parameter value for using context classloader.
*/
private static final String CLASSLOADER_CONTEXT = "context";

private static final Map<String, String> props = new ConcurrentHashMap<>();

private static int appType = APP_TYPE_COMMON;
Expand Down Expand Up @@ -307,6 +312,15 @@ private static void resolveAppName() {
private static String toEnvKey(/*@NotBlank*/ String propKey) {
return propKey.toUpperCase().replace('.', '_');
}
/**
* Whether use context classloader via config parameter
*
* @return Whether use context classloader
*/
public static boolean shouldUseContextClassloader() {
String classloaderConf = SentinelConfig.getConfig(SentinelConfig.SPI_CLASSLOADER);
return CLASSLOADER_CONTEXT.equalsIgnoreCase(classloaderConf);
}

private SentinelConfig() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import java.util.concurrent.atomic.AtomicBoolean;

import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.spi.ServiceLoaderUtil;
import com.alibaba.csp.sentinel.spi.SpiLoader;

/**
* Load registered init functions and execute in order.
Expand All @@ -43,9 +43,9 @@ public static void doInit() {
return;
}
try {
ServiceLoader<InitFunc> loader = ServiceLoaderUtil.getServiceLoader(InitFunc.class);
List<InitFunc> initFuncs = SpiLoader.of(InitFunc.class).loadInstanceListSorted();
List<OrderWrapper> initList = new ArrayList<OrderWrapper>();
for (InitFunc initFunc : loader) {
for (InitFunc initFunc : initFuncs) {
RecordLog.info("[InitExecutor] Found init func: {}", initFunc.getClass().getCanonicalName());
insertSorted(initList, initFunc);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import java.util.List;

import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.util.SpiLoader;
import com.alibaba.csp.sentinel.spi.SpiLoader;

/**
* Get all {@link MetricExtension} via SPI.
Expand All @@ -35,7 +35,7 @@ public class MetricExtensionProvider {
}

private static void resolveInstance() {
List<MetricExtension> extensions = SpiLoader.loadInstanceList(MetricExtension.class);
List<MetricExtension> extensions = SpiLoader.of(MetricExtension.class).loadInstanceList();

if (extensions.isEmpty()) {
RecordLog.info("[MetricExtensionProvider] No existing MetricExtension found");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.slots.DefaultSlotChainBuilder;
import com.alibaba.csp.sentinel.util.SpiLoader;
import com.alibaba.csp.sentinel.spi.SpiLoader;

/**
* A provider for creating slot chains via resolved slot chain builder SPI.
Expand All @@ -41,7 +41,7 @@ public static ProcessorSlotChain newSlotChain() {
}

// Resolve the slot chain builder SPI.
slotChainBuilder = SpiLoader.loadFirstInstanceOrDefault(SlotChainBuilder.class, DefaultSlotChainBuilder.class);
slotChainBuilder = SpiLoader.of(SlotChainBuilder.class).loadFirstInstanceOrDefault();

if (slotChainBuilder == null) {
// Should not go through here.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
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.util.SpiLoader;
import com.alibaba.csp.sentinel.spi.Spi;
import com.alibaba.csp.sentinel.spi.SpiLoader;

import java.util.List;

Expand All @@ -31,14 +32,14 @@
* @author qinan.qn
* @author leyou
*/
@Spi(isDefault = true)
public class DefaultSlotChainBuilder implements SlotChainBuilder {

@Override
public ProcessorSlotChain build() {
ProcessorSlotChain chain = new DefaultProcessorSlotChain();

// Note: the instances of ProcessorSlot should be different, since they are not stateless.
List<ProcessorSlot> sortedSlotList = SpiLoader.loadPrototypeInstanceListSorted(ProcessorSlot.class);
List<ProcessorSlot> sortedSlotList = SpiLoader.of(ProcessorSlot.class).loadInstanceListSorted();
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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,21 @@
import java.util.Map;
import java.util.Set;

import com.alibaba.csp.sentinel.Constants;
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.ProcessorSlot;
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
import com.alibaba.csp.sentinel.spi.SpiOrder;
import com.alibaba.csp.sentinel.spi.Spi;

/**
* A {@link ProcessorSlot} that dedicates to {@link AuthorityRule} checking.
*
* @author leyou
* @author Eric Zhao
*/
@SpiOrder(-6000)
@Spi(order = Constants.ORDER_AUTHORITY_SLOT)
public class AuthoritySlot extends AbstractLinkedProcessorSlot<DefaultNode> {

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

import java.util.List;

import com.alibaba.csp.sentinel.Constants;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.context.Context;
import com.alibaba.csp.sentinel.node.DefaultNode;
Expand All @@ -25,15 +26,15 @@
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreaker;
import com.alibaba.csp.sentinel.spi.SpiOrder;
import com.alibaba.csp.sentinel.spi.Spi;

/**
* A {@link ProcessorSlot} dedicates to circuit breaking.
*
* @author Carpenter Lee
* @author Eric Zhao
*/
@SpiOrder(-1000)
@Spi(order = Constants.ORDER_DEGRADE_SLOT)
public class DegradeSlot extends AbstractLinkedProcessorSlot<DefaultNode> {

@Override
Expand Down
Loading

0 comments on commit ac3bebc

Please sign in to comment.