sentinel slot初始化逻辑分析

概述

如下图,为sentinel的一个原理图,可以看到基本就是通过各个slot来进行资源统计收集限流等,因此为了更好的了解sentinel的底层实现细节,我们对sentinel的slot的组装和初始化进行一个分析,为后期其他功能分析打好基础。
image-20210808195004802

从官方实例开始入手

sentinel的代码量还是比较多,所以无法快速定位slot的初始化的代码,因此最方便也是最直接的方式就是从入口分析开始,我们先看一下官方示例,如下代码我们可以看到SphU.entry才是限流的入口,我们就从这个方法开始分析

public static void main(String[] args) {
    // 配置规则.
    initFlowRules();

    while (true) {
        // 1.5.0 版本开始可以直接利用 try-with-resources 特性
        try (Entry entry = SphU.entry("HelloWorld")) {
            // 被保护的逻辑
            System.out.println("hello world");
	} catch (BlockException ex) {
            // 处理被流控的逻辑
	    System.out.println("blocked!");
	}
    }
}

private static void initFlowRules(){
    List<FlowRule> rules = new ArrayList<>();
    FlowRule rule = new FlowRule();
    rule.setResource("HelloWorld");
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    // Set limit QPS to 20.
    rule.setCount(20);
    rules.add(rule);
    FlowRuleManager.loadRules(rules);
}

1. 限流入口

可以看到这里调用了Env.sph的entry的方法传递了,对应的参数,看一下Evn.sph的具体实现

image-20210808192158661

2.Env.sph的具体实现

sph的具体实现为CtSph类,所以我们下一步分析entry的逻辑

image-20210804221920695

3. entry逻辑分析

这里最终调用了entryWithPriority方法,所以重点分析entryWithPriority的逻辑

image-20210808192301313

image-20210804222129333

image-20210804222146147

image-20210808192534366

以上代码主要分为2部分,第一部分为获取ProcessorSlot链如下图

ProcessorSlot<Object> chain = lookProcessChain(resourceWrapper);

第二部分执行ProcessorSlot的entry,如下图代码

chain.entry(context, resourceWrapper, null, count, prioritized, args);

我们今天主要分析第一部分,ProcessorSlot的初始化

3.1 ProcessorSlot组装与初始化

以下代码的主要逻辑首先从chainMap中获取资源,如果没有在进行初始化,初始化会调用SlotChainProvider.newSlotChain();

public class CtSph implements Sph {
  
private static volatile Map<ResourceWrapper, ProcessorSlotChain> chainMap
        = new HashMap<ResourceWrapper, ProcessorSlotChain>();
ProcessorSlot<Object> lookProcessChain(ResourceWrapper resourceWrapper) {
        ProcessorSlotChain chain = chainMap.get(resourceWrapper);
        if (chain == null) {
            synchronized (LOCK) {
                chain = chainMap.get(resourceWrapper);
                if (chain == null) {
                    // Entry size limit.
                    if (chainMap.size() >= Constants.MAX_SLOT_CHAIN_SIZE) {
                        return null;
                    }

                    chain = SlotChainProvider.newSlotChain();
                    Map<ResourceWrapper, ProcessorSlotChain> newMap = new HashMap<ResourceWrapper, ProcessorSlotChain>(
                        chainMap.size() + 1);
                    newMap.putAll(chainMap);
                    newMap.put(resourceWrapper, chain);
                    chainMap = newMap;
                }
            }
        }
        return chain;
    }
}

3.1.1 SlotChainProvider.newSlotChain()分析

newSlotChain()方法主要逻辑分为2部分

  • 第一部分 从META-INFA.services/com.alibaba.csp.sentinel.slotchain.SlotChainBuilder文件 获取SlotChainBuilder的spi实现
  • 第二部分 执行SlotChainBuilder.build方法,组装ProcessorSlotChain
public final class SlotChainProvider {

    private static volatile SlotChainBuilder slotChainBuilder = null;

