Spring Webflux 源码阅读之 reactive包

Spring-webflux 源码阅读

org.springframework.web.reactive (包名)

介绍

Spring-webflux模块的顶级软件包包含DispatcherHandler,它是WebFlux服务器端点处理的主要入口点,包括用于将请求映射到处理程序的关键协议,调用它们并处理结果。

该模块为反应式服务器端点提供两种编程模型。一个基于注释@Controller ,另一个基于功能路由和处理。该模块还包含一个功能性,反应性WebClient以及客户端和服务器,反应式WebSocket支持。

几张diagram:

dispachServlet.jpg

(Interface)

HandlerAdapter

DispatcherHandler与调用处理程序的细节相分离的协议,使得它可以支持任何处理程序类型。

supports

boolean supports(Object handler);

这个HandlerAdapter是否支持给定的handler

Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler);

用给定的handler 来处理请求

鼓励实现处理因调用处理程序而导致的异常,并且必要时返回表示错误响应的替代结果。

此外,由于异步HandlerResult可能会在结果处理过程中产生错误,因此还鼓励在HandlerResult中设置异常处理程序,以便稍后在结果处理后也可以应用异常处理程序。

exchange 当前的服务器交换

返回值:reactor.core.publisher.Mono<HandlerResult> , 这将返回Mono,一个单独的HandlerResult或没有,
如果请求已完全处理,不需要进一步处理。

All Known Implementing Classes 所有已知实施类:

HandlerFunctionAdapter, RequestMappingHandlerAdapter, SimpleHandlerAdapter, WebSocketHandlerAdapter

HandlerMapping

All Known Implementing Classes 所有已知实施类:

AbstractHandlerMapping,AbstractHandlerMethodMapping, AbstractUrlHandlerMapping,RequestMappingHandlerMapping, RequestMappingInfoHandlerMapping, RouterFunctionMapping, SimpleUrlHandlerMapping

由定义请求和处理程序对象之间的映射的对象实现的接口。

BEST_MATCHING_HANDLER_ATTRIBUTE
包含最佳匹配模式的映射处理程序的属性名称。

BEST_MATCHING_PATTERN_ATTRIBUTE
在处理程序映射中包含最佳匹配模式的属性的名称。

MATRIX_VARIABLES_ATTRIBUTE
包含具有URI变量名称的映射的属性的名称以及每个URI变量的相应MultiValueMap。

PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE
包含处理程序映射中的路径的属性的名称,在匹配的情况下,例如“/ static / **”或完全相关的URI。

PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE

包含适用于映射处理程序的可生产的MediaType集合的属性的名称。

URI_TEMPLATE_VARIABLES_ATTRIBUTE
包含URI模板的属性的名称将变量名称映射到值。

Mono<Object> getHandler(ServerWebExchange exchange);

返回此请求的处理程序(handler)。

返回Mono<Object>:一个发出一个值的Mono,如果请求无法解析到一个处理程序,那么它就没有

HandlerResultHandler

All Known Implementing Classes 所有已知实施类:

ResponseBodyResultHandler, ResponseEntityResultHandler, ServerResponseResultHandler, ViewResolutionResultHandler

处理HandlerResult,通常由HandlerAdapter返回。

supports

boolean supports(HandlerResult result);;

该对象是否可以使用给定的HandlerResult

Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result);

处理给定的结果修改响应标头and/or将数据写入响应。

result - 处理的结果

Mono <Void>来指示请求处理完成。

用给定的handler 来处理请求

鼓励实现处理因调用处理程序而导致的异常,并且必要时返回表示错误响应的替代结果。

Class

BindingContext

帮助将请求数据绑定到对象上并提供对具有控制器特定属性的共享模型的访问的上下文。

提供为特定目标创建WebExchangeDataBinder的方法,命令对象将数据绑定和验证应用,或者没有目标对象用于从请求值进行简单类型转换。用于请求的默认模型的容器。

Constructors 构造器

BindingContext()

创建一个新的BindingContext。

BindingContext(WebBindingInitializer initializer)

使用给定的初始化程序创建一个新的BindingContext。
初始化程序 - 要应用的绑定初始化程序(可能为null)

Method

public Model getModel()

返回一个对象

public WebExchangeDataBinder createDataBinder(ServerWebExchange exchange,
@Nullable
java.lang.Object target,
java.lang.String name)

                                          创建一个WebExchangeDataBinder,以在目标命令对象上应用数据绑定和验证。

