Spring Cloud OpenFeign使用教程


Spring Cloud OpenFeign Demo

之前項目中需要在Spring Cloud中使用OpenFeign的情況,Spring Cloud的版本是目前最新的Greenwich.SR2版本,對應的Spring boot是2.1.7.RELEASE。

在網上找了很多資料,大多言之不詳,並且版本也比較低,不適合我的最新版本Spring Cloud的需求。 所以決定還是自己寫個教程。

本教程要解決如下幾個問題:

  1. 怎么配置OpenFeignServer
  2. 怎么配置OpenFeignClient
  3. 多個參數傳遞問題
  4. FeignClient的日志問題
  5. 多個FeignClient使用同一個name的問題

怎么配置OpenFeignServer

我們知道OpenFeign是用在Spring Cloud中的聲明式的web service client。

OpenFeignServer就是一個普通的Rest服務,不同的是我們需要將他注冊到eureka server上面,方便后面的OpenFeignClient調用。

啟動類如下:

@SpringBootApplication
@EnableDiscoveryClient
public class OpenFeignServer {
        public static void main(String[] args) {
            SpringApplication.run(OpenFeignServer.class, args);
    }
}

我們定義了兩個Rest服務:

OrderController:


@Slf4j
@RestController
@RequestMapping(path = "/order")
public class OrderController {

    /** * PostMapping with @RequestBody * @param user */
    @PostMapping("doOrder")
    public void doOrder(@RequestBody User user){
        log.info("do order !!!!");
    }
}

UserController:

@RestController
@RequestMapping(path = "/user")
public class UserController {

    /** * GetMapping example with @RequestParam * @param userId * @return userName */
    @GetMapping("getUserName")
    public String getUserName(@RequestParam("userId") String userId){
        if("100".equals(userId)) {
            return "張學友";
        }else{
            return "劉德華";
        }
    }

    /** * GetMapping example with @RequestParam and @SpringQueryMap * @param userId * @param user * @return userAge */
    @GetMapping("getUserAge")
    public String getUserAge(@RequestParam("userId") String userId, @SpringQueryMap User user){
        if("100".equals(userId)) {
            return "20";
        }else{
            return "18";
        }
    }
}

我們將其注冊到eureka上面,名字為openfeign-server

spring:
  application:
    name: openfeign-server

怎么配置OpenFeignClient

OpenFeignClient的pom依賴如下:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

配置OpenFeignClient只需要使用@FeignClient來注解一個interface即可,如下所示:

@FeignClient(value = "openfeign-server")
@RequestMapping(path = "/user")
public interface UserClient {

    @GetMapping("getUserName")
    public String getUserName(@RequestParam("userId") String userId);

    @GetMapping("getUserAge")
    public String getUserAge(@RequestParam("userId") String userId, @SpringQueryMap User user);
}

其中@FeignClient中的value是要調用的服務的注冊名,即OpenFeignServer在eureka的注冊名。

FeignClient的 Request路徑,方式和參數要和被調用的Rest服務保持一致。

這樣我們就可以像下面一樣來調用OpenFeignClient了:

@Slf4j
@RestController
public class UserController {

    @Autowired
    private UserClient userClient;

    @GetMapping("getUserName2")
    public void getUserName(){
        log.info(userClient.getUserName("100"));
    }
}

多個參數傳遞問題

一般我們會使用@GetMapping和@PostMapping兩種方式來調用Rest服務。

而接收的參數則會使用@RequestParam和@RequestBody來獲取。

首先我們講一下@RequestBody,@RequestBody只能用在Post請求,並且一個Post請求只能有一個@RequestBody。 @RequestBody的參數可以包括復雜類型。

然后我們講一下@RequestParam,@RequestParam可以用在Post和Get請求中,但是要注意:@RequestParam 的參數只能是基本類型或者Enum,或者List和Map(List和Map里面也只能是基本類型)。所以@RequestParam可以和@RequestBody一起使用。