    public static ProcessorSlotChain newSlotChain() {
        if (slotChainBuilder != null) {
            return slotChainBuilder.build();
        }
       
        //第一步 3.1.2 获取SlotChainBuilder的spi实现
        slotChainBuilder = SpiLoader.of(SlotChainBuilder.class).loadFirstInstanceOrDefault();

        if (slotChainBuilder == null) {
         //日志打印
            slotChainBuilder = new DefaultSlotChainBuilder();
        } else {
            //日志打印
        }
      //第二步  3.1.3 执行build方法,组装ProcessorSlotChain
        return slotChainBuilder.build();
    }

    private SlotChainProvider() {}
}
3.1.2 SlotChainBuilder 构建分析

以下代码就是获取SlotChainBuilder的spi的具体实现逻辑,先分析一下SpiLoader.of的逻辑

 SpiLoader.of(SlotChainBuilder.class).loadFirstInstanceOrDefault();
3.1.2.1 SpiLoader of的分析

of方法主要把传进去class,放入到SPI_LOADER_MAP的中,SPI_LOADER_MAP的key为class名称,value为SpiLoader实例,而在创建SpiLoader实例时传递class作为构造参数,并赋值给了service属性。这个service会在执行loadFirstInstanceOrDefault方法时候用到。


public final class SpiLoader<S> {

  
    // Cache the SpiLoader instances, key: classname of Service, value: SpiLoader instance
private static final ConcurrentHashMap<String, SpiLoader> SPI_LOADER_MAP = new ConcurrentHashMap<>();

public static <T> SpiLoader<T> of(Class<T> service) {
				...
          //获取类名称
        String className = service.getName();
        
        SpiLoader<T> spiLoader = SPI_LOADER_MAP.get(className);
        if (spiLoader == null) {
            synchronized (SpiLoader.class) {
                spiLoader = SPI_LOADER_MAP.get(className);
                if (spiLoader == null) {
                    SPI_LOADER_MAP.putIfAbsent(className, new SpiLoader<>(service));
                    spiLoader = SPI_LOADER_MAP.get(className);
                }
            }
        }

        return spiLoader;
    }
}



 private Class<S> service;

 private SpiLoader(Class<S> service) {
        this.service = service;
 }



3.1.2.2 SpiLoader loadFirstInstanceOrDefault 分析

loadFirstInstanceOrDefault 方法会根据of方法传递类获取对应实现并返回,这里分为3步,我们先看第一步load方法

    public S loadFirstInstanceOrDefault() {
      //第一步
        load();
      //第二步  
        for (Class<? extends S> clazz : classList) {
            if (defaultClass == null || clazz != defaultClass) {
                return createInstance(clazz);
            }
        }
      //第三步
        return loadDefaultInstance();
    }
3.1.2.2.1 第一步: SpiLoader.load分析

这里service在3.1.2.1 步执行Of方法进行了设置为SlotChainBuilder类,load方法总结下就是从META-INFA.services/com.alibaba.csp.sentinel.slotchain.SlotChainBuilder文件中获取对应内容,找到SlotChainBuilder对应的实现类,并把对应的实现类保存在classList、sortedClassList、classMap对象中。但是这里的load的方法不止加载SlotChainBuilder文件,也用来加载其他资源。


public final class SpiLoader<S> {
  
  
//在of方法已经进行了设置这里为SlotChainBuilder类
private Class<S> service;  
private static final String SPI_FILE_PREFIX = "META-INF/services/";
  
private final List<Class<? extends S>> classList = Collections.synchronizedList(new ArrayList<Class<? extends S>>());

