概述
1. 综述
神禹网关是通过责任链方式组织的,那它的调用链是什么样子的,调用链是怎样组装在一起的,本篇文章就来探索这个问题。
2. 结论先行
神禹网关调用链如下所示
HttpWebHandlerAdapter -> ExceptionHandlingWebHandler -> FilteringWebHandler -> DefaultWebFilterChain ->ShenyuWebHandler
3. 阅读前准备知识
3.1 shenyu网关注册了自己的Handler
Shenyu网关是基于WebFlux的,在ShenyuConfiguration.java类中,神禹网关注册了自己的WebHandler,ShenyuWebHandler,这里是webflux设计的精巧之处,除了神禹,spring-cloud-gateway也是基于此进行扩展的,spring-cloud-gateway中注册的handler叫DispatcherHandler,此处等我分享spring-cloud-gateway原理的时候在详说,继续看神禹,神禹注册webHandler的代码如下所示。
@Bean("webHandler")
public ShenyuWebHandler shenyuWebHandler(final ObjectProvider<List<ShenyuPlugin>> plugins, final ShenyuConfig config) {
List<ShenyuPlugin> pluginList = plugins.getIfAvailable(Collections::emptyList);
List<ShenyuPlugin> shenyuPlugins = pluginList.stream()
.sorted(Comparator.comparingInt(ShenyuPlugin::getOrder)).collect(Collectors.toList());
shenyuPlugins.forEach(shenyuPlugin -> LOG.info("load plugin:[{}] [{}]", shenyuPlugin.named(), shenyuPlugin.getClass().getName()));
return new ShenyuWebHandler(shenyuPlugins, config);
}
4. HttpHandler的生成过程
4.1 HttpHandler Bean注册进spring
HttpHandlerAutoConfiguration中类,把HttpHandler注册成了一个bean,HttpHandler生成方式如代码第一行所示,applicatinContext的生成方式参见扩展问题。
@Bean
public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider) {
HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(this.applicationContext).build(); //HttpHandler生成方式
WebFluxProperties properties = propsProvider.getIfAvailable();
if (properties != null && StringUtils.hasText(properties.getBasePath())) {
Map<String, HttpHandler> handlersMap = Collections.singletonMap(properties.getBasePath(), httpHandler);
return new ContextPathCompositeHandler(handlersMap);
}
return httpHandler;
}
4.2 WebHttpHandlerBuilder.applicationContext(applicationContext)
applicationContext(applicationContext)代码如下所示,第一行代码,从context中获取WebHandler类的实例,也就是阅读前准备知识中神禹网关注册的ShenyuWebHandler。
之后它又做了三件事情
- 找到所有的webFilters;
- 找到所有的exceptionHandlers;
- 找到所有的HttpHandlerDecoratorFactory,调用httpHandlerDecorator方法。
public static WebHttpHandlerBuilder applicationContext(ApplicationContext context) {
//此行代码设置了WebHttpHandlerBuilder中的WebHandler为ShenyuWebHandler
WebHttpHandlerBuilder builder = new WebHttpHandlerBuilder(
context.getBean(WEB_HANDLER_BEAN_NAME, WebHandler.class), context);
List<WebFilter> webFilters = context
.getBeanProvider(WebFilter.class)
.orderedStream()
.collect(Collectors.toList());
builder.filters(filters -> filters.addAll(webFilters));
List<WebExceptionHandler> exceptionHandlers = context
.getBeanProvider(WebExceptionHandler.class)
.orderedStream()
.collect(Collectors.toList());
builder.exceptionHandlers(handlers -> handlers.addAll(exceptionHandlers));
context.getBeanProvider(HttpHandlerDecoratorFactory.class)
.orderedStream()
.forEach(builder::httpHandlerDecorator);
.....//此处省略一些代码
return builder;
}
4.3 WebHttpHandlerBuilder.build()方法
build() 方法最重要的是前三行代码,它生成了一个handler链。
第一行,使用FilteringWebHandler 包装this.webHandler 即 ShenyuWebHandler,生成如下结构的调用链
FilteringWebHandler -> ShenyuWebHandler;
第二行,使用ExceptionHandlingWebHandler 包装第一行的结果,生成如下结构的调用链
ExceptionHandlingWebHandler -> FilteringWebHadler -> ShenyuWebHandler
第三行,使用HttpWebHandlerAdapter 包装第二行的结果,生成如下结构的调用链
HttpWebHandlerAdapter -> ExceptionHandlingWebHandler -> FilteringWebHandler -> ShenyuWebHandler
public HttpHandler build() {
//第一行
WebHandler decorated = new FilteringWebHandler(this.webHandler, this.filters);
//第二行
decorated = new ExceptionHandlingWebHandler(decorated, this.exceptionHandlers);
//第三行
HttpWebHandlerAdapter adapted = new HttpWebHandlerAdapter(decorated);
if (this.sessionManager != null) {
adapted.setSessionManager(this.sessionManager);
}
if (this.codecConfigurer != null) {
adapted.setCodecConfigurer(this.codecConfigurer);
}
if (this.localeContextResolver != null) {
adapted.setLocaleContextResolver(this.localeContextResolver);
}
if (this.forwardedHeaderTransformer != null) {
adapted.setForwardedHeaderTransformer(this.forwardedHeaderTransformer);
}
if (this.applicationContext != null) {
adapted.setApplicationContext(this.applicationContext);
}
adapted.afterPropertiesSet();
return (this.httpHandlerDecorator != null ? this.httpHandlerDecorator.apply(adapted) : adapted);
}
4.4 FilteringWebHandler 内部包装DefaultWebFilterChain
FilteringWebHandler 类构造函数内部调用了 DefaultWebFilterChain,此时调用链为HttpWebHandlerAdapter -> ExceptionHandlingWebHandler -> FilteringWebHandler -> DefaultWebFilterChain ->ShenyuWebHandler
public FilteringWebHandler(WebHandler handler, List<WebFilter> filters) {
super(handler);
this.chain = new DefaultWebFilterChain(handler, filters);
}
4.5 DefaultWebFilterChain filter链的构造
DefaultWebFilterChain构造函数如下所示。
public DefaultWebFilterChain(WebHandler handler, List<WebFilter> filters) {
Assert.notNull(handler, "WebHandler is required");
this.allFilters = Collections.unmodifiableList(filters);
this.handler = handler;
DefaultWebFilterChain chain = initChain(filters, handler);
this.currentFilter = chain.currentFilter;
this.chain = chain.chain;
}
initChain(filters, handler)方法源码如下所示,通过循环所有的filter,构造成filter链循环调用会生成如下结构的filter chain
initChain的源代码如下所示
private static DefaultWebFilterChain initChain(List<WebFilter> filters, WebHandler handler) {
DefaultWebFilterChain chain = new DefaultWebFilterChain(filters, handler, null, null);
ListIterator<? extends WebFilter> iterator = filters.listIterator(filters.size());
while (iterator.hasPrevious()) {
chain = new DefaultWebFilterChain(filters, handler, iterator.previous(), chain);
}
return chain;
}
最终调用的构造函数如下
private DefaultWebFilterChain(List<WebFilter> allFilters, WebHandler handler,
@Nullable WebFilter currentFilter, @Nullable DefaultWebFilterChain chain) {
this.allFilters = allFilters;
this.currentFilter = currentFilter;
this.handler = handler;
this.chain = chain;
}
5. ShenyuWebHandler 的执行过程
5.1 ShenyuWebHandler的注册
如阅读前准备知识所述,ShenyuWebHandler 在 ShenyuConfiguration类中作为一个bean被注册进spring。方法参数上第一个入参是plugins,关于它是如何获取到的,参见扩展问题。
@Bean("webHandler")
public ShenyuWebHandler shenyuWebHandler(final ObjectProvider<List<ShenyuPlugin>> plugins, final ShenyuConfig config) {
List<ShenyuPlugin> pluginList = plugins.getIfAvailable(Collections::emptyList);
List<ShenyuPlugin> shenyuPlugins = pluginList.stream()
.sorted(Comparator.comparingInt(ShenyuPlugin::getOrder)).collect(Collectors.toList());
shenyuPlugins.forEach(shenyuPlugin -> LOG.info("load plugin:[{}] [{}]", shenyuPlugin.named(), shenyuPlugin.getClass().getName()));
return new ShenyuWebHandler(shenyuPlugins, config);
}
5.2 ShenyuWebHandler的Handle方法
由源码可知,ShenyuWebHandler的handle方法内部调用了DefaultShenyuPluginChain的execute方法。
@Override
public Mono<Void> handle(@NonNull final ServerWebExchange exchange) {
Mono<Void> execute = new DefaultShenyuPluginChain(plugins).execute(exchange);
if (scheduled) {
return execute.subscribeOn(scheduler);
}
return execute;
}
5.3 DefaultShenyuPluginChain.execute()方法逻辑
execute()方法迭代插件列表,并判断插件是否跳过,如果跳过就执行下一个插件,否则执行插件。神禹网关的调用链就是这样组织的。
@Override
public Mono<Void> execute(final ServerWebExchange exchange) {
return Mono.defer(() -> {
if (this.index < plugins.size()) {
ShenyuPlugin plugin = plugins.get(this.index++);
boolean skip = plugin.skip(exchange);
if (skip) {
return this.execute(exchange);
}
return plugin.execute(exchange, this);
}
return Mono.empty();
});
}
6 扩展问题
1. applicationContext是如何获取的
2. ShenyuConfiguration注册ShenyuWebHandler时,插件是如何获取到的
我会在下一章分享这两个问题。
最后
以上就是幸福花瓣为你收集整理的2. shenyu(神禹)网关调用链及组装过程1. 综述2. 结论先行 3. 阅读前准备知识4. HttpHandler的生成过程5. ShenyuWebHandler 的执行过程6 扩展问题的全部内容,希望文章能够帮你解决2. shenyu(神禹)网关调用链及组装过程1. 综述2. 结论先行 3. 阅读前准备知识4. HttpHandler的生成过程5. ShenyuWebHandler 的执行过程6 扩展问题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复