在线不卡日本ⅴ一区v二区_精品一区二区中文字幕_天堂v在线视频_亚洲五月天婷婷中文网站

  • <menu id="lky3g"></menu>
  • <style id="lky3g"></style>
    <pre id="lky3g"><tt id="lky3g"></tt></pre>

    「Feign」OpenFeign入門以及遠(yuǎn)程調(diào)用

    一、OpenFeign介紹

    OpenFeign是 種聲明式,模版化的HTTP客戶端。使 OpenFeign進 遠(yuǎn)程調(diào) 時,開發(fā)者完全感知不到這是在進 遠(yuǎn)程調(diào) , 是像在調(diào) 本地 法 樣。使 式是注解+接 形式,把需要調(diào) 的遠(yuǎn)程接 封裝到接 當(dāng)中,映射地址為遠(yuǎn)程接 的地址。在啟動SpringCloud應(yīng) 時,F(xiàn)eign會掃描標(biāo)有@FeignClient注解的接 , 成代理并且注冊到Spring容器當(dāng)中。 成代理時Feign會為每個接 法創(chuàng)建 個RequestTemplate對象,該對象封裝HTTP請求需要的全部信息,請求參數(shù)名、請求 法等信息都是在這個過程中確定的,模版化就體現(xiàn)在這 。

    二、OpenFeign的使用

    • 搭建前置環(huán)境,在pom.xml文件中引入依賴,可以選擇使用注冊中心或者配置中心

    org.springframework.cloud spring-cloud-dependencies 2020.0.3 pom import org.springframework.cloud spring-cloud-starter-consul-config org.springframework.cloud spring-cloud-starter-consul-discovery org.springframework.boot spring-boot-starter-actuator org.springframework.cloud spring-cloud-starter-openfeign

    1.使用注冊中心

    • 使 注冊中 ,將服務(wù)注冊到consul(nacos),調(diào) 者拿到被調(diào) 服務(wù)的地址端 進 調(diào)

    spring.cloud.consul.host=192.168.0.124#consul地址spring.cloud.consul.port=8080#端 號spring.cloud.consul.discovery.service-name=service-test-01#服務(wù)名稱spring.cloud.consul.discovery.health-check-interval=1m#健康檢查間隔時間server.port=10000#服務(wù)端 號

    • 在配置類上開啟服務(wù)發(fā)現(xiàn)以及允許遠(yuǎn)程調(diào)

    @EnableDiscoveryClient //開啟服務(wù)發(fā)現(xiàn)@EnableFeignClients //開啟服務(wù)調(diào) ,只需要在調(diào) 開啟即可

    • 服務(wù)運 之后可以在consul的UI界 看到運 的服務(wù),consul會定時檢查服務(wù)的健康狀態(tài)
    • 創(chuàng)建遠(yuǎn)程調(diào)用接口

    @FeignClient(“serviceName”)public interface Service2Remote { /** 這 有 定義解碼器對遠(yuǎn)程調(diào) 的結(jié)果進 解析,拿到真正的返回類型,所以接 返回值類型和遠(yuǎn)程接 返回類型保持 致 **/ @PostMapping(“/page”) List pageQuestion(PageQuestionReq req);}

    • 簡單使用

    @RestController@RequestMapping(“/service/remote”)public class RemoteController { @Autowired private Service2Remote service2Remote; @PostMapping(“/getQuestionList”) public List getQuestionList(@RequestBody PageQuestionReq req){ List result = service2Remote.pageQuestion(req); //對拿到的數(shù)據(jù)進 處理… return result; }}

    2.使用配置中心

    • 將請求的URL寫在配置中 進 讀取修改配置 件

    spring.cloud.consul.config.format=KEY_VALUE#consul 持yaml格式和Key-value形式spring.cloud.consul.config.enabled=true#開啟配置spring.cloud.consul.config.prefixes=glab/plat/wt/application/test#consul配置存放的外層 件夾 錄spring.cloud.consul.config.default-context=config# 級 件夾spring.cloud.consul.config.watch.delay=1000#輪詢時間spring.cloud.consul.discovery.enabled=false#關(guān)閉注冊remote.url=www.baidu.com#請求地址

    • 創(chuàng)建遠(yuǎn)程調(diào)用接口

    @FeignClient(name = “service2RemoteByUrl”,url = “${remote.url}”) //name需要配置,URL從配置中 讀取public interface Service2RemoteByUrl { @PostMapping(“/page”) List pageQuestion(PageQuestionReq req);}

    3.自定義解碼器(編碼器

    // 定義解碼器實現(xiàn)Decoder接 ,重寫decode 法即可,根據(jù)具體需求進 編寫//如果是 定義編碼器,需要實現(xiàn)Encoder接 ,重寫encode 法public class FeignDecoder implements Decoder { @Override public Object decode(Response response, Type type) throws IOException,DecodeException, FeignException { if (response.body() == null){ throw new DecodeException(ErrorEnum.EXECUTE_ERR.getErrno(),”沒有獲取到有效結(jié)果值”,response.request()); } // 拿到值 String result = Util.toString(response.body().asReader(Util.UTF_8)); Map resMap = null; try { resMap = JSON.parseObject(result, Map.class); } catch (Exception e) { //返回結(jié)果是字符串 return result; }}

    4.遠(yuǎn)程調(diào)用攜帶Cookie

    • 由于feign調(diào) 是新創(chuàng)建 個Request,因此在請求時不會攜帶 些原本就有的信息,例如Cookie,因此需要 定義RequestInterceptor對Request進 額外設(shè)置, 般情況下,寫 Cookie是 較常 的做法,如下設(shè)置

    @Configurationpublic class BeanConfig { @Bean public RequestInterceptor requestInterceptor(){ return template -> { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); //此處可以根據(jù)業(yè)務(wù) 具體定制攜帶規(guī)則 String data = request.getParameter(“data”); String code = null; try { //這 需要轉(zhuǎn)碼,否則會報錯 code = URLEncoder.encode(data, “UTF-8”); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } template.query(“data”,code); //請求頭中攜帶Cookie String cookie = request.getHeader(“Cookie”); template.header(“Cookie”,cookie); }; } @Bean public Decoder decoder(){ return new FeignDecoder(); }}

    三、調(diào)用流程解析

    //在使 EnableFeignClients開啟feign功能時,點擊進 會看到該注解是通過ImportFeignClientsRegistrar類 效的,其中有個 法//registerBeanDefinitions執(zhí) 兩條語句registerDefaultConfiguration(metadata, registry); //加載默認(rèn)配置信息registerFeignClients(metadata, registry); //注冊掃描標(biāo)有FeignClient的接 //關(guān)注registerFeignClients 法for (String basePackage : basePackages) { candidateComponents.addAll(scanner.findCandidateComponents(basePackage)); //在basePackage路徑下掃描并添加標(biāo)有FeignClient的接 }for (BeanDefinition candidateComponent : candidateComponents) { //遍歷 if (candidateComponent instanceof AnnotatedBeanDefinition) { registerClientConfiguration(registry, name, attributes.get(“configuration”)); // registerFeignClient(registry, annotationMetadata, attributes); //注冊到Spring容器當(dāng)中, 法詳細(xì)在FeignClientsRegistrar類當(dāng)中 }}//在對feign調(diào) 時進 斷點調(diào)試//在 成Feign遠(yuǎn)程接 的代理類時,調(diào) 處理器是Feign提供的FeignInvocationHandlerpublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (“equals”.equals(method.getName())) { //equals,hashCode,toString三個 法直接本地執(zhí) } else if (“hashCode”.equals(method.getName())) { return hashCode(); } else if (“toString”.equals(method.getName())) { return toString(); } //執(zhí) 法對應(yīng)的 法處理器MethodHandler,這個接 是Feign提供的,與InvocationHandler 任何關(guān)系,只有 個invoke 法 return dispatch.get(method).invoke(args);}//點進上 的invoke 法public Object invoke(Object[] argv) throws Throwable { //創(chuàng)建 個request模版 RequestTemplate template = buildTemplateFromArgs.create(argv); while (true) { try { return executeAndDecode(template, options); //創(chuàng)建request執(zhí) 并且解碼 } }}Object executeAndDecode(RequestTemplate template, Options options) throws Throwable { Request request = targetRequest(template); //創(chuàng)建Request并增強 Response response = client.execute(request, options); //執(zhí) 調(diào)用請求,不再繼續(xù)分析了 response = response.toBuilder().request(request).requestTemplate(template).build(); //如果有重寫解碼器,使 定義的解碼器,feign默認(rèn)使 SpringEncoder if (decoder != null) return decoder.decode(response, metadata.returnType()); } Request targetRequest(RequestTemplate template) { //如果 定義了RequestInterceptor,在這 可以對Request進 增強 for (RequestInterceptor interceptor : requestInterceptors) { //執(zhí) 定義的apply 法 interceptor.apply(template); } //創(chuàng)建Request return target.apply(template);}

    四、補充

    • 關(guān)于Client接 的實現(xiàn)類,使 注冊中 和使 配置中 其流程稍有區(qū)別

    //使 配置中 拿url 式進 調(diào) ,使 的是Client的默認(rèn)內(nèi)部實現(xiàn)類 Default ,其中Default使 的是HttpURLConnection進 Http請求的HttpURLConnection connection = convertAndSend(request, options);//如果使 的是服務(wù)發(fā)現(xiàn),使 的使 Client的實現(xiàn)類FeignBlockingLoadBalancerClient,它會去根據(jù)配置的服務(wù)名去注冊中 查找服務(wù)的IP地址和端 號,執(zhí) 使 的仍然是默認(rèn)實現(xiàn)類Default,通過HttpURLConnection請求//FeignBlockingLoadBalancerClient,根據(jù)服務(wù)名稱查找服務(wù)IP地址、端 88 ServiceInstance instance = loadBalancerClient.choose(serviceId, lbRequest);//具體實現(xiàn) 法,BlockingLoadBalancerClient類中 145 Response loadBalancerResponse = Mono.from(loadBalancer.choose(request)).block();//還有其他實現(xiàn)Client接 的客戶端,例如ApacheHttpClient,ApacheHttpClient帶有連接池功能,具有優(yōu)秀的HTTP連接復(fù) 能 ,需要通過引 依賴來使

    鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場,版權(quán)歸原作者所有,如有侵權(quán)請聯(lián)系管理員(admin#wlmqw.com)刪除。
    上一篇 2022年6月13日 21:14
    下一篇 2022年6月13日 21:14

    相關(guān)推薦

    聯(lián)系我們

    聯(lián)系郵箱:admin#wlmqw.com
    工作時間:周一至周五,10:30-18:30,節(jié)假日休息