sentinal源码2-初始化
2019-03-30 本文已影响0人
modou1618
- 包含很多static的初始化块,并通过ServiceLoader的方式加载各种类
一 static初始化块
static初始化块.png二 CtSph
- 提供资源请求entry初始化函数
2.1 同步context
- 1 超过可限流的context入口类型数,则不做限流
- 2 未指定则使用默认名称的context入口节点
- 3 全局限流开关
Constants.ON
,关闭则不做限流 - 4 获取当前资源对应的处理链,每个资源对应一个处理链,名称活方法表示资源
- 5 资源对应的资源节点处理链数达到上限,则后续资源请求不做处理
- 6 实例化资源请求Entry,按资源节点处理链依次处理,进行统计,资源申请等操作
- 7 资源申请失败,按处理链做失败统计等处理
private Entry entryWithPriority(ResourceWrapper resourceWrapper, int count, boolean prioritized, Object... args)
throws BlockException {
Context context = ContextUtil.getContext();
if (context instanceof NullContext) { //1
return new CtEntry(resourceWrapper, null, context);
}
if (context == null) {//2
context = MyContextUtil.myEnter(Constants.CONTEXT_DEFAULT_NAME, "", resourceWrapper.getType());
}
if (!Constants.ON) {//3
return new CtEntry(resourceWrapper, null, context);
}
ProcessorSlot<Object> chain = lookProcessChain(resourceWrapper);//4
if (chain == null) {//5
return new CtEntry(resourceWrapper, null, context);
}
Entry e = new CtEntry(resourceWrapper, chain, context);
try {
chain.entry(context, resourceWrapper, null, count, prioritized, args);//6
} catch (BlockException e1) {
e.exit(count, args);//7
throw e1;
} catch (Throwable e1) {
RecordLog.info("Sentinel unexpected exception", e1);
}
return e;
}
2.1.1 lookProcessChain
- 根据context名称获取处理链
- 使用hashmap存储
private static volatile Map<ResourceWrapper, ProcessorSlotChain> chainMap = new HashMap<ResourceWrapper, ProcessorSlotChain>();
- 二次加锁校验方式初始化
- 写拷贝更新的方式更新存储map
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;
}
2.1.2 获取资源节点处理链
public ProcessorSlotChain build() {
ProcessorSlotChain chain = new DefaultProcessorSlotChain();
chain.addLast(new NodeSelectorSlot());
chain.addLast(new ClusterBuilderSlot());
chain.addLast(new LogSlot());
chain.addLast(new StatisticSlot());
chain.addLast(new SystemSlot());
chain.addLast(new AuthoritySlot());
chain.addLast(new FlowSlot());
chain.addLast(new DegradeSlot());
return chain;
}
2.2 异步context
//todo
三 Entry
3.1 类结构图
entry类.png3.2 CtEntry
3.2.1 实例化
- Entry实例化
- 保存资源处理链,资源处理上下文context
CtEntry(ResourceWrapper resourceWrapper, ProcessorSlot<Object> chain, Context context) {
super(resourceWrapper);
this.chain = chain;
this.context = context;
setUpEntryFor(context);
}
- 设置Entry父子关系,更新context.curEntry为本次新建的Entry
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);
}
- 保存对应的context名称
- 保存资源请求时间
public Entry(ResourceWrapper resourceWrapper) {
this.resourceWrapper = resourceWrapper;
this.createTime = TimeUtil.currentTimeMillis();
}
3.2.2 资源请求失败处理
- 1 失败的entry非context当前entry,则按entry父子关系依次向上调用所有entry的失败处理函数exit()
- 2 失败entry是context的当前entry,
调用资源处理链的exit函数
更新context的curEntry为请求失败Entry的父节点Entry
删除Entry的父子关系
如Entry无父节点,则若是默认context则需要自动清理,手动配置的context则由用户手动退出。
清理Entry的context属性
protected void exitForContext(Context context, int count, Object... args) throws ErrorEntryFreeException {
if (context != null) {
// Null context should exit without clean-up.
if (context instanceof NullContext) {
return;
}
if (context.getCurEntry() != this) {//1
String curEntryNameInContext = context.getCurEntry() == null ? null : context.getCurEntry().getResourceWrapper().getName();
// Clean previous call stack.
CtEntry e = (CtEntry)context.getCurEntry();
while (e != null) {
e.exit(count, args);
e = (CtEntry)e.parent;
}
String errorMessage = String.format("The order of entry exit can't be paired with the order of entry"
+ ", current entry in context: <%s>, but expected: <%s>", curEntryNameInContext, resourceWrapper.getName());
throw new ErrorEntryFreeException(errorMessage);
} else {//2
if (chain != null) {
chain.exit(context, resourceWrapper, count, args);
}
context.setCurEntry(parent);
if (parent != null) {
((CtEntry)parent).child = null;
}
if (parent == null) {
if (ContextUtil.isDefaultContext(context)) {
ContextUtil.exit();
}
}
clearEntryContext();
}
}
}
- 清理线程变量缓存的context
public static void exit() {
Context context = contextHolder.get();
if (context != null && context.getCurEntry() == null) {
contextHolder.set(null);
}
}
3.3 AsyncEntry
//todo