前言
Context组件在sentinel中扮演的是一种什么样的角色呢?借用原作者的注释:
This class holds metadata of current invocation
其实就是保存一次资源访问链路元数据的类,链路的各个节点都能通过获取链路绑定的context来获取一些信息进行相应的处理。很多涉及链路的框架都会有类似设计,例如netty的ChannelHandlerContext,go语言网络包中的context等等。下面通过源码分析sentinel中Context的创建和使用流程。
Context结构
com.alibaba.csp.sentinel.context.Context
public class Context {
/**
* Context name.
*/
private final String name;
/**
* The entrance node of current invocation tree.
*/
private DefaultNode entranceNode;
/**
* Current processing entry.
*/
private Entry curEntry;
/**
* The origin of this context (usually indicate different invokers, e.g. service consumer name or origin IP).
*/
private String origin = "";
private final boolean async;
...
Context类主要由五个成员变量组成,分别是
- name,一般是访问的资源名
- entranceNode,就是记录当次链路流控信号量的node
- curEntry,当前Context所属的entry
- origin, 资源访问者信息
- async,是否异步
Context创建
Context通常通过ContextUtil的enter方法创建,我们可以先看下ContextUtil类的源码
com.alibaba.csp.sentinel.context.ContextUtil
public class ContextUtil {
/**
* Store the context in ThreadLocal for easy access.
*/
private static ThreadLocal<Context> contextHolder = new ThreadLocal<>();
/**
* Holds all {@link EntranceNode}. Each {@link EntranceNode} is associated with a distinct context name.
*/
private static volatile Map<String, DefaultNode> contextNameNodeMap = new HashMap<>();
private static final ReentrantLock LOCK = new ReentrantLock();
private static final Context NULL_CONTEXT = new NullContext();
static {
// Cache the entrance node for default context.
initDefaultContext();
}
private static void initDefaultContext() {
String defaultContextName = Constants.CONTEXT_DEFAULT_NAME;
EntranceNode node = new EntranceNode(new Str