Soul 網關源碼閱讀(六)Sofa請求處理概覽

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"Soul 網關源碼閱讀(六)Sofa請求處理概覽","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule","attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"link","attrs":{"href":"https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB6-sofa%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%A6%82%E8%A7%88.md#%E7%AE%80%E4%BB%8B","title":null}},{"type":"text","text":"簡介","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    今天來探索一下Sofa請求處理流程,看看和前面的HTTP、Dubbo有什麼異同","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"link","attrs":{"href":"https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB6-sofa%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%A6%82%E8%A7%88.md#sofa%E7%A4%BA%E4%BE%8B%E8%BF%90%E8%A1%8C","title":null}},{"type":"text","text":"Sofa示例運行","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic","attrs":{}}],"text":"PS:如果請求加上參數運行不成功,請更新最新版本,此問題在新版本中已經修復:","attrs":{}},{"type":"link","attrs":{"href":"https://blog.csdn.net/baidu_27627251/article/details/112726694","title":null},"content":[{"type":"text","text":"https://blog.csdn.net/baidu_27627251/article/details/112726694","attrs":{}}],"marks":[{"type":"italic"}]},{"type":"text","text":" ","attrs":{}},{"type":"link","attrs":{"href":"https://github.com/dromara/soul/pull/992","title":null},"content":[{"type":"text","text":"Add sofa param resolve service","attrs":{}}],"marks":[{"type":"italic"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    首先運行下官方的Sofa示例,首先啓動下mysql和zookeeper,這裏使用docker啓動:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"docker run -dit --name zk -p 2181:2181 zookeepe\ndocker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:latest","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    然後運行Soul-admin,Soul-Bootst,在管理圖界面起用sofa插件","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    運行官方示例:soul-examples --> soul-examples-sofa","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    這裏有個坑,需要注意,啓動後,bootstrap打印日誌中沒有sofa插件,請求一直失敗","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"o.d.s.w.configuration.SoulConfiguration : load plugin:[global] [org.dromara.soul.plugin.global.GlobalPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[sign] [org.dromara.soul.plugin.sign.SignPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[waf] [org.dromara.soul.plugin.waf.WafPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[rate_limiter] [org.dromara.soul.plugin.ratelimiter.RateLimiterPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[hystrix] [org.dromara.soul.plugin.hystrix.HystrixPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[resilience4j] [org.dromara.soul.plugin.resilience4j.Resilience4JPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[divide] [org.dromara.soul.plugin.divide.DividePlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[webClient] [org.dromara.soul.plugin.httpclient.WebClientPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[divide] [org.dromara.soul.plugin.divide.websocket.WebSocketPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[alibaba-dubbo-body-param] [org.dromara.soul.plugin.alibaba.dubbo.param.BodyParamPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[dubbo] [org.dromara.soul.plugin.alibaba.dubbo.AlibabaDubboPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[monitor] [org.dromara.soul.plugin.monitor.MonitorPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[response] [org.dromara.soul.plugin.httpclient.response.WebClientResponsePlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[response] [org.dromara.soul.plugin.alibaba.dubbo.response.DubboResponsePlugin]\n```xml\n\n    查看初始的plugins也是沒有sofa\n\n```java\n public SoulWebHandler soulWebHandler(final ObjectProvider> plugins) {\n List pluginList = plugins.getIfAvailable(Collections::emptyList);\n final List soulPlugins = pluginList.stream()\n .sorted(Comparator.comparingInt(SoulPlugin::getOrder)).collect(Collectors.toList());\n soulPlugins.forEach(soulPlugin -> log.info(\"load plugin:[{}] [{}]\", soulPlugin.named(), soulPlugin.getClass().getName()));\n return new SoulWebHandler(soulPlugins);\n }","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    經過探索和老哥的討論,發現是每天起用sofa的相關依賴","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    我們在Bootstrap的pom.xml文件中添加下面的依賴,然後重啓","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":" \n \n com.alipay.sofa\n sofa-rpc-all\n 5.7.6\n \n \n org.apache.curator\n curator-client\n 4.0.1\n \n \n org.apache.curator\n curator-framework\n 4.0.1\n \n \n org.apache.curator\n curator-recipes\n 4.0.1\n \n \n org.dromara\n soul-spring-boot-starter-plugin-sofa\n ${project.version}\n \n ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    然後查看日誌打印,出現了sofa相關的插件","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"o.d.s.w.configuration.SoulConfiguration : load plugin:[global] [org.dromara.soul.plugin.global.GlobalPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[sign] [org.dromara.soul.plugin.sign.SignPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[waf] [org.dromara.soul.plugin.waf.WafPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[rate_limiter] [org.dromara.soul.plugin.ratelimiter.RateLimiterPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[hystrix] [org.dromara.soul.plugin.hystrix.HystrixPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[resilience4j] [org.dromara.soul.plugin.resilience4j.Resilience4JPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[divide] [org.dromara.soul.plugin.divide.DividePlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[webClient] [org.dromara.soul.plugin.httpclient.WebClientPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[divide] [org.dromara.soul.plugin.divide.websocket.WebSocketPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[sofa-body-param] [org.dromara.soul.plugin.sofa.param.BodyParamPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[dubbo] [org.dromara.soul.plugin.alibaba.dubbo.AlibabaDubboPlugin]\n// 新出現的sofa相關的\no.d.s.w.configuration.SoulConfiguration : load plugin:[sofa] [org.dromara.soul.plugin.sofa.SofaPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[monitor] [org.dromara.soul.plugin.monitor.MonitorPlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[response] [org.dromara.soul.plugin.alibaba.dubbo.response.DubboResponsePlugin]\no.d.s.w.configuration.SoulConfiguration : load plugin:[response] [org.dromara.soul.plugin.httpclient.response.WebClientResponsePlugin]\n// 新出現的sofa相關的\no.d.s.w.configuration.SoulConfiguration : load plugin:[response] [org.dromara.soul.plugin.sofa.response.SofaResponsePlugin]","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    日誌中還打印了成功加載sofa相關的metadata","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"o.d.s.p.s.cache.ApplicationConfigCache : init sofa reference success there meteData is :MetaData\no.d.s.p.s.cache.ApplicationConfigCache : init sofa reference success there meteData is :MetaData\no.d.s.p.s.cache.ApplicationConfigCache : init sofa reference success there meteData is :MetaData","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    訪問鏈接: ","attrs":{}},{"type":"link","attrs":{"href":"http://localhost:9195/sofa/findAll","title":null},"content":[{"type":"text","text":"http://localhost:9195/sofa/findAll","attrs":{}}]},{"type":"text","text":" ,成功返回如下請求","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"{\n \"code\": 200,\n \"message\": \"Access to success!\",\n \"data\": {\n \"name\": \"hello world Soul Sofa , findAll\",\n \"id\": \"998932133\"\n }\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"link","attrs":{"href":"https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB6-sofa%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%A6%82%E8%A7%88.md#%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90","title":null}},{"type":"text","text":"源碼解析","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic","attrs":{}}],"text":"PS:Debug時間過程,會導致超時,這是正常的","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    首先找到我們非常熟悉的切入點函數: SoulWebHandler ,在下面的方法中打上斷點,然後逐步進入每個plugin觀察其行爲","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":" public Mono execute(final ServerWebExchange exchange) {\n return Mono.defer(() -> {\n if (this.index < plugins.size()) {\n SoulPlugin plugin = plugins.get(this.index++);\n Boolean skip = plugin.skip(exchange);\n if (skip) {\n return this.execute(exchange);\n }\n return plugin.execute(exchange, this);\n }\n return Mono.empty();\n });\n }","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"link","attrs":{"href":"https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB6-sofa%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%A6%82%E8%A7%88.md#globalplugin","title":null}},{"type":"text","text":"GlobalPlugin","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    進入其中,執行處理邏輯,通過上篇的分析,我們知道大致作用是將請求類型放入exchange中","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"link","attrs":{"href":"https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB6-sofa%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%A6%82%E8%A7%88.md#signpluginwafpluginratelimiterpluginhystrixpluginresilience4jplugin","title":null}},{"type":"text","text":"SignPlugin/WafPlugin/RateLimiterPlugin/HystrixPlugin/Resilience4JPlugin","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    進入其中,但plugin沒有起用,不執行邏輯","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"link","attrs":{"href":"https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB6-sofa%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%A6%82%E8%A7%88.md#dividepluginwebclientpluginwebsocketplugin","title":null}},{"type":"text","text":"DividePlugin/WebClientPlugin/WebSocketPlugin","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    通過類型判斷,跳過,不執行","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"link","attrs":{"href":"https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB6-sofa%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%A6%82%E8%A7%88.md#bodyparamplugin","title":null}},{"type":"text","text":"BodyParamPlugin","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    這個plugin在dubbo的時候也是要執行,我們來看看它幹了寫啥事。從下面邏輯中大概能看出先判斷是否符合執行條件,然後將請求地址替換成真實的後端地址","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":" public Mono execute(final ServerWebExchange exchange, final SoulPluginChain chain) {\n final ServerHttpRequest request = exchange.getRequest();\n final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);\n // 判斷類型是不是sofa\n if (Objects.nonNull(soulContext) && RpcTypeEnum.SOFA.getName().equals(soulContext.getRpcType())) {\n MediaType mediaType = request.getHeaders().getContentType();\n ServerRequest serverRequest = ServerRequest.create(exchange, messageReaders);\n if (MediaType.APPLICATION_JSON.isCompatibleWith(mediaType)) {\n return body(exchange, serverRequest, chain);\n }\n if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(mediaType)) {\n return formData(exchange, serverRequest, chain);\n }\n // 進行路徑替換,換成後端服務器的\n return query(exchange, serverRequest, chain);\n }\n return chain.execute(exchange);\n }\n\n private Mono query(final ServerWebExchange exchange, final ServerRequest serverRequest, final SoulPluginChain chain) {\n exchange.getAttributes().put(Constants.SOFA_PARAMS,\n HttpParamConverter.ofString(() -> serverRequest.uri().getQuery()));\n return chain.execute(exchange);\n }","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    這裏有個非常有趣的現象,我們第四篇分析中,dubbo也走了一模一樣的類,在上面函數邏輯中,我們看出它並不能兼容dubbo,那dubbo是如何走這個類的呢?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    通過調試我們發現,當同時啓動dubbo和sofa的時候,會生成兩個BodyParamPlugin,名稱是一模一樣的,但裏面的判斷類型換了,很神奇,猜測這個類是動態生成之類的手段,這裏先不探索了,可以後面研究研究","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"link","attrs":{"href":"https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB6-sofa%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%A6%82%E8%A7%88.md#alibabadubboplugin","title":null}},{"type":"text","text":"AlibabaDubboPlugin","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    通過類型判斷,跳過","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"link","attrs":{"href":"https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB6-sofa%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%A6%82%E8%A7%88.md#sofaplugin","title":null}},{"type":"text","text":"SofaPlugin","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    這個從名字就看出來是核心類,我們看看它具體幹了啥。通過下面註釋的地方,可以看出和dubbo請求的非常的相像。進行路由匹配,成功後rpc調用,獲得結果後放入exchange中","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":" # AbstractSoulPlugin\n public Mono execute(final ServerWebExchange exchange, final SoulPluginChain chain) {\n String pluginName = named();\n final PluginData pluginData = BaseDataCache.getInstance().obtainPluginData(pluginName);\n if (pluginData != null && pluginData.getEnabled()) {\n final Collection selectors = BaseDataCache.getInstance().obtainSelectorData(pluginName);\n if (CollectionUtils.isEmpty(selectors)) {\n return handleSelectorIsNull(pluginName, exchange, chain);\n }\n final SelectorData selectorData = matchSelector(exchange, selectors);\n if (Objects.isNull(selectorData)) {\n return handleSelectorIsNull(pluginName, exchange, chain);\n }\n selectorLog(selectorData, pluginName);\n final List rules = BaseDataCache.getInstance().obtainRuleData(selectorData.getId());\n if (CollectionUtils.isEmpty(rules)) {\n return handleRuleIsNull(pluginName, exchange, chain);\n }\n // 判斷是否有路由規則能匹配上\n RuleData rule;\n if (selectorData.getType() == SelectorTypeEnum.FULL_FLOW.getCode()) {\n //get last\n rule = rules.get(rules.size() - 1);\n } else {\n rule = matchRule(exchange, rules);\n }\n if (Objects.isNull(rule)) {\n return handleRuleIsNull(pluginName, exchange, chain);\n }\n ruleLog(rule, pluginName);\n // 匹配上後執行處理邏輯\n return doExecute(exchange, chain, selectorData, rule);\n }\n return chain.execute(exchange);\n }\n\n # SofaPlugin\n protected Mono doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {\n String body = exchange.getAttribute(Constants.SOFA_PARAMS);\n SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);\n assert soulContext != null;\n MetaData metaData = exchange.getAttribute(Constants.META_DATA);\n if (!checkMetaData(metaData)) {\n assert metaData != null;\n log.error(\" path is :{}, meta data have error.... {}\", soulContext.getPath(), metaData.toString());\n exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);\n Object error = SoulResultWrap.error(SoulResultEnum.META_DATA_ERROR.getCode(), SoulResultEnum.META_DATA_ERROR.getMsg(), null);\n return WebFluxResultUtils.result(exchange, error);\n }\n if (StringUtils.isNoneBlank(metaData.getParameterTypes()) && StringUtils.isBlank(body)) {\n exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);\n Object error = SoulResultWrap.error(SoulResultEnum.SOFA_HAVE_BODY_PARAM.getCode(), SoulResultEnum.SOFA_HAVE_BODY_PARAM.getMsg(), null);\n return WebFluxResultUtils.result(exchange, error);\n }\n // 這裏得到結果,跟下去\n final Mono result = sofaProxyService.genericInvoker(body, metaData, exchange);\n return result.then(chain.execute(exchange));\n }\n\n # SofaProxyService\n public Mono genericInvoker(final String body, final MetaData metaData, final ServerWebExchange exchange) throws SoulException {\n // 根據請求路徑,獲得rpc中的consumer \n ConsumerConfig reference = ApplicationConfigCache.getInstance().get(metaData.getPath());\n if (Objects.isNull(reference) || StringUtils.isEmpty(reference.getInterfaceId())) {\n ApplicationConfigCache.getInstance().invalidate(metaData.getServiceName());\n reference = ApplicationConfigCache.getInstance().initRef(metaData);\n }\n GenericService genericService = reference.refer();\n Pair pair;\n if (null == body || \"\".equals(body) || \"{}\".equals(body) || \"null\".equals(body)) {\n pair = new ImmutablePair<>(new String[]{}, new Object[]{});\n } else {\n pair = sofaParamResolveService.buildParameter(body, metaData.getParameterTypes());\n }\n CompletableFuture future = new CompletableFuture<>();\n RpcInvokeContext.getContext().setResponseCallback(new SofaResponseCallback() {\n @Override\n public void onAppResponse(final Object o, final String s, final RequestBase requestBase) {\n future.complete(o);\n }\n\n @Override\n public void onAppException(final Throwable throwable, final String s, final RequestBase requestBase) {\n future.completeExceptionally(throwable);\n }\n\n @Override\n public void onSofaException(final SofaRpcException e, final String s, final RequestBase requestBase) {\n future.completeExceptionally(e);\n }\n });\n // 通過函數名,能猜到是rpc調用,然後得到結果,並將結果放入exchange中\n genericService.$invoke(metaData.getMethodName(), pair.getLeft(), pair.getRight());\n return Mono.fromFuture(future.thenApply(ret -> {\n if (Objects.isNull(ret)) {\n ret = Constants.SOFA_RPC_RESULT_EMPTY;\n }\n exchange.getAttributes().put(Constants.SOFA_RPC_RESULT, ret);\n exchange.getAttributes().put(Constants.CLIENT_RESPONSE_RESULT_TYPE, ResultEnum.SUCCESS.getName());\n return ret;\n })).onErrorMap(SoulException::new);\n }","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"link","attrs":{"href":"https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB6-sofa%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%A6%82%E8%A7%88.md#monitorplugin","title":null}},{"type":"text","text":"MonitorPlugin","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    不跳過,但插件沒有開啓","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"link","attrs":{"href":"https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB6-sofa%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%A6%82%E8%A7%88.md#dubboresponsepluginwebclientresponseplugin","title":null}},{"type":"text","text":"DubboResponsePlugin/WebClientResponsePlugin","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    通過類型判斷,跳過執行","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"link","attrs":{"href":"https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB6-sofa%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%A6%82%E8%A7%88.md#sofaresponseplugin","title":null}},{"type":"text","text":"SofaResponsePlugin","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    通過上幾篇分析和名字能猜出來是將響應返回給客戶端的,通過下面代碼的邏輯也可以看出","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":" public Mono execute(final ServerWebExchange exchange, final SoulPluginChain chain) {\n return chain.execute(exchange).then(Mono.defer(() -> {\n // 從exchange中獲取結果\n final Object result = exchange.getAttribute(Constants.SOFA_RPC_RESULT);\n if (Objects.isNull(result)) {\n Object error = SoulResultWrap.error(SoulResultEnum.SERVICE_RESULT_ERROR.getCode(), SoulResultEnum.SERVICE_RESULT_ERROR.getMsg(), null);\n return WebFluxResultUtils.result(exchange, error);\n }\n Object success = SoulResultWrap.success(SoulResultEnum.SUCCESS.getCode(), SoulResultEnum.SUCCESS.getMsg(), JsonUtils.removeClass(result));\n // 熟悉的返回響應的函數\n return WebFluxResultUtils.result(exchange, success);\n }));\n }","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"link","attrs":{"href":"https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/soul%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB6-sofa%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%A6%82%E8%A7%88.md#%E6%80%BB%E7%BB%93","title":null}},{"type":"text","text":"總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    上面的plugin流程大致如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"GlobalPlugin : 將請求類型置入","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SignPlugin : 跳過不執行邏輯","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"WafPlugin : 跳過不執行邏輯","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"RateLimiterPlugin : 跳過不執行邏輯","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"HystrixPlugin : 跳過不執行邏輯","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Resilience4JPlugin : 跳過不執行邏輯","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"DividePlugin : 跳過不執行邏輯","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"WebClientPlugin : 跳過不執行邏輯","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"WebSocketPlugin : 跳過不執行邏輯","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"BodyParamPlugin : 執行RPC的請求路徑替換,替換成真實的服務器後端路徑,作用類似於dividePlugin;不同rpc有相關的這個插件名,也就是會有多個BodyParamPlugin","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"AlibabaDubboPlugin : 跳過不執行邏輯","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SofaPlugin : 發送請求到後臺服務器,拿到結果,寫入exchange","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MonitorPlugin : 跳過不執行邏輯","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"DubboResponsePlugin : 跳過不執行邏輯","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"WebClientResponsePlugin : 跳過不執行邏輯","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SofaResponsePlugin : 從exchange中拿到響應,發送給客戶端","attrs":{}}]}],"attrs":{}}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    經過這幾篇的分析,我們進一步優化我們對Soul網關的請求流程,大致如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/picture/Soulprocessfirst.png","title":null}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/56/56d5702f608fbe436dac6e5cf32012a2.png","alt":"在這裏插入圖片描述","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://github.com/lw1243925457/SE-Notes/blob/master/profession/program/%E5%BC%80%E6%BA%90/soul/picture/Soulprocessfirst.png","title":null}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"    更新了我們對處理流程中一些類的認知:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過上篇分析,得到GlobalPlugin的具體作用,是置入請求類型","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"BodyParamPlugin 作用類似於 dividePlugin,能進行路由匹配,匹配後將路徑修改真實的後端服務器路徑;並且能動態的生成同名的但針對不同rpc實現的plugin","attrs":{}}]}],"attrs":{}}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章