      // Cache the sorted classes of Provider
private final List<Class<? extends S>> sortedClassList = Collections.synchronizedList(new ArrayList<Class<? extends S>>());

private final ConcurrentHashMap<String, Class<? extends S>> classMap = new ConcurrentHashMap<>();  
  
public void load() {
     //1 如果已经执行则返回
    if (!loaded.compareAndSet(false, true)) {
        return;
    }
    //2 fullFileName= META-INFA.services/com.alibaba.csp.sentinel.slotchain.SlotChainBuilder
    String fullFileName = SPI_FILE_PREFIX + service.getName();
    //3 就是获取classloader
    ClassLoader classLoader;
    if (SentinelConfig.shouldUseContextClassloader()) {
        classLoader = Thread.currentThread().getContextClassLoader();
    } else {
        classLoader = service.getClassLoader();
    }
    if (classLoader == null) {
        classLoader = ClassLoader.getSystemClassLoader();
    }
  
    Enumeration<URL> urls = null;
    try {
      //4 根据全路径获取具体的资源
        urls = classLoader.getResources(fullFileName);
    } catch (IOException e) {
       ...
    }

    ...

    while (urls.hasMoreElements()) {
        URL url = urls.nextElement();

        InputStream in = null;
        BufferedReader br = null;
        try {
            in = url.openStream();
            br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
            String line;
            while ((line = br.readLine()) != null) {
                ...
                line = line.trim();

                Class<S> clazz = null;
                try {
                  //5 根据文件内容转换为具体类
                    clazz = (Class<S>) Class.forName(line, false, classLoader);
                } catch (ClassNotFoundException e) {
                    fail("class " + line + " not found", e);
                }
                //6 判断clazz是不是SlotChainBuilder的子类
                if (!service.isAssignableFrom(clazz)) {
                    fail("class " + clazz.getName() + "is not subtype of " + service.getName() + ",SPI configuration file=" + fullFileName);
                }

                classList.add(clazz);
                //7 获取子类的Spi的注解,并获取的spi的value值,如果为空返回类名称作为classMap的key
                Spi spi = clazz.getAnnotation(Spi.class);
                String aliasName = spi == null || "".equals(spi.value()) ? clazz.getName() : spi.value();
                ...
                  
                classMap.put(aliasName, clazz);
                
                //8 如果spi注解标识为默认,那么defaultClass=当前子类
                if (spi != null && spi.isDefault()) {
                    if (defaultClass != null) {
                        fail("Found more than one default Provider, SPI configuration file=" + fullFileName);
                    }
                    defaultClass = clazz;
                }

            }
        } catch (IOException e) {
            fail("error reading SPI configuration file", e);
        } finally {
            closeResources(in, br);
        }
    }
     //9 把当前添加的classList的存入到sortedClassList中,并根据spi的注解的order值进行降序排序,这里因为SlotChainBuilder的子类只有一个所以这里,对他来说意义不大,但是后续ProcessorSlot加载会用到
    sortedClassList.addAll(classList);
    Collections.sort(sortedClassList, new Comparator<Class<? extends S>>() {
        @Override
        public int compare(Class<? extends S> o1, Class<? extends S> o2) {
            Spi spi1 = o1.getAnnotation(Spi.class);
            int order1 = spi1 == null ? 0 : spi1.order();

            Spi spi2 = o2.getAnnotation(Spi.class);
            int order2 = spi2 == null ? 0 : spi2.order();

            return Integer.compare(order1, order2);
        }
    });
}

} 

讲了那么多com.alibaba.csp.sentinel.slotchain.SlotChainBuilder文件,那么他的内容是什么

image-20210804231754441

DefaultSlotChainBuilder的为SlotChainBuilder具体实现类,并且有Spi注解标识,并且是默认类

image-20210804231836843

3.1.2.2.2 第二步:createInstance(clazz)分析

在3.1.2.2.1 分析中classList不为空,且值为DefaultSlotChainBuilder类,并且为defaultClass,所以这里逻辑不会走第二步,直接看第三步。

public final class SpiLoader<S> {
  
public S loadFirstInstanceOrDefault() {
      //第一步
        load();
      //第二步  
        for (Class<? extends S> clazz : classList) {
            if (defaultClass == null || clazz != defaultClass) {
                return createInstance(clazz);
            }
        }
      //第三步
        return loadDefaultInstance();
    }
}  
3.1.2.2.3 第三步:SpiLoader loadFirstInstanceOrDefault分析

loadDefaultInstance()方法,主要逻辑就是创建DefaultSlotChainBuilder实例并返回。

public final class SpiLoader<S> {
  
public S loadFirstInstanceOrDefault() {
      //第一步
        load();
      //第二步  
        for (Class<? extends S> clazz : classList) {
            if (defaultClass == null || clazz != defaultClass) {
                return createInstance(clazz);
            }
        }
      //第三步
        return loadDefaultInstance();
    }
}  

在**loadDefaultInstance()**逻辑中,又调用了load方法,这里load方法会直接返回,因为此方法已经在上面已经执行了,所以在执行到此代码快!loaded.compareAndSet(false, true)会返回false,具体请查看load方法。

