Context 代表调用链路上下文,贯穿一次调用链路中的所有 Entry。Context 维持着入口节点entranceNode、本次调用链路的 curNode、调用来源origin等信息。Context 名称即为调用链路入口名称。Sentinel将上下文放在ThreadLocal中存储。在源码中经常看到Context context = contextHolder.get();,该代码即为在线程中获取上下文Context。

Context创建只发生在两个地方,第一个是ContextUtil初始化时,第二个是调用ContextUtil.enter(name, origin)。
package com.alibaba.csp.sentinel.context;
/**
* Utility class to get or create {@link Context} in current thread.
* Each {@link SphU}#entry() or {@link SphO}#entry() should be in a {@link Context}.
* If we don't invoke {@link ContextUtil}#enter() explicitly, DEFAULT context will be used.
*/
public class ContextUtil {
/*省略部分代码。。。。。。*/
static {
// Cache the entrance node for default context.
initDefaultContext();
}
private static void initDefaultContext() {
String defaultContextName = Constants.CONTEXT_DEFAULT_NAME;
/*初始化一个sentinel_default_context,type为in的队形*/
EntranceNode node = new EntranceNode(new StringResourceWrapper(defaultContextName, EntryType.IN), null);
/*Constants.ROOT会初始化一个name是machine-root,type=IN的对象*/
Constants.ROOT.addChild(node);
/*map添加key=CONTEXT_DEFAULT_NAME的对象*/
contextNameNodeMap.put(defaultContextName, node);
}
}
/*省略部分代码。。。。。。*/
ContextUtil初始化时会执行static代码块,initDefaultContext方法会创建一个名为sentinel_default_context的EntranceNode做为节点接入ROOT节点。并把该节点放入contextNameNodeMap中,该map添加了volatile关键字,轻量级的线程之间可以互相看见的共享操作。
protected static Context trueEnter(String name, String origin) {
Context context = contextHolder.get();
if (context == null) {
Map<String, DefaultNode> localCacheNameMap = contextNameNodeMap;
/*在contextNameNodeMap中查找是否有已存在的node*/
DefaultNode node = localCacheNameMap.get(name);
if (node == null) {
if (localCacheNameMap.size() > Constants.MAX_CONTEXT_NAME_SIZE) {
setNullContext();
return NULL_CONTEXT;
} else {
try {
LOCK.lock();
/*类似initDefaultContext方法的内容,但不一样*/
node = contextNameNodeMap.get(name);
if (node == null) {
if (contextNameNodeMap.size() > Constants.MAX_CONTEXT_NAME_SIZE) {
setNullContext();
return NULL_CONTEXT;
} else {
/*此处创建的node名字为ContextUtil.enter中的name*/
node = new EntranceNode(new StringResourceWrapper(name, EntryType.IN), null);
/*以下代码提升迭代稳定性,防止脏读*/
Constants.ROOT.addChild(node);
Map<String, DefaultNode> newMap = new HashMap<>(contextNameNodeMap.size() + 1);
newMap.putAll(contextNameNodeMap);
newMap.put(name, node);
contextNameNodeMap = newMap;
}
}
} finally {
LOCK.unlock();
}
}
}
context = new Context(node, name);
context.setOrigin(origin);
contextHolder.set(context);
}
return context;
}
Sentinel源码(流量入口)
文章转载自安全链,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