protected WebExchangeDataBinder initDataBinder(WebExchangeDataBinder binder,
ServerWebExchange exchange)

                                           始化给定交换的数据绑定实例。

public WebExchangeDataBinder createDataBinder(ServerWebExchange exchange,
java.lang.String name)

                                          创建一个没有目标对象的WebExchangeDataBinder,将请求值的类型转换为简单类型。

HandlerResult

表示调用处理程序或处理程序方法的结果。

public HandlerResult(java.lang.Object handler,
@Nullable
java.lang.Object returnValue,
MethodParameter returnType)

                 创建一个新的HandlerResult
  • handler - the handler that handled the request
  • returnValue - the return value from the handler possibly null
  • returnType - the return value type

public java.lang.Object getHandler()

返回处理请求的处理程序。

@Nullable
public java.lang.Object getReturnValue()

返回从处理程序返回的值(如果有)。

public ResolvableType getReturnType()

返回从处理程序返回的值的类型 - 例如在控制器方法的签名上声明的返回类型。另请参见getReturnTypeSource()来获取返回类型的底层MethodParameter。

public BindingContext getBindingContext()

返回用于请求处理的BindingContext。

DispatcherHandler(程序入口 , 核心)

All Implemented Interfaces 所有实现的接口:

Aware, ApplicationContextAware, WebHandler

HTTP请求处理程序/控制器的中央调度程序

分发已经注册的处理程序来处理请求,提供方便的映射方式

DispatcherHandler从Spring配置中发现需要的代理组件。它在应用程序上下文中检测到以下内容:

  • HandlerMapping -- map requests to handler objects(将请求映射到处理对象)
  • HandlerAdapter -- for using any handler interface(使用相应的处理程序接口)
  • HandlerResultHandler -- process handler return values(流程处理程序返回值)

DispatcherHandler也设计为一个Spring bean本身,并实现了ApplicationContextAware以访问其运行的上下文。如果DispatcherHandler被声明为bean名称“webHandler”,那么它将被WebHttpHandlerBuilder.applicationContextorg.springframework.context.ApplicationContext)发现,与WebFilterWebExceptionHandler等一起创建一个处理链。

@EnableWebFlux配置中包含DispatcherHandler beande声明。

构造器

DispatcherHandler()

创建一个新的DispatcherHandler,它需要通过setApplicationContext(org.springframework.context.ApplicationContext)配置一个ApplicationContext

DispatcherHandler(ApplicationContext applicationContext)

为给定的ApplicationContext创建一个新的DispatcherHandler。

方法摘要

@Nullable
public final java.util.List<HandlerMapping> getHandlerMappings()

返回在注入的上下文中类型检测到的所有HandlerMapping bean,并排序。

注意:如果在setApplicationContext(ApplicationContext)之前调用,此方法可能返回null。返回的是具有配置的映射的不可变列表或空值

public void setApplicationContext(ApplicationContext applicationContext)

设置此对象运行的ApplicationContext。通常,此调用将用于初始化对象。

在普通bean属性的采集之后但是在初始化回调之前调用,例如InitializingBean.afterPropertiesSet()或自定义init方法。在ResourceLoaderAware.setResourceLoader(org.springframework.core.io.ResourceLoader),ApplicationEventPublisherAware.setApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher)和MessageSourceAware(如果适用)后调用。

覆盖了接口ApplicationContextAware中的setApplicationContext

applicationContext - 该对象要使用的ApplicationContext对象

protected void initStrategies(ApplicationContext context)

** 初始化环境 **

public reactor.core.publisher.Mono<java.lang.Void> handle(ServerWebExchange exchange)

处理Web服务器交换。

在接口WebHandler中定义了handle方法,在这里来实现

Mono <Void>来指示请求处理完成

下面让我们来看看这个调度器是怎么实现的。


    @Nullable
    private List<HandlerMapping> handlerMappings;

    @Nullable
    private List<HandlerAdapter> handlerAdapters;

    @Nullable
    private List<HandlerResultHandler> resultHandlers;
    

首先定义了可以为空的三个List列表,分别是handlerMappingshandlerAdaptersresultHandlers


public DispatcherHandler(ApplicationContext applicationContext) {
        initStrategies(applicationContext);
    }
    
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
        initStrategies(applicationContext);
    }