疑问:看了一下loadDefaultInstance的引用,只有loadFirstInstanceOrDefault方法调用,这里可以不用调用load方法,不止为啥又要调用?懂得人可以解答一下,继续分析。

由于loadDefaultInstance()方法中的defaultClass不为空,这里为DefaultSlotChainBuilder类,作为参数传递给createInstance方法,下面看看createInstance方法具体实现

public final class SpiLoader<S> {

	public S loadDefaultInstance() {
        //有执行调用load方法。
        load();
   
        if (defaultClass == null) {
            return null;
        }

        return createInstance(defaultClass);
    }
    
    
     //这里会直接返回,因为loaded的值已经在第一次执行设置为true。
     public void load() {
        if (!loaded.compareAndSet(false, true)) {
            return;
        }
      ...
    }
}  
    

createInstance方法的参数class为DefaultSlotChainBuilder,DefaultSlotChainBuilder类上面是有@Spi(isDefault = true)注解,其次spi属性singleton默认为true,所以singleton就等于true,这里又调用了createInstance重载方法

public final class SpiLoader<S> {
  
	private S createInstance(Class<? extends S> clazz) {
    
    Spi spi = clazz.getAnnotation(Spi.class);
    boolean singleton = true;
    if (spi != null) {
        singleton = spi.isSingleton();
    }
     
    return createInstance(clazz, singleton);
}

}

/**
* DefaultSlotChainBuilder类源码
**/
@Spi(isDefault = true)
public class DefaultSlotChainBuilder implements SlotChainBuilder {

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

        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");
                continue;
            }

            chain.addLast((AbstractLinkedProcessorSlot<?>) slot);
        }

        return chain;
    }
}

createInstance(Class<? extends S> clazz, boolean singleton) 逻辑可以看到已class的名称作为key,创建class实例,存储在singletonMap中,并返回,比较简单。

public final class SpiLoader<S> {
	private final ConcurrentHashMap<String, S> singletonMap = new ConcurrentHashMap<>();
  
	private S createInstance(Class<? extends S> clazz, boolean singleton) {
    S instance = null;
    try {
        if (singleton) {
            instance = singletonMap.get(clazz.getName());
            if (instance == null) {
                synchronized (this) {
                    instance = singletonMap.get(clazz.getName());
                    if (instance == null) {
                      
                        instance = service.cast(clazz.newInstance());
                        singletonMap.put(clazz.getName(), instance);
                    }
                }
            }
        } else {
            instance = service.cast(clazz.newInstance());
        }
    } catch (Throwable e) {
        fail(clazz.getName() + " could not be instantiated");
    }
    return instance;
	}

}
3.1.2.3 SlotChainBuilder构建总结

从模块中 META-INFA.services的文件夹下查找com.alibaba.csp.sentinel.slotchain.SlotChainBuilder文件,并读取对应的内容为com.alibaba.csp.sentinel.slots.DefaultSlotChainBuilder,并构建DefaultSlotChainBuilder实例返回。

 SpiLoader.of(SlotChainBuilder.class).loadFirstInstanceOrDefault();
3.1.3 组装ProcessorSlotChain

以下代码,在第一步已经构建了SlotChainBuilder实例为DefaultSlotChainBuilder,具体清查看build方法。

public final class SlotChainProvider {

    private static volatile SlotChainBuilder slotChainBuilder = null;

    public static ProcessorSlotChain newSlotChain() {
        if (slotChainBuilder != null) {
            return slotChainBuilder.build();
        }
       
        //第一步 3.1.2 获取SlotChainBuilder的spi实现
        slotChainBuilder = SpiLoader.of(SlotChainBuilder.class).loadFirstInstanceOrDefault();

        if (slotChainBuilder == null) {
         //日志打印
            slotChainBuilder = new DefaultSlotChainBuilder();
        } else {
            //日志打印
        }
      //第二步  3.1.3 执行build方法,组装ProcessorSlotChain
        return slotChainBuilder.build();
    }

    private SlotChainProvider() {}
}
3.1.3.1ProcessorSlotChain build分析

