<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          feign的一個注解居然隱藏這么多知識!

          共 8907字,需瀏覽 18分鐘

           ·

          2021-09-28 21:49


          點擊上方“Java金融”,選擇“設為星標”

          后臺回復"888"獲取bat面試題集

          引言

          最近由于業(yè)務的需要,需要接入下阿里云的一個接口,打開文檔看了看這個接口看下來還是比簡單的目測個把小時就可以搞定,但是接入的過程還是比較坎坷的。首先我看了看他給的示例,首先把阿里云文檔推薦的demo下載下來,把它的例子跑起來,替換下幾個必要的參數(shù)比如秘鑰啥的。這些秘鑰一般公司都會有專職的人員與阿里云去對接,你只要負責管他要就行了。不過也不排除也有得公司需要自己去對接阿里云。說到這里就想吐槽下,對接阿里云的時候技術支持群居然是釘釘,所以需要他們的支持就必須要下載個釘釘, 電腦上莫名的有需要多裝一個軟件。扯遠了我們還是回到正題,把它demo下載下來,然后把對應的秘鑰等參數(shù)替換下,然后運行下demo看看是否能夠正常返回結果,做這一步主要是為了保證產(chǎn)品給過來的秘鑰等參數(shù)是否正確。如果能夠掉通接口,那就說明參數(shù)沒啥問題的接著我們就可以著手來寫業(yè)務代碼了。接入阿里云二要素認證https://market.aliyun.com/products/57000002/cmapi029454.html?spm=5176.10695662.1194487.1.60066c190NsSkZ#sku=yuncode2345400003 把官網(wǎng)的demo下載下來跑起來看看,官網(wǎng)給出的例子還是比較簡單粗暴的,就是封裝了一個Apachehttplcient工具類一大坨的代碼,個人還是習慣性的使用feign來進行調(diào)用,因為feign的代碼干凈整潔,雖然底層也是通過HttpClient來實現(xiàn),但是實現(xiàn)對我來說是無感的,畢竟業(yè)務代碼看起來干凈整潔。它的demo如下:

          public static void main(String[] args) {
               String host = "https://safrvcert.market.alicloudapi.com";
               String path = "/safrv_2meta_id_name/";
               String method = "GET";
               String appcode = "你自己的AppCode";
               Map<String, String> headers = new HashMap<String, String>();
               //最后在header中的格式(中間是英文空格)為Authorization:APPCODE 83359fd73fe94948385f570e3c139105
               headers.put("Authorization""APPCODE " + appcode);
               Map<String, String> querys = new HashMap<String, String>();
               querys.put("__userId""__userId");
               querys.put("customerID""customerID");
               querys.put("identifyNum""identifyNum");
                      querys.put("identifyNumMd5""identifyNumMd5");
               querys.put("userName""userName");
               querys.put("verifyKey""verifyKey");


               try {
                /**
                * 重要提示如下:
                * HttpUtils請從
                * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java
                * 下載
                *
                * 相應的依賴請參照
                * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
                */

                HttpResponse response = HttpUtils.doGet(host, path, method, headers, querys);
                //錯誤信息見X-Ca-Error-Message字段
                          System.out.println(response.toString());
                //獲取response的body
                System.out.println(EntityUtils.toString(response.getEntity()));
               } catch (Exception e) {
                e.printStackTrace();
               }
           }
          HttpResponse response = HttpUtils.doGet(host, path, method, headers, querys);

          根據(jù)它提供的代碼我們可以看出來他是用一個httpUtils 類來實現(xiàn)http請求的,我們可以把這個httpClient類 替換成我們的FeignClient替換后的代碼如下:

          @FeignClient(name = "verifyIdCardAndNameFeignClient", url = "https://safrvcert.market.alicloudapi.com")
          public interface VerifyIdCardAndNameFeignClient {
              @RequestMapping(value = "/safrv_2meta_id_name/", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
              Response verifyIdCardAndNameMap(@RequestParam Map<String,String> app, @RequestHeader("Authorization") String authorization);

          相對比較下來下面這個HttpClientUtils代碼是不是比較簡潔按照這個demo功能確實是實現(xiàn)了,說實話個人還是不是很喜歡用map來作為參數(shù),map作為入?yún)⒌脑挘瑓?shù)全靠猜可讀性以及可維護性有點差,個人還是習慣性的封裝一個javaBean作為實體。阿里文檔其實也有提到一嘴,雖然他只說到數(shù)據(jù)查詢這一層。下面我們就修改下請求參數(shù)把它改成一個javaBean,改變后的代碼

          @RequestMapping(value = "/safrv_2meta_id_name/", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
          Response verifyIdCardAndNameDTO(@RequestBody AliyunVerifyIdCardAndNameReq app, @RequestHeader("Authorization") String authorization);

          請求并沒有成功,根據(jù)報錯返回的信息看下來應該是沒有接受到參數(shù)。我們是GET請求的方式然后參數(shù)傳遞的是實體導致沒有接收到。feignClient不支持get方式傳遞實體類嗎?后來經(jīng)過查詢資料發(fā)現(xiàn)了一個注解@SpringQueryMap 我們把上述代碼@RequestBody替換成@SpringQueryMap完美解決這個問題

          @SpringQueryMap

          spring cloud 2.1.x 以上的版本,提供了一個新的注解@SpringQueryMap,為何這個注解可以幫我們實現(xiàn)。源碼之下無秘密,我們可以翻翻feign的源碼相對來說應該是比較簡單的,我們可以簡單的來看下源碼。看源碼是不是也不知道從哪里看起,從頭看到尾肯定也不現(xiàn)實, 不從頭開始看,又不知道源碼在哪里,有個很簡單的方法我們直接拿著這個注解全局搜一下,看看有哪些地方使用到了,在每個地方都打上一個斷點試試我們?nèi)炙严掳l(fā)現(xiàn)使用的地方主要在QueryMapParameterProcessor這個類里面。所以我們可以在這個類里面打上一個斷點試試。


          /**
           * {@link SpringQueryMap} parameter processor.
           *
           * @author Aram Peres
           * @see AnnotatedParameterProcessor
           */

          public class QueryMapParameterProcessor implements AnnotatedParameterProcessor {

           private static final Class<SpringQueryMap> ANNOTATION = SpringQueryMap.class;

           @Override
           public Class<? extends Annotation> getAnnotationType() {
            return ANNOTATION;
           }

           @Override
           public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) {
            int paramIndex = context.getParameterIndex();
            MethodMetadata metadata = context.getMethodMetadata();
            if (metadata.queryMapIndex() == null) {
             metadata.queryMapIndex(paramIndex);
             metadata.queryMapEncoded(SpringQueryMap.class.cast(annotation).encoded());
            }
            return true;
           }
          }

          我們發(fā)現(xiàn)打這個類的話在容器啟動的時候會進行加載,并且會執(zhí)行processArgument方法,這個我們先不管這個方法,接下來我們來看看 Feign真正發(fā)起調(diào)用的地方找到SynchronousMethodHandler#invoke方法

          public RequestTemplate create(Object[] argv) {
           ... 省略部分代碼
           // metadata.queryMapIndex() 就是QueryMapParameterProcessor #processArgument方法賦值的
                if (metadata.queryMapIndex() != null) {
                  // add query map parameters after initial resolve so that they take
                  // precedence over any predefined values
                  // 通過下標獲取到需要特殊處理的對象,這里有個問題只會處理方法參數(shù)的第一個@SpringQueryMap注解,
                  // 原因就是QueryMapParameterProcessor #processArgument這個方法只會把第一個下標賦值進去,然后這里也只會取第一個下標,所以只會處理第一個@SpringQueryMap注解
                  Object value = argv[metadata.queryMapIndex()];
                  //將對象轉(zhuǎn)換為map  這里需要注意下默認使用解析參數(shù)的是FieldQueryMapEncoder類所以它并不會去解析父類的參數(shù),如果需要解析父類的參數(shù)我們需要在feign的Config里面指定QueryMapEncoder為FieldQueryMapEncoder
                  Map<String, Object> queryMap = toQueryMap(value);
                  //拼接解析完成的對象為URL參數(shù)
                  template = addQueryMapQueryParameters(queryMap, template);
                }
          ... 省略部分代碼
          }

          上述代碼邏輯還是挺好理解的

          • 首先去判斷是否需要處理下querymap
          • 通過下標獲取到需要特殊處理的對象
          • 將對象轉(zhuǎn)換為map(這里有個坑默認不會去解析父類的字段)
          • 拼接追加mapurl

          總結

          • 上面通過@SpringQueryMap注解實現(xiàn)了get傳參,但是如果需要傳遞多個@SpringQueryMap注解我們可以怎么來實現(xiàn)呢?
          • 或者我們可以自己動手來實現(xiàn)一個我們自己的SpringQueryMap,我們該如何實現(xiàn)?
          • @SpringQueryMap注解默認是不會去解析父類的參數(shù),如果需要解析父類的參數(shù)需要修改Feignconfig# QueryMapEncoderFieldQueryMapEncoder
          • 如果我們自己去實現(xiàn)了一個AnnotatedParameterProcessor所有默認的PathVariableParameterProcessorRequestParamParameterProcessor、RequestHeaderParameterProcessor、QueryMapParameterProcessor都會失效,為啥會失效我們?nèi)タ纯?code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">SpringMvcContract這個類。所以自定義AnnotatedParameterProcessor需要慎重。

          結束

          • 由于自己才疏學淺,難免會有紕漏,假如你發(fā)現(xiàn)了錯誤的地方,還望留言給我指出來,我會對其加以修正。
          • 如果你覺得文章還不錯,你的轉(zhuǎn)發(fā)、分享、贊賞、點贊、留言就是對我最大的鼓勵。
          • 感謝您的閱讀,十分歡迎并感謝您的關注。


          往期精選

          最近面試BAT,整理一份面試資料Java面試BATJ通關手冊,覆蓋了Java核心技術、JVM、Java并發(fā)、SSM、微服務、數(shù)據(jù)庫、數(shù)據(jù)結構、等等。獲取方式:點“在看”,關注公眾號并回復 666 領取,更多內(nèi)容陸續(xù)奉上。

          文章有幫助的話,在看,轉(zhuǎn)發(fā)吧。

          謝謝支持喲 (*^__^*)

          瀏覽 37
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  老妇裸体乱婬视频 | а√天堂资源官网在线资源 | 久久久亚洲AV成人电影 | 成人美女毛片 | 国产精品成人电影 |