- 包含很多static的初始化塊魄衅,并通過(guò)ServiceLoader的方式加載各種類
一 static初始化塊
static初始化塊.png
二 CtSph
- 提供資源請(qǐng)求entry初始化函數(shù)
2.1 同步context
- 1 超過(guò)可限流的context入口類型數(shù)晃虫,則不做限流
- 2 未指定則使用默認(rèn)名稱的context入口節(jié)點(diǎn)
- 3 全局限流開(kāi)關(guān)
Constants.ON
,關(guān)閉則不做限流 - 4 獲取當(dāng)前資源對(duì)應(yīng)的處理鏈毅访,每個(gè)資源對(duì)應(yīng)一個(gè)處理鏈盘榨,名稱活方法表示資源
- 5 資源對(duì)應(yīng)的資源節(jié)點(diǎn)處理鏈數(shù)達(dá)到上限,則后續(xù)資源請(qǐng)求不做處理
- 6 實(shí)例化資源請(qǐng)求Entry守呜,按資源節(jié)點(diǎn)處理鏈依次處理山憨,進(jìn)行統(tǒng)計(jì)郁竟,資源申請(qǐng)等操作
- 7 資源申請(qǐng)失敗,按處理鏈做失敗統(tǒng)計(jì)等處理
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存儲(chǔ)
private static volatile Map<ResourceWrapper, ProcessorSlotChain> chainMap = new HashMap<ResourceWrapper, ProcessorSlotChain>();
- 二次加鎖校驗(yàn)方式初始化
- 寫拷貝更新的方式更新存儲(chǔ)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é)點(diǎn)處理鏈
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 實(shí)例化
- Entry實(shí)例化
- 保存資源處理鏈讥蟆,資源處理上下文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);
}
- 保存對(duì)應(yīng)的context名稱
- 保存資源請(qǐng)求時(shí)間
public Entry(ResourceWrapper resourceWrapper) {
this.resourceWrapper = resourceWrapper;
this.createTime = TimeUtil.currentTimeMillis();
}
3.2.2 資源請(qǐng)求失敗處理
- 1 失敗的entry非context當(dāng)前entry修然,則按entry父子關(guān)系依次向上調(diào)用所有entry的失敗處理函數(shù)exit()
- 2 失敗entry是context的當(dāng)前entry质况,
調(diào)用資源處理鏈的exit函數(shù)
更新context的curEntry為請(qǐng)求失敗Entry的父節(jié)點(diǎn)Entry
刪除Entry的父子關(guān)系
如Entry無(wú)父節(jié)點(diǎn),則若是默認(rèn)context則需要自動(dòng)清理中贝,手動(dòng)配置的context則由用戶手動(dòng)退出潭陪。
清理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é)點(diǎn)關(guān)系圖
image.png