Spring Cloud(十一)聲名式服務調用:Feign的使用 (上)


一、寫在前邊

最近開發任務比較忙,下班也開始鍛煉了,這個系列的文章就放了很久,看github我提交的Feign的入門程序已經好久了,今天正好得空,這就更上一貼,准備分幾部分寫

注意:之前幾個項目中,筆者忽略了一個問題,pom文件中如果parent節點下的是spring-cloud-starter-parent而不是spring-boot-starter-parent的話,這樣就可以不用寫如下代碼了

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Camden.SR3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

二、Feign簡介

通過前面的學習對Ribbon和Hystrix來進行開發,通過這兩個重磅武器學會了如何在微服務實現客戶端的負載均衡、服務調用和斷路保護,實踐中我們發現這兩個基礎工具總是成對出現的,那么有沒有更高層次的封裝來簡化開發呢?

Spring為我們提供了Spring Cloud Feign就是這樣的一個工具,基於Netflix Feign實現,除了負載均衡、服務調用和斷路保護的功能外,還提供了聲明式Web服務客戶端的定義方式以及兼容SpringMVC的注解支持。

三、快速入門

繼續使用之前的整個項目,沒有這個項目的同學請clone下來代碼,地址:https://github.com/HellxZ/SpringCloudLearn.git

新建一個項目名為FeignCustomer

pom.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.cnblogs.hellxz</groupId>
    <artifactId>FeignCustomer</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-parent</artifactId>
        <version>Dalston.SR5</version>
        <relativePath/>
    </parent>

    <dependencies>
        <!-- Hystrix,Feign是基於Hystrix的-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
        </dependency>
        <!-- Eureka依賴,連接注冊中心的都需要有這個依賴 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <!-- Feign依賴,聲明式開發 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>
        <!-- SpringMVC依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

如同常規在resources包下創建application.yml

server:
  port: 9001
spring:
  application:
    name: feign-customer
eureka:
  client:
    serviceUrl:
      defaultZone: http://peer1:1111/eureka

創建主類,相較於其他只需添加@EnableFeignClients來開啟Feign的支持

package com.cnblogs.hellxz;

import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

@EnableFeignClients //開啟Feign
@SpringCloudApplication
public class FeignApp {

    public static void main(String[] args) {
        SpringApplication.run(FeignApp.class, args);
    }
}

除了以上的我們需要一個用來調用服務提供者的工具,在Ribbon那幾章我們使用的是RestTemplate,Feign是一種聲明式調用工具,下面就來探索一下

com.cnblogs.hellxz.client創建EurekaServiceFeign,這個是用來當做Service一樣的用法,代碼如下:

package com.cnblogs.hellxz.client;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * 服務提供者的Feign
 * 這個接口相當於把原來的服務提供者項目當成一個Service類,
 * 我們只需在聲明它的Feign-client的名字,會自動去調用注冊中心的這個名字的服務
 * 更簡單的理解是value相當於MVC中的Controller類的父路徑,通過"父路徑+子路徑和參數來調用服務"
 */
@FeignClient(value = "eureka-service") //其中的value的值為要調用服務的名稱
public interface EurekaServiceFeign {

    /**
     * 第一個Feign代碼
     * Feign中沒有原生的@GetMapping/@PostMapping/@DeleteMapping/@PutMapping,要指定需要用method進行
     */
    @RequestMapping(value = "/hello", method=RequestMethod.GET)
    String helloFeign();
}

剛才說過我們可以使用這個Feign當做Service來使用服務提供者的方法,得出返回值,這里我們寫一個Controller來示范一下使用

package com.cnblogs.hellxz.controller;

import com.cnblogs.hellxz.client.EurekaServiceFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("feign")
public class HelloController {

    @Autowired
    private EurekaServiceFeign eurekaServiceFeign; //注入Feign

    @GetMapping("/hello")
    @ResponseBody
    public String sayHello(){
        //在方法中調用feign的方法
        return eurekaServiceFeign.helloFeign();
    }
}

