springcloud學(xué)習(xí)筆記-Feign

上篇文章介紹了springcloud中eureka以及ribbon的基本使用方式,本文繼續(xù)記錄feign的學(xué)習(xí)歷程

什么是feign

feign與ribbon一樣剩膘,作用都是在springcloud中調(diào)用服務(wù)的遵馆。feign底層也是ribbon粥血,對(duì)ribbon進(jìn)行了再次封裝湿滓。

feign與ribbon的使用方式區(qū)分

  • .ribbon通過(guò)注入restTemplate來(lái)實(shí)現(xiàn)對(duì)服務(wù)的調(diào)用诗良,在調(diào)用時(shí)需要手動(dòng)構(gòu)建http請(qǐng)求
public class ConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
        log.info("consumer啟動(dòng)成功");
    }

    @Bean
    @LoadBalanced
    RestTemplate restTemplate()
    {
        return new RestTemplate();
    }
}
    @Autowired
    RestTemplate restTemplate;

    @Override
    public String hiService(String name) throws UnknownHostException {
        //當(dāng)前機(jī)器ip
        InetAddress ia = InetAddress.getLocalHost();
       //構(gòu)建http請(qǐng)求
        for (int i =0;i<1;i++){
            String str = restTemplate.getForObject("http://SERVICE-HI/hi?name=" + name, String.class);
            log.info( str + " 第 " + i + " 次調(diào)用");
        }
        return "0";
    }
  • feign通過(guò)指定FeignClient,通過(guò)接口直接調(diào)用服務(wù)
@FeignClient("SERVICE-HI")
public interface DemoServiceFeign {

    /**
     *  注意:
     *      @RequestParam 中 value要與服務(wù)提供方接口中聲明的參數(shù)一致
     *      @PostMapping 中 url要與服務(wù)提供方url一致
     * @param name
     * @return
     */
    @PostMapping("/hi")
    String hello(@RequestParam(value = "name") String name);
}

feign調(diào)用服務(wù)

    @Autowired
    private DemoServiceFeign demoServiceFeign;

    @RequestMapping(value = "/hello")
    public String hello(@RequestParam String name) throws UnknownHostException {
        return demoServiceFeign.hello(name);
    }

feign依賴

  • 不同版本的springcloud糠亩,對(duì)應(yīng)的feign依賴也不同鸥拧,文中使用這個(gè)maven坐標(biāo)
        <!--feign依賴-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
  • 老版本坐標(biāo),如果版本不符合,maven會(huì)顯示spring-cloud-starter-feign:unknow
      <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>

使用feign

@Slf4j
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
//@EnableHystrix
public class ConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
        log.info("consumer啟動(dòng)成功");
    }


}
  • 編寫接口富弦,接口添加@FeignClient注解
@FeignClient("SERVICE-HI")
public interface DemoServiceFeign {

    /**
     *  注意:
     *      @RequestParam 中 value要與服務(wù)提供方接口中聲明的參數(shù)一致
     *      @PostMapping 中 url要與服務(wù)提供方url一致
     * @param name
     * @return
     */
    @PostMapping("/hi")
    String hello(@RequestParam(value = "name") String name);
}

官網(wǎng)中有說(shuō)明,F(xiàn)eignClient注解中需要加入被feign調(diào)用服務(wù)的 應(yīng)用名稱:spring.application.name=service-hi氛驮;文檔還提到“您還可以使用url屬性(絕對(duì)值或只是主機(jī)名)指定URL”,本文使用服務(wù)名稱

  • 控制層調(diào)用腕柜,注入接口調(diào)用,當(dāng)做普通方法調(diào)用即可
    注意這里不需要在注入restTemplate類來(lái)手動(dòng)構(gòu)建http請(qǐng)求了矫废。
    feign底層的介紹推薦這幾篇文章:https://blog.csdn.net/qq_39470742/article/details/83539517
    博主有很多篇介紹feign源碼的文章
    @Autowired
    private DemoServiceFeign demoServiceFeign;

    @RequestMapping(value = "/hello")
    public String hello(@RequestParam String name) throws UnknownHostException {
        return demoServiceFeign.hello(name);
    }
  • 調(diào)用結(jié)果,已經(jīng)使用feign實(shí)現(xiàn)了服務(wù)間調(diào)用


    圖片.png
  • feign切換負(fù)載均衡策略
    文章開頭有說(shuō)道feign本質(zhì)上調(diào)用的也是ribbon盏缤,是對(duì)ribbon的高度封裝,因此切換負(fù)載均衡策略蓖扑,實(shí)際上就是對(duì)ribbon切換負(fù)載均衡策略

SERVICE-HI:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

ribbon默認(rèn)輪詢策略唉铜,這里切換為隨機(jī)策略,可以看到結(jié)果已經(jīng)成功了

圖片.png

到這里feign簡(jiǎn)單使用已經(jīng)完成了,至于服務(wù)間調(diào)用選擇feign還是ribbon律杠,網(wǎng)上有很多種說(shuō)法潭流,個(gè)人感覺feign確實(shí)很好用,接口以及注解標(biāo)明調(diào)用的api可讀性很強(qiáng)柜去,更容易上手灰嫉。下面介紹一些使用feign時(shí)遇到的問題

read time out