如果我們是Get請求,但是又有復合類型怎么辦? 比如我們想傳遞一個User對象。User對象里面只有普通的兩個String屬性。 這里我們可以使用@SpringQueryMap:

    @GetMapping("getUserAge")
    public String getUserAge(@RequestParam("userId") String userId, @SpringQueryMap User user);

注意:@SpringQueryMap后面的參數只能是普通的POJO,不能是復合類型,否則解析不了。如果必須使用復合類型,那么使用@RequestBody吧。

FeignClient的日志問題

OpenFeign的Logger.Level有4種級別:

  • NONE 沒有日志
  • BASIC 請求方法,請求URL,返回Code和執行時間
  • HEADERS 請求和返回的頭部基本信息
  • FULL 請求和返回的頭部,內容,元數據

要想使用這些級別,必須將OpenFeignClient的logger設置成debug級別:

#日志配置
logging:
  level:
    com:
      flydean: debug

同時我們在代碼中配置OpenFeign的日志級別:

@Configuration
public class CustFeignLogConfig {
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

這樣我們在日志里面就可以看到DEBUG的所有HTTP請求信息。

多個FeignClient使用同一個name的問題

其實這里我們的Server定義了兩個Rest服務,User和Order。

上面我們講到了可以這樣定義UserClient:

@FeignClient(value = "openfeign-server")
@RequestMapping(path = "/user")
public interface UserClient {
    ...
}

如果我們同樣的這樣定義OrderClient:

@FeignClient(value = "openfeign-server")
@RequestMapping(path = "/order")
public interface OrderClient {
    ...
}

運行時候就會報錯。 原因是兩個FeignClient使用了同一個value!

那怎么解決這個問題呢?

/** * 因為@FeignClient的value不能重復,所以需要在這里以自定義的方式來創建 * @author wayne * @version FeignClientController, 2019/9/5 7:07 下午 */
@Data
@Component
@Import(FeignClientsConfiguration.class)
public class FeignClientController {

    private OrderClient orderClient;
    private UserClient userClient;

    public FeignClientController(Decoder decoder, Encoder encoder, Client client, Contract contract) {
        this.orderClient = Feign.builder().client(client)
                .encoder(encoder)
                .decoder(decoder)
                .contract(contract)
                //默認是Logger.NoOpLogger
                .logger(new Slf4jLogger(OrderClient.class))
                //默認是Logger.Level.NONE
                .logLevel(Logger.Level.FULL)
                .target(OrderClient.class, "http://openfeign-server");

        this.userClient = Feign.builder().client(client)
                .encoder(encoder)
                .decoder(decoder)
                .contract(contract)
                //默認是Logger.NoOpLogger
                .logger(new Slf4jLogger(UserClient.class))
                //默認是Logger.Level.NONE
                .logLevel(Logger.Level.FULL)
                .target(UserClient.class, "http://openfeign-server");
    }
}

方法就是手動創建FeignClient, 上面的例子中,我們手動創建了OrderClient和UserClient兩個FeignClient。

注意下面的代碼片段,手動創建的FeignClient默認是沒有logger和logLevel的。所以上面我們配置好的log信息對手動創建的FeignClient是無效的。 下面展示了如何手動添加:

//默認是Logger.NoOpLogger
                .logger(new Slf4jLogger(OrderClient.class))
                //默認是Logger.Level.NONE
                .logLevel(Logger.Level.FULL)

如何運行

本項目的模塊都是以spring boot構建的,直接在編譯器中運行Main方法即可啟動。

  1. 啟動openfeign-registry-server

openfeign-registry-server會啟動eureka server,供后面的OpenFeignServer和OpenFeignClient注冊。

  1. 啟動openfeign-server

  2. 啟動openfeign-client

  3. 測試openFeignClient

get請求url: http://localhost:8000/getUserName1

查看日志,看看輸出吧。

本項目代碼地址 :spring-cloud-openfeign-demo

更多教程請參考 flydean的博客


免責聲明!

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



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