- 包含很多static的初始化塊,并通過ServiceLoader的方式加載各種類
一 static初始化塊

static初始化塊.png
二 CtSph
- 提供資源請求entry初始化函數(shù)
2.1 同步context
- 1 超過可限流的context入口類型數(shù),則不做限流
- 2 未指定則使用默認名稱的context入口節(jié)點
- 3 全局限流開關(guān)
Constants.ON,關(guān)閉則不做限流 - 4 獲取當前資源對應(yīng)的處理鏈,每個資源對應(yīng)一個處理鏈,名稱活方法表示資源
- 5 資源對應(yīng)的資源節(jié)點處理鏈數(shù)達到上限,則后續(xù)資源請求不做處理
- 6 實例化資源請求Entry,按資源節(jié)點處理鏈依次處理,進行統(tǒng)計,資源申請等操作
- 7 資源申請失敗,按處理鏈做失敗統(tǒng)計等處理
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
- 根據(jù)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 獲取資源節(jié)點處理鏈
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 類結(jié)構(gòu)圖

entry類.png
3.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);
}
- 設(shè)置Entry父子關(guān)系,更新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);
}
- 保存對應(yīng)的context名稱
- 保存資源請求時間
public Entry(ResourceWrapper resourceWrapper) {
this.resourceWrapper = resourceWrapper;
this.createTime = TimeUtil.currentTimeMillis();
}
3.2.2 資源請求失敗處理
- 1 失敗的entry非context當前entry,則按entry父子關(guān)系依次向上調(diào)用所有entry的失敗處理函數(shù)exit()
- 2 失敗entry是context的當前entry,
調(diào)用資源處理鏈的exit函數(shù)
更新context的curEntry為請求失敗Entry的父節(jié)點Entry
刪除Entry的父子關(guān)系
如Entry無父節(jié)點,則若是默認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
四 節(jié)點關(guān)系圖

image.png