feign底層使用的ribbon,ribbon本身有默認(rèn)的超時(shí)時(shí)間嗓奢,在LoadBalancerFeignClient.java類中有execute方法讼撒,如下:

        @Override
    public Response execute(Request request, Request.Options options) throws IOException {

execute方法中有兩個(gè)參數(shù),Request是包含一些請(qǐng)求信息股耽,Options是配置相關(guān)信息根盒,Options類內(nèi)容如下:

public static class Options {
        private final int connectTimeoutMillis;
        private final int readTimeoutMillis;
        private final boolean followRedirects;

        public Options(int connectTimeoutMillis, int readTimeoutMillis, boolean followRedirects) {
            this.connectTimeoutMillis = connectTimeoutMillis;
            this.readTimeoutMillis = readTimeoutMillis;
            this.followRedirects = followRedirects;
        }

        public Options(int connectTimeoutMillis, int readTimeoutMillis) {
            this(connectTimeoutMillis, readTimeoutMillis, true);
        }

        public Options() {
            this(10000, '\uea60');
        }

        public int connectTimeoutMillis() {
            return this.connectTimeoutMillis;
        }

        public int readTimeoutMillis() {
            return this.readTimeoutMillis;
        }

        public boolean isFollowRedirects() {
            return this.followRedirects;
        }
    }

這里可以看到,如果ribbon默認(rèn)的連接時(shí)間為10秒物蝙,默認(rèn)的readTimeOut時(shí)間為60秒炎滞;我們讓服務(wù)提供者睡眠10秒后提供服務(wù),來(lái)測(cè)試readTimeOut時(shí)間是否合理茬末,代碼如下

//服務(wù)提供者厂榛,休眠10秒
@RestController
public class DemoController {

    @Value("${server.port}")
    String port;

    @RequestMapping("/hi")
    public String home(@RequestParam(value = "name") String name)
    {
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "hi " + name + ",i am from port:" + port;
    }
}

結(jié)果

圖片.png

idea報(bào)錯(cuò)

java.net.SocketTimeoutException: Read timed out
    at java.net.SocketInputStream.socketRead0(Native Method) ~[na:1.8.0_181]
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) ~[na:1.8.0_181]
    at java.net.SocketInputStream.read(SocketInputStream.java:171) ~[na:1.8.0_181]
    at java.net.SocketInputStream.read(SocketInputStream.java:141) ~[na:1.8.0_181]
    at java.io.BufferedInputStream.fill(BufferedInputStream.java:246) ~[na:1.8.0_181]
    at java.io.BufferedInputStream.read1(BufferedInputStream.java:286) ~[na:1.8.0_181]
    at java.io.BufferedInputStream.read(BufferedInputStream.java:345) ~[na:1.8.0_181]
    at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:735) ~[na:1.8.0_181]
    at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:678) ~[na:1.8.0_181]
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1587) ~[na:1.8.0_181]
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492) ~[na:1.8.0_181]
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480) ~[na:1.8.0_181]
    at feign.Client$Default.convertResponse(Client.java:82) ~[feign-core-10.4.0.jar:na]

可以看到盖矫,在沒有主動(dòng)修改ribbon超時(shí)時(shí)間時(shí),他默認(rèn)是60秒击奶,但休眠10秒就已經(jīng)超時(shí)了辈双,事實(shí)上及時(shí)休眠1秒也會(huì)超時(shí),感興趣的可以測(cè)試一下柜砾,原因是hystrix默認(rèn)是1秒超時(shí)湃望,這里就需要指定feign的超時(shí)時(shí)間,具體設(shè)置多少需要看各個(gè)項(xiàng)目的需求

feign學(xué)習(xí)到這里就基本完成了痰驱,接下來(lái)會(huì)記錄hystrix的學(xué)習(xí)证芭,歡迎大家來(lái)討論

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市担映,隨后出現(xiàn)的幾起案子废士,更是在濱河造成了極大的恐慌,老刑警劉巖蝇完,帶你破解...
    沈念sama閱讀 212,294評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件官硝,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡短蜕,警方通過(guò)查閱死者的電腦和手機(jī)氢架,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,493評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)朋魔,“玉大人岖研,你說(shuō)我怎么就攤上這事【欤” “怎么了孙援?”我有些...
    開封第一講書人閱讀 157,790評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)解滓。 經(jīng)常有香客問我赃磨,道長(zhǎng)筝家,這世上最難降的妖魔是什么洼裤? 我笑而不...
    開封第一講書人閱讀 56,595評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮溪王,結(jié)果婚禮上腮鞍,老公的妹妹穿的比我還像新娘。我一直安慰自己莹菱,他們只是感情好移国,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,718評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著道伟,像睡著了一般迹缀。 火紅的嫁衣襯著肌膚如雪使碾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,906評(píng)論 1 290
  • 那天祝懂,我揣著相機(jī)與錄音票摇,去河邊找鬼。 笑死砚蓬,一個(gè)胖子當(dāng)著我的面吹牛矢门,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播灰蛙,決...
    沈念sama閱讀 39,053評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼祟剔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了摩梧?” 一聲冷哼從身側(cè)響起物延,我...
    開封第一講書人閱讀 37,797評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎仅父,沒想到半個(gè)月后教届,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,250評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡驾霜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,570評(píng)論 2 327
  • 正文 我和宋清朗相戀三年案训,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粪糙。...
    茶點(diǎn)故事閱讀 38,711評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡强霎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蓉冈,到底是詐尸還是另有隱情城舞,我是刑警寧澤,帶...
    沈念sama閱讀 34,388評(píng)論 4 332
  • 正文 年R本政府宣布寞酿,位于F島的核電站家夺,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏伐弹。R本人自食惡果不足惜拉馋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,018評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望惨好。 院中可真熱鬧煌茴,春花似錦、人聲如沸日川。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,796評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)龄句。三九已至回论,卻和暖如春散罕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背傀蓉。 一陣腳步聲響...
    開封第一講書人閱讀 32,023評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工笨使, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人僚害。 一個(gè)月前我還...
    沈念sama閱讀 46,461評(píng)論 2 360
  • 正文 我出身青樓硫椰,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親萨蚕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子靶草,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,595評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容