好了,我們分別啟動注冊中心、服務提供者、還有這個Feign項目

使用postman進行測試,使用Get請求訪問http://localhost:9001/feign/hello

四、參數綁定

Spring官方在整合NetFlix Feign的時候,加入了SpringMVC的注解支持,這使得Feign讓習慣了SpringMVC的程序員更好的過渡過來,下面我舉幾個例子,就舉項目中最常用的吧。

1. @PathVariable

擴充EurekaServiceFeign,添加如下代碼,注釋很詳細,不多說

    /**
     * 在服務提供者我們有一個方法是用直接寫在鏈接,SpringMVC中用的@PathVariable
     * 這里邊和SpringMVC中有些有一點點出入,SpringMVC中只有一個參數而且參數名的話是不用額外指定參數名的,而feign中必須指定
     */
    @RequestMapping(value = "/greet/{dd}",method = RequestMethod.GET)
    String greetFeign(@PathVariable("dd") String dd);

HelloController中也添加對應的代碼,用來調用上邊的方法

    /**
     * 注意這里是SpringMVC,URL中的參數與方法中的參數名相同無需在注解中注明參數名
     */
    @GetMapping("/greet/{test}")
    @ResponseBody
    public String greet(@PathVariable String test){
        return eurekaServiceFeign.greetFeign(test);
    }

測試這個方法

2. @RequestParam

為聲名為Feign的類添加方法,調用服務提供者的方法

如下代碼中使用的User類是從服務提供者模塊中復制出來的

    /**
     * 這里說下@RequestParam 注解和SpringMVC中差別也是不大,我認為區別在於Feign中的是參數進入URL或請求體中,
     * 而SpringMVC中是參數從請求體中到方法中
     * @param ids id串,比如“1,2,3”
     * @return
     */
    @RequestMapping(value = "/users",method = RequestMethod.GET)
    public List<User> getUsersByIds(@RequestParam("ids") List<Long> ids);

調用這個方法的方法

    /**
     * 調用Feign中使用@RequestParam的方法
     */
    @GetMapping("/users")
    @ResponseBody
    public List<User> getUserListByIds(@RequestParam("ids") List<Long> ids){
      return eurekaServiceFeign.getUsersByIds(ids);
    }

測試

3. @RequestHeader

這里是為請求的Header中加入參數的注解,但是之前我們的服務提供者並沒有這個方法,這里為GetRequestController添加一個方法如下

    @GetMapping("/headers")
    public String getParamByRequestHeader(@RequestHeader("name") String name){
        return name;
    }

現在我們為Feign這個類添加一個調用上邊方法的方法

    /**
     * 這里是將參數添加到Headers中
     * @param name 參數
     */
    @RequestMapping(value = "/headers")
    String getParamByHeaders(@RequestHeader("name") String name);

在Controller中,添加代碼

    @GetMapping("/headers")
    @ResponseBody
    public String getParamByHeaders(@RequestHeader("name") String name){
        return eurekaServiceFeign.getParamByHeaders(name);
    }

測試

5. @RequestBody

使用這個注解需要使用Post請求,這里簡單舉例

Feign類中添加方法

    /**
     * 調用服務提供者的post方法,接收回來再被服務提供者丟回來
     * @param user User對象
     */
    @RequestMapping(value = "/user", method = RequestMethod.POST)
    User getUserByRequestBody(@RequestBody User user);

Controller中添加

    @PostMapping("/requestBody")
    @ResponseBody
    public User getParamByRequestBody(@RequestBody User user){
        return eurekaServiceFeign.getUserByRequestBody(user);
    }

測試

需要注意的是@RequestParam@RequestHeader,以及最先提到的@PathVariable這三個注解都需要寫明參數名稱,這點與SpringMVC中不同,否則會報IllegalStateException異常,所以一定要指明參數名!

時間不早了,明天繼續更


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM