Sentinel源码分析四、NodeSelectorSlot

NodeSelectorSlot

以下分析Slot代码, 只针对entry方法。exit方法不多做分析。有兴趣的可以自行查看。

NodeSelectorSlot的代码不多,但是却是最复杂的一个Slot。要理解这个Slot的代码,首先需要搞清楚Context相关的内容。

之前简单说明了一下Context,一个持有元数据的上下文,所谓的元数据主要是Entry,而Entry是一个双向链表,构成了一个调用链。

这里进一步分析Entry、Context、Node,为理解NodeSelectorSlot做准备。

回到com.alibaba.csp.sentinel.CtSph#entryWithPriority(com.alibaba.csp.sentinel.slotchain.ResourceWrapper, int, boolean, java.lang.Object…)的代码:

private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args)
    throws BlockException {
    Context context = ContextUtil.getContext();
    if (context instanceof NullContext) {
        // The {@link NullContext} indicates that the amount of context has exceeded the threshold,
        // so here init the entry only. No rule checking will be done.
        return new CtEntry(resourceWrapper, null, context);
    }

    if (context == null) {
        // Using default context.
        context = InternalContextUtil.internalEnter(Constants.CONTEXT_DEFAULT_NAME);
    }

    // Global switch is close, no rule checking will do.
    if (!Constants.ON) {
        return new CtEntry(resourceWrapper, null, context);
    }

    // 获取该资源对应的SlotChain
    ProcessorSlot<Object> chain = lookProcessChain(resourceWrapper);

    /*
     * Means amount of resources (slot chain) exceeds {@link Constants.MAX_SLOT_CHAIN_SIZE},
     * so no rule checking will be done.
     */
    if (chain == null) {
        return new CtEntry(resourceWrapper, null, context);
    }

    Entry e = new CtEntry(resourceWrapper, chain, context);
    try {
        // 执行Slot的entry方法
        chain.entry(context, resourceWrapper, null, count, prioritized, args);
    } catch (BlockException e1) {
        // 抛出BlockExecption
        e.exit(count, args);
        throw e1;
    } catch (Throwable e1) {
        // This should not happen, unless there are errors existing in Sentinel internal.
        RecordLog.info("Sentinel unexpected exception", e1);
    }
    return e;
}

先看一下Entry的创建过程

CtEntry(ResourceWrapper resourceWrapper, ProcessorSlot<Object> chain, Context context) {
    super(resourceWrapper);
    this.chain = chain;
    this.context = context;

    setUpEntryFor(context);
}
 private void setUpEntryFor(Context context) {
        // The entry should not be associated to NullContext.
        if (context instanceof NullContext) {
            return;
        }
        // 获取「上下文」中上一次的入口
        this.parent = context.getCurEntry();
        if (parent != null) {
            // 然后将当前入口设置为上一次入口的子节点
            ((CtEntry) parent).child = this;
        }
        // 设置「上下文」的当前入口为该类本身
        context.setCurEntry(this);
    }

每次进行entry调用都会创建一个新的CtEntry,当Context 不变的情况下,context下的curEntry会设置对应的parent和child,同时curEntry指向最新的创建的CtEntry。这里就构成了一个双向链表。

而Context的创建和销毁过程是如何处理的呢?

详细分析一下Context的创建过程

context = InternalContextUtil.internalEnter(Constants.CONTEXT_DEFAULT_NAME);

private final static class InternalContextUtil extends ContextUtil {
   
    static Context internalEnter(String name) {
   
        return trueEnter(name, "");
    }

    static Context internalEnter(String name, String origin) {
   
        return trueEnter(name, origin);
    }
}

 protected 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值