Hystrix插件圖
Hystrix類繼承圖
Bootstrap依賴模塊
bootstrap依賴模塊
網(wǎng)關插件啟動關鍵段
- 將網(wǎng)關插件列表注入到
webHandler
中
// @see org.dromara.soul.web.configuration.SoulConfiguration
@Bean("webHandler")
public SoulWebHandler soulWebHandler(final ObjectProvider<List<SoulPlugin>> plugins) {
// 將所有的網(wǎng)關插件躯肌,掛載到webHandler中蛉拙;且按照順序掛載
List<SoulPlugin> pluginList = plugins.getIfAvailable(Collections::emptyList);
final List<SoulPlugin> soulPlugins = pluginList.stream()
.sorted(Comparator.comparingInt(SoulPlugin::getOrder)).collect(Collectors.toList());
soulPlugins.forEach(soulPlugin -> log.info("load plugin:[{}] [{}]", soulPlugin.named(), soulPlugin.getClass().getName()));
return new SoulWebHandler(soulPlugins);
}
- 推測
webHandler
會將傳入的插件列表,生成插件鏈奴烙,在處理流程中依次處理
// @see org.dromara.soul.web.handler.SoulWebHandler
public Mono<Void> handle(@NonNull final ServerWebExchange exchange) {
MetricsTrackerFacade.getInstance().counterInc(MetricsLabelEnum.REQUEST_TOTAL.getName());
Optional<HistogramMetricsTrackerDelegate> startTimer = MetricsTrackerFacade.getInstance().histogramStartTimer(MetricsLabelEnum.REQUEST_LATENCY.getName());
// 直接將插件列表生成一個插件鏈DefaultSoulPluginChain叮叹,責任鏈的execute方法會遍歷所有插件列表,依次處理
// Mono的subscribeOn沒看明白乏苦???【就是講線程池綁定到Mono請求流程中】汇荐;難道是經(jīng)過Mono的請求洞就,都會提交給這個線程池執(zhí)行?Mono本身是有默認線程池吧掀淘,這里為什么要自用線程池旬蟋?應該是自行創(chuàng)建的Mono對象
return new DefaultSoulPluginChain(plugins).execute(exchange).subscribeOn(scheduler)
.doOnSuccess(t -> startTimer.ifPresent(time -> MetricsTrackerFacade.getInstance().histogramObserveDuration(time)));
}
- 我們看下網(wǎng)關插件鏈
DefaultSoulPluginChain.execute
的邏輯實現(xiàn)
// 1. 執(zhí)行方法,遍歷插件列表革娄,并調(diào)用插件的執(zhí)行邏輯
// 2. 返回Mono對象倾贰,能方便的使用Reactive的事件驅(qū)動編程的機制
public Mono<Void> execute(final ServerWebExchange exchange) {
return Mono.defer(() -> {
if (this.index < plugins.size()) {
SoulPlugin plugin = plugins.get(this.index++);
// 先判斷當前請求是否滿足插件處理的邏輯,如果不滿足拦惋,則跳過不處理匆浙;否則進行處理
Boolean skip = plugin.skip(exchange);
if (skip) {
// 跳過,直接執(zhí)行下一個插件
return this.execute(exchange);
}
// 執(zhí)行當前插件
return plugin.execute(exchange, this);
}
// 所有插件執(zhí)行完畢
return Mono.empty();
});
}
- 我們看下插件
HystrixPlugin
的執(zhí)行邏輯架忌,從上面的類圖可以得知是執(zhí)行的AbstractSoulPlugin
的execute
方法
public Mono<Void> execute(final ServerWebExchange exchange, final SoulPluginChain chain) {
String pluginName = named();
// 獲取插件的配置數(shù)據(jù)
final PluginData pluginData = BaseDataCache.getInstance().obtainPluginData(pluginName);
if (pluginData != null && pluginData.getEnabled()) {
// 獲取插件選擇器
final Collection<SelectorData> selectors = BaseDataCache.getInstance().obtainSelectorData(pluginName);
// 插件選擇器為空的處理
if (CollectionUtils.isEmpty(selectors)) {
return handleSelectorIsNull(pluginName, exchange, chain);
}
// 匹配選擇器
final SelectorData selectorData = matchSelector(exchange, selectors);
if (Objects.isNull(selectorData)) {
return handleSelectorIsNull(pluginName, exchange, chain);
}
selectorLog(selectorData, pluginName);
// 獲取選擇器的規(guī)則
final List<RuleData> rules = BaseDataCache.getInstance().obtainRuleData(selectorData.getId());
// 規(guī)則為空處理
if (CollectionUtils.isEmpty(rules)) {
return handleRuleIsNull(pluginName, exchange, chain);
}
// 匹配規(guī)則
RuleData rule;
if (selectorData.getType() == SelectorTypeEnum.FULL_FLOW.getCode()) {
//get last
rule = rules.get(rules.size() - 1);
} else {
rule = matchRule(exchange, rules);
}
// 未匹配到規(guī)則的處理
if (Objects.isNull(rule)) {
return handleRuleIsNull(pluginName, exchange, chain);
}
ruleLog(rule, pluginName);
// 將匹配到插件配置數(shù)據(jù)吞彤,傳遞給插件本身處理自身的業(yè)務邏輯
return doExecute(exchange, chain, selectorData, rule);
}
// 插件數(shù)據(jù)沒有我衬,則直接進入到下一個插件
return chain.execute(exchange);
}
- 再看
HystrixPlugin
的doExecute
方法
protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);
assert soulContext != null;
// 構(gòu)造hystrix處理
final HystrixHandle hystrixHandle = GsonUtils.getInstance().fromJson(rule.getHandle(), HystrixHandle.class);
if (StringUtils.isBlank(hystrixHandle.getGroupKey())) {
hystrixHandle.setGroupKey(Objects.requireNonNull(soulContext).getModule());
}
if (StringUtils.isBlank(hystrixHandle.getCommandKey())) {
hystrixHandle.setCommandKey(Objects.requireNonNull(soulContext).getMethod());
}
// 生成hystrix command
Command command = fetchCommand(hystrixHandle, exchange, chain);
// 這里就木有看懂了叹放,需額外學習RxJava
return Mono.create(s -> {
Subscription sub = command.fetchObservable().subscribe(s::success,
s::error, s::success);
s.onCancel(sub::unsubscribe);
if (command.isCircuitBreakerOpen()) {
log.error("hystrix execute have circuitBreaker is Open! groupKey:{},commandKey:{}", hystrixHandle.getGroupKey(), hystrixHandle.getCommandKey());
}
}).doOnError(throwable -> {
log.error("hystrix execute exception:", throwable);
exchange.getAttributes().put(Constants.CLIENT_RESPONSE_RESULT_TYPE, ResultEnum.ERROR.getName());
chain.execute(exchange);
}).then();
}
TODO
- soul網(wǎng)關如何調(diào)用hystrix進行控制的?
- Hystrix原理學習
- RxJava學習