以下代码,build方法中 SpiLoader.of(ProcessorSlot.class).loadInstanceListSorted()of方法已经在上面分析过来,具体请看3.1.2.1节,这里具体分析第一步的loadInstanceListSorted方法逻辑

@Spi(isDefault = true)
public class DefaultSlotChainBuilder implements SlotChainBuilder {

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

      //第一步:获取ProcessorSlot集合
        List<ProcessorSlot> sortedSlotList = SpiLoader.of(ProcessorSlot.class).loadInstanceListSorted();
        for (ProcessorSlot slot : sortedSlotList) {
            if (!(slot instanceof AbstractLinkedProcessorSlot)) {
                //打印日志
                continue;
            }
            //第二步: 组装ProcessorSlotChain链
            chain.addLast((AbstractLinkedProcessorSlot<?>) slot);
        }

        return chain;
    }
}

3.1.3.1.1 ProcessorSlot实现类获取分析

以下代码,loadInstanceListSorted中第一步load方法,逻辑是解析META-INF/services/com.alibaba.csp.sentinel.slotchain.ProcessorSlot文件内容并进行升序排序后然后在创建对应的实例保存在sortedClassList集合中,具体请查看3.1.2.2.1节。

public final class SpiLoader<S> {
   
private final List<Class<? extends S>> sortedClassList = Collections.synchronizedList(new ArrayList<Class<? extends S>>());

public List<S> loadInstanceListSorted() {
      //第一步
        load();
      //第二步   
        return createInstanceList(sortedClassList);
    }
}  

ProcessorSlot文件内容

image-20210805001248470

3.1.3.1.1.1 创建ProcessorSlot实例

以下代码中1、2、3步,构建ProcessorSlot实例的具体逻辑,clazzList为ProcessorSlot实现类集合。

 private List<S> createInstanceList(List<Class<? extends S>> clazzList) {
        if (clazzList == null || clazzList.size() == 0) {
            return Collections.emptyList();
        }

        List<S> instances = new ArrayList<>(clazzList.size());
        for (Class<? extends S> clazz : clazzList) {
            //第1步
            S instance = createInstance(clazz);
            instances.add(instance);
        }
        return instances;
    }

   //第2步
    private S createInstance(Class<? extends S> clazz) {
        Spi spi = clazz.getAnnotation(Spi.class);
        boolean singleton = true;
        if (spi != null) {
            singleton = spi.isSingleton();
        }
        return createInstance(clazz, singleton);
    }

    //第3步
    private S createInstance(Class<? extends S> clazz, boolean singleton) {
        S instance = null;
        try {
            if (singleton) {
                instance = singletonMap.get(clazz.getName());
                if (instance == null) {
                    synchronized (this) {
                        instance = singletonMap.get(clazz.getName());
                        if (instance == null) {
                            instance = service.cast(clazz.newInstance());
                            singletonMap.put(clazz.getName(), instance);
                        }
                    }
                }
            } else {
                instance = service.cast(clazz.newInstance());
            }
        } catch (Throwable e) {
            fail(clazz.getName() + " could not be instantiated");
        }
        return instance;
    }
}
  
  
3.1.3.1.2 组装ProcessorSlotChain总结

至此第一步已经分析完成,具体返回结果请看调试截图,与内容一致,根据order属性进行升序排序。

@Spi(isDefault = true)
public class DefaultSlotChainBuilder implements SlotChainBuilder {

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

      //第一步:获取ProcessorSlot集合
        List<ProcessorSlot> sortedSlotList = SpiLoader.of(ProcessorSlot.class).loadInstanceListSorted();
        for (ProcessorSlot slot : sortedSlotList) {
            if (!(slot instanceof AbstractLinkedProcessorSlot)) {
                //打印日志
                continue;
            }
            //第二步: 组装ProcessorSlotChain链
            chain.addLast((AbstractLinkedProcessorSlot<?>) slot);
        }

        return chain;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vtdq6Xgc-1628423013811)(/Users/dongweizhao/Library/Application Support/typora-user-images/image-20210808183618701.png)]

3.1.3.2 构建 ProcessorSlot链

第一步已经执行完成,第二步就是构建ProcessorSlotChain链,ProcessorSlotChain链为责任链模式,先分析下ProcessorSlotChain逻辑