protected void initStrategies(ApplicationContext context) {
        Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
                context, HandlerMapping.class, true, false);

        ArrayList<HandlerMapping> mappings = new ArrayList<>(mappingBeans.values());
        AnnotationAwareOrderComparator.sort(mappings);
        this.handlerMappings = Collections.unmodifiableList(mappings);

        Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
                context, HandlerAdapter.class, true, false);

        this.handlerAdapters = new ArrayList<>(adapterBeans.values());
        AnnotationAwareOrderComparator.sort(this.handlerAdapters);

        Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
                context, HandlerResultHandler.class, true, false);

        this.resultHandlers = new ArrayList<>(beans.values());
        AnnotationAwareOrderComparator.sort(this.resultHandlers);
    }

在实例化DispatcherHandler之后,开始调用initStrategies(applicationContext),这个方法,beansOfTypeIncludingAncestors这个方法来通过解析和反射等方法来收集context中所有的bean(可以通过注解或者xml配置Spring Bean,Springboot都是注解一般),来创建ioc容器, 上面代码中的mappingBeans adapterBeans beans 都是如此,创建好之后来让之前最初创建的三个List变量集合引用,并且对他们进行排序。

到现在为止,初始化已经完成了,接下来我们来看这个入口类的核心方法:

    @Override
    public Mono<Void> handle(ServerWebExchange exchange) {
        if (logger.isDebugEnabled()) {
            ServerHttpRequest request = exchange.getRequest();
            logger.debug("Processing " + request.getMethodValue() + " request for [" + request.getURI() + "]");
        }
        if (this.handlerMappings == null) {
            return Mono.error(HANDLER_NOT_FOUND_EXCEPTION);
        }
        return Flux.fromIterable(this.handlerMappings)
                .concatMap(mapping -> mapping.getHandler(exchange))
                .next()
                .switchIfEmpty(Mono.error(HANDLER_NOT_FOUND_EXCEPTION))
                .flatMap(handler -> invokeHandler(exchange, handler))
                .flatMap(result -> handleResult(exchange, result));
    }
    
    
package org.springframework.web.server;
 
public interface WebHandler {

    /**
     * Handle the web server exchange.
     * @param exchange the current server exchange
     * @return {@code Mono<Void>} to indicate when request handling is complete
     */
    Mono<Void> handle(ServerWebExchange exchange);

}

    

其实这个handle方法是实现了package org.springframework.web.server中的WebHandler中的接口,这里可以看到先拿到了请求中的request,然后接下来就是Flux开始遍历我们的handlerMappings,从ServerWebExchange中获得相应的Handle,会调用invokeHandler(exchange, handler)来匹配真正要使用的那个handlerAdapter,来执行handle方法处理请求逻辑,return handlerAdapter.handle(exchange, handler);,这个过程中,别的类已经处理完了,并且返回了结果(还没看到哪些类),返回一个Mono<HandlerResult>,代码如下:


    private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
        if (this.handlerAdapters != null) {
            for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
                if (handlerAdapter.supports(handler)) {
                    return handlerAdapter.handle(exchange, handler);
                }
            }
        }
        return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
    }

最后就是调用handleResult(exchange, result)这个方法,代码如下:


    private HandlerResultHandler getResultHandler(HandlerResult handlerResult) {
        if (this.resultHandlers != null) {
            for (HandlerResultHandler resultHandler : this.resultHandlers) {
                if (resultHandler.supports(handlerResult)) {
                    return resultHandler;
                }
            }
        }
        throw new IllegalStateException("No HandlerResultHandler for " + handlerResult.getReturnValue());
    }
    

同理,也是要遍历来匹配真正的resultHandler,然后获得这个,调用handlerResult.getReturnValue());来返回结果。今天先看到这,还有点懵。不过可以感受到这个异步非阻塞IO框架的强大之处。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • Spring Webflux --handler 提供包括抽象基类在内的HandlerMapping实现。 先扔一...
    一颗懒能阅读 3,041评论 0 3
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,598评论 18 399
  • Spring-webflux --config 源码阅读 包名 org.springframework.web.r...
    一颗懒能阅读 4,644评论 1 3
  • 老师, 你讲了那么多历史, 我们还不都一个样,要根据环境而生活么? 那些道理,打来打去,从古时候打到当今,喻过来喻...
    写字人已失踪阅读 267评论 0 1