Sentinel-NodeSelectorSlot
NodeSelectorSlot解析
在理解这一章前,可以先阅读sentinel整体架构可能了解起来更有帮助。
在NodeSelectorSlot中维护这变量 private volatile Map<String, DefaultNode> map = new HashMap<String, DefaultNode>(10);
相同资源共享一个chain,也就使用同一个NodeSelectorSlot对象。其中key表示context name 而value表示DefaultNode,说明对于相同的资源名称的不同contextName中各自有一个defaultNode,并添加到数结构中。
代码如下:
@Override public void entry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized, Object... args) throws Throwable { /* * It's interesting that we use context name rather resource name as the map key. * * Remember that same resource({@link ResourceWrapper#equals(Object)}) will share * the same {@link ProcessorSlotChain} globally, no matter in which context. So if * code goes into {@link #entry(Context, ResourceWrapper, DefaultNode, int, Object...)}, * the resource name must be same but context name may not. * * If we use {@link com.alibaba.csp.sentinel.SphU#entry(String resource)} to * enter same resource in different context, using context name as map key can * distinguish the same resource. In this case, multiple {@link DefaultNode}s will be created * of the same resource name, for every distinct context (different context name) each. * * Consider another question. One resource may have multiple {@link DefaultNode}, * so what is the fastest way to get total statistics of the same resource? * The answer is all {@link DefaultNode}s with same resource name share one * {@link ClusterNode}. See {@link ClusterBuilderSlot} for detail. */ DefaultNode node = map.get(context.getName()); if (node == null) { synchronized (this) { node = map.get(context.getName()); if (node == null) { node = new DefaultNode(resourceWrapper, null); HashMap<String, DefaultNode> cacheMap = new HashMap<String, DefaultNode>(map.size()); cacheMap.putAll(map); cacheMap.put(context.getName(), node); map = cacheMap; // Build invocation tree // 这边会继续构建调用树 /** * 相同资源的DefaultNode 不同context name的 都会添加到对应的entranceNode上, * 如果context name相同 资源名称也相同 则 DefaultNode在多线程内共享 */ ((DefaultNode)context.getLastNode()).addChild(node); } } } // 设置context的当前node为当前资源的的defaultNode context.setCurNode(node); // 触发下一个slot fireEntry(context, resourceWrapper, node, count, prioritized, args); }