@Spi(isDefault = true)
public class DefaultSlotChainBuilder implements SlotChainBuilder {

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

      //第一步:获取ProcessorSlot集合
        List<ProcessorSlot> sortedSlotList = SpiLoader.of(ProcessorSlot.class).loadInstanceListSorted();
        for (ProcessorSlot slot : sortedSlotList) {
            if (!(slot instanceof AbstractLinkedProcessorSlot)) {
                //打印日志
                continue;
            }
            //第二步: 组装ProcessorSlotChain链
            chain.addLast((AbstractLinkedProcessorSlot<?>) slot);
        }

        return chain;
    }
}

通过对以上代码分析,这里调用了addLast方法,可以看到根据每次设置进去的值,都作为上次end节点next节点。而end和first节点默认为内部类实现,这样就构成一个执行链,默认值顺序为

-> 内部类first
->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.block.authority.AuthoritySlot
->com.alibaba.csp.sentinel.slots.system.SystemSlot
->com.alibaba.csp.sentinel.slots.block.flow.FlowSlot
->com.alibaba.csp.sentinel.slots.block.degrade.DegradeSlot
public class DefaultProcessorSlotChain extends ProcessorSlotChain {

  
    AbstractLinkedProcessorSlot<?> first = new AbstractLinkedProcessorSlot<Object>() {

        @Override
        public void entry(Context context, ResourceWrapper resourceWrapper, Object t, int count, boolean prioritized, Object... args)
            throws Throwable {
            super.fireEntry(context, resourceWrapper, t, count, prioritized, args);
        }

        @Override
        public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
            super.fireExit(context, resourceWrapper, count, args);
        }

    };

    AbstractLinkedProcessorSlot<?> end = first;

    //第一步
    @Override
    public void addLast(AbstractLinkedProcessorSlot<?> protocolProcessor) {
          //第二步
        end.setNext(protocolProcessor);
          //第三步
        end = protocolProcessor;
    }
   ...

}


/**
 * @author qinan.qn
 * @author jialiang.linjl
 */
public abstract class AbstractLinkedProcessorSlot<T> implements ProcessorSlot<T> {

    private AbstractLinkedProcessorSlot<?> next = null;

     ...
    public AbstractLinkedProcessorSlot<?> getNext() {
        return next;
    }
  
   //第二步
    public void setNext(AbstractLinkedProcessorSlot<?> next) {
        this.next = next;
    }

}

3.2 总结

在看下下面的截图,当每次限流调用entryWithPriority方法时,首先会调用lookProcessChain方法获取slot执行链,而lookProcessChain的执行逻辑有分为2种场景。

1.如果是系统的第一次调用不是当前资源的第一次调用

lookProcessChain方法会调用**SlotChainProvider.newSlotChain()**方法进行slot的初始化。

2 .如果是资源的第一次调用非系统第一次调用

会从chainMap中已资源对象作为key,从中获取slot对象,如果没有,则调用**SlotChainProvider.newSlotChain()方法进行返回,而SlotChainProvider.newSlotChain()**方法会从缓存中返回 ProcessorSlotChain对象。

image-20210808192534366

public class CtSph implements Sph {
  
private static volatile Map<ResourceWrapper, ProcessorSlotChain> chainMap
        = new HashMap<ResourceWrapper, ProcessorSlotChain>();
ProcessorSlot<Object> lookProcessChain(ResourceWrapper resourceWrapper) {
        ProcessorSlotChain chain = chainMap.get(resourceWrapper);
        if (chain == null) {
            synchronized (LOCK) {
                chain = chainMap.get(resourceWrapper);
                if (chain == null) {
                    // Entry size limit.
                    if (chainMap.size() >= Constants.MAX_SLOT_CHAIN_SIZE) {
                        return null;
                    }

                    chain = SlotChainProvider.newSlotChain();
                    Map<ResourceWrapper, ProcessorSlotChain> newMap = new HashMap<ResourceWrapper, ProcessorSlotChain>(
                        chainMap.size() + 1);
                    newMap.putAll(chainMap);
                    newMap.put(resourceWrapper, chain);
                    chainMap = newMap;
                }
            }
        }
        return chain;
    }
}

链接

sentinel官网

sentinel源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值