OpenFeign筆記


0 環境

系統環境:win10
編輯器:idea
springcloud版本:H版

1 前言

之前使用的eureka/hystrix 都是調用RestTemplate(繁瑣 重復高) OpenFeign對請求進行簡化。Feign停更了 OpenFeign是在Feign基礎上開發出來的

  • 常用的幾種接口調用方法
  • Httpclient 易用 靈活
  • Okhttp 處理網絡請求 輕量級 支持多協議。。
  • HttpURLConnection 使用復雜
  • RestTemplate Rest服務的客戶端 提供多種便攜訪問HTTP服務的方法

2 嘗鮮

2.1 創建springboot項目

在這里插入圖片描述

2.2 yml配置

spring:
  application:
    name: openfeign


eureka:
  client:
    service-url:
      defaultZone: http://localhost:1234/eureka

server:
  port: 5000

2.3 啟動類配置

@EnableFeignClients --> 開啟Feign在這里插入圖片描述

2.4 接口配置

使用的是之前的eureka server和provider以及如今使用的openfeign

// openfeign service
// 對比之前xxx.getForObject("http://provider/hello1", String.class)
// 現在只需要抽取provider hello1 拼接不需要我們操心了
@FeignClient("provider")
public interface HelloService {
	@GetMapping("/hello")
    // 方法名無所謂 無參調用
    String hello();
}    

2.5 接口調用

@RestController
public class HelloController {
    @Autowired
    HelloService helloService;

    // 無參測試
    @GetMapping("/hello")
    public String hello(){
        return helloService.hello();
    }
}    

2.6 測試結果

開啟eureka server provider openfeign
在這里插入圖片描述

3 參數傳遞

3.1 導入依賴模塊

因為要用到類 之前新建一個模塊 現在該opfeign需要引入依賴 可以在opfeign中定義類(隨意)

		<dependency>
            <groupId>xxx</groupId>
            <artifactId>commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

3.2 接口配置

// eureka provider
@RestController
public class HelloController {
	
	@GetMapping("/hello1")
    public String hello1(String name){
        return "hello provider: " + name;
    }
	
	@PostMapping("/user1")
    public User addUser1(@RequestBody User user){
        return user;
    }
	
	@DeleteMapping("/user1/{id}")
    public void delUser1(@PathVariable Integer id){
        System.out.println("json形式:" + id);
    }

    @GetMapping("/user2")
    public void getUserByName(@RequestHeader String name) throws UnsupportedEncodingException {
        // 解碼
        System.out.println(URLDecoder.decode(name, "utf-8"));
    }
}    
// openfeign service配置
@FeignClient("provider")
public interface HelloService {
    // 參數傳遞一定要綁定參數名
    @GetMapping("/hello1")
    String hello1(@RequestParam("name") String name);

    // json
    // 注:key/value形式的參數 一定要標記參數的名稱
    @PostMapping("/user1")
    User user1(@RequestBody User user);

    // 刪除id
    // /user1/{id}
    @DeleteMapping("/user1/{id}")
    void delUser1(@PathVariable Integer id);

    // 通過header來傳參 中文要轉碼
    @GetMapping("/user2")
    void getUserByName(@RequestHeader String name);

}

3.3 接口調用

	// openfeign controller 傳參
    @GetMapping("/hello1")
    public void hello1() throws UnsupportedEncodingException {
        String s = helloService.hello1("你好呀");
        System.out.println("hello1:" + s);
        System.out.println("---------------------------------------");
        User user = new User();
        user.setId(1);
        user.setName("小個");
        user.setNickName("薩達過");
        User user1 = helloService.user1(user);
        System.out.println("user:" + user1);
        System.out.println("---------------------------------------");
        helloService.delUser1(1);
        System.out.println("---------------------------------------");
        // 放在heard中的中文參數 一定要先編碼在傳遞
        helloService.getUserByName(URLEncoder.encode("方便熱土", "utf-8"));

    }

3.4 測試結果

開啟eureka server provider openfeign
在這里插入圖片描述

3.5 小結

  • 參數傳遞
  • 參數一定要綁定參數名
  • 若通過header來傳遞參數 中文需轉碼 編碼后在傳遞(URLEncoder.encode(xxx, "utf-8"))
    .provider解碼(URLDecoder.decode(xxx, "utf-8"))

4 繼承特性

4.1 新建maven子模塊

這個包被其他模塊依賴 需要springmvc依賴

<dependencies>
        <!-- 涉及到springmvc -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>

        <!-- 存儲類模塊 -->
        <dependency>
            <groupId>xxx</groupId>
            <artifactId>commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

    </dependencies>

4.2 封裝接口

public interface IUserService {
    @GetMapping("/hello")
    String hello();

    // 參數傳遞一定要綁定參數名 若是參數最好用@RequestParam
    // 最好別用map 其問題是可以隨意傳參
    @GetMapping("/hello1")
    String hello1(@RequestParam("name") String name);

    // json
    // 注:key/value形式的參數 一定要標記參數的名稱
    @PostMapping("/user1")
    User addUser1(@RequestBody User user);

    // 刪除id
    // /user1/{id}
    // 添加@PathVariable("id") 注意了一定要把("id")添加進去 不然會報錯
    @DeleteMapping("/user1/{id}")
    void delUser1(@PathVariable("id") Integer id);

    // 通過header來傳參 中文要轉碼
    // 添加@RequestHeader("name") 注意了一定要把("name")添加進去 不然會報RequestHeader0參數錯
    @GetMapping("/user2")
    void getUserByName(@RequestHeader("name") String name) throws UnsupportedEncodingException;
}

4.3 消費者和openfeign添加依賴

		<dependency>
            <groupId>com.sundown</groupId>
            <artifactId>commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>com.sundown</groupId>
            <artifactId>hi-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

4.4 提供者實現接口

@RestController
//@RequestMapping("/test")
public class Hello1Controller implements IUserService {

    @Value("${server.port}")
    Integer port;
	
	// 重寫
    @Override
    public String hello(){
        return "hello provider:" + port;
    }


    /**
    * @Description: consumer訪問該接口 調用RestTemplate的get請求
    * @Param: [name]
    * @return: java.lang.String
    * @Author: 水面行走
    * @Date: 2020/3/4
    */
    @Override
    public String hello1(String name){
        return "hello provider: " + name;
    }

    @GetMapping("/hello2")
    public String hello2(String name){
        System.out.println(new Date() + "--->" + name);
        return "hello " + name;
    }

    // 在provider 提供2個post接口

    /**
    * @Description: key:value形式傳參
    * @Param: [user]
    * @return: model.User
    * @Author: 水面行走
    * @Date: 2020/3/7
    */
    @PostMapping("/user")
    public User addUser(User user){
        return user;
    }


    /**
     * @Description: json形式傳參
     * @Param: [user]
     * @return: model.User
     * @Author: 水面行走
     * @Date: 2020/3/7
     */
    @Override
    public User addUser1(@RequestBody User user){
        return user;
    }

    /**
    * @Description: k/v形式 因為是更新操作 put方法返回為void 所以返回值為void就行 有返回值不會報錯
    * @Param:
    * @return:
    * @Author: 水面行走
    * @Date: 2020/xx/xx
    */
    @PutMapping("/update-user")
    public void updateUser(User user){
        System.out.println("k/v形式:" + user);
    }

    /**
     * @Description: json形式 別忘了傳參添加注解 因為是更新操作 put方法返回為void 所以返回值為void就行 有返回值不會報錯
     * @Param:
     * @return:
     * @Author: 水面行走
     * @Date: 2020/xx/xx
     */
    @PutMapping("/update-user1")
    public void updateUser1(@RequestBody User user){
        System.out.println("json形式:" + user);
    }

    /**
    * @Description: k/v形式的刪除 xxx?id=1
    * @Param:
    * @return:
    * @Author: 水面行走
    * @Date: 2020/3/8
    */
    @DeleteMapping("/deluser")
    public void delUser(Integer id){
        System.out.println("k/v形式:" + id);
    }

    /**
     * @Description: PathVariable(參數放在路徑中 xxx/1)形式的刪除
     * @Param:
     * @return:
     * @Author: 水面行走
     * @Date: 2020/3/8
     */
    @Override
    public void delUser1(@PathVariable Integer id){
        System.out.println("json形式:" + id);
    }

    @Override
    public void getUserByName(@RequestHeader String name) throws UnsupportedEncodingException {
        // 解碼
        System.out.println(URLDecoder.decode(name, "utf-8"));
    }
}

4.5 openfeign配置

// 繼承接口
// 繼承特性的好處:抽出公共模塊 provider和consumer代碼一致 只需更改公共接口即可 減少出錯率
// 壞處就是耦合度變高
@FeignClient("provider")
public interface Hello1Service extends IUserService {

}
// 調用Hello1Service
// 其他這個類沒有變化 調用結果和上次是一致的
@RestController
public class Hello1Controller {
    @Autowired
    Hello1Service hello1Service;

    // 無參測試
    @GetMapping("/hello")
    public String hello(){
        return hello1Service.hello();
    }

    // 傳參
    @GetMapping("/hello1")
    public void hello1() throws UnsupportedEncodingException {
        String s = hello1Service.hello1("你好呀");
        System.out.println("hello1:" + s);
        System.out.println("---------------------------------------");
        User user = new User();
        user.setId(1);
        user.setName("小個");
        user.setNickName("薩達過");
        User user1 = hello1Service.addUser1(user);
        System.out.println("user:" + user1);
        System.out.println("---------------------------------------");
        hello1Service.delUser1(1);
        System.out.println("---------------------------------------");
        // 放在heard中的中文參數 一定要先編碼在傳遞
        hello1Service.getUserByName(URLEncoder.encode("個百分點", "utf-8"));

    }

}

4.6 小結

  • 繼承特性
  • 代碼簡潔 服務者和消費者指向同一目標 一改都改 出錯煩惱大減(既是優點也是缺點(耦合度高) 類似赤壁之戰 曹操的戰船相連)
  • 無論是否繼承 參數(無參還是傳參方式依然不變)

5 數據壓縮

開啟壓縮 節省資源 提升性能

feign:
  compression:
    request:
      # 開啟數據壓縮請求
      enabled: true
      # 壓縮數據類型
      mime-types: text/xml, application/xml, application/json
      # 數據壓縮下限 2048表示傳輸數據大於2048 才會進行數據壓縮(最小壓縮值標准)
      min-request-size: 2048
    # 開啟數據壓縮響應
    response:
      enabled: true

在這里插入圖片描述在這里插入圖片描述

6 日志配置

  • 配置日志 分4種
  1. NONE: 不開啟日志(默認)
  2. BASIC: 記錄請求方法、URL、響應狀態、執行時間
  3. HEADERS: 在BASIC基礎上 加載請求/響應頭(+2)
  4. FULL: 在HEADERS基礎上 增加body和請求元數據(+3)

6.1 在yml中配置日志級別

# 可以在yml feign.client.config.xxx 配置超時時間 攔截器等配置
logging:
  level:
    com.sundown.openfeign:  debug

6.2 兩種配置日志bean方式

  • 在applicaton類中配置bean
import feign.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableFeignClients
public class OpenfeignApplication {

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

    // 配置日志 分4種
    // 1. NONE: 不開啟日志(默認)
    // 2. BASIC: 記錄請求方法、URL、響應狀態、執行時間
    // 3. HEADERS: 在BASIC基礎上 加載請求/響應頭(+2)
    // 4. FULL: 在HEADERS基礎上 增加body和請求元數據(+3)
    // 通過bean配置
    @Bean
    Logger.Level loggerLevel(){
        return Logger.Level.FULL;
    }
}
  • Configuration中配置

正好將超時和自定義攔截器加入

@Configuration
public class FeignConfig {
     // 超時時間配置(通過Options可配置連接超時時間和讀取超時時間)
    // Options第一個參數連接超時時間(ms 默認1000*10)
    // Options第二個參數取超時時間(ms 默認1000*60)
    @Bean
    public Request.Options options(){
        return new Request.Options(3000, 8000);
    }

    /**
     * 日志級別
     * 在這里配置日志級別
     * @return
     */
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
	
	 // 配置basic認證
    // 通常: 調用有權限控制的接口 可能認證的值通過傳參/請求頭去傳認證信息
    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
        return new BasicAuthRequestInterceptor("user", "password");
    }

    // 自定義攔截器配置
    @Bean
    public FeignBasicAuthRequestInterceptor feignBasicAuthRequestInterceptor() {
        return new FeignBasicAuthRequestInterceptor();
    }
}    
// OpenFeign自定義攔截器(自定義認證方式) 實現RequestInterceptor
// 自定義一個請求攔截器 在請求之前做認證操作 在往請求頭中配置認證后的信息
public class FeignBasicAuthRequestInterceptor implements RequestInterceptor {

    // 業務邏輯
    @Override
    public void apply(RequestTemplate requestTemplate) {
        System.err.println("歡迎進入攔截器: " + requestTemplate);
    }
}
// 在openfeign service層配置
//@FeignClient(value = "provider",configuration= FeignConfig.class) 配置類-->攔截器啥的
@FeignClient(value = "provider",configuration= FeignConfig.class)
public interface Hello1Service extends IUserService {

}

啟動eureka server和provider 還有openfeign http://localhost:5000/hello1
在這里插入圖片描述
在這里插入圖片描述

7 openfeign+hystrix配合使用

降級@FeignClient+value+fallback/fallbackFactory屬性(都是在openfeign模塊中實現 且要開啟hystrix)

  hystrix:
    # 開啟hystrix
    enabled: true
  • 降級fallback屬性
// fallback屬性實現類 
@Component
@RequestMapping("/milk") // implements Hello1Service相當於調用了2次 避免重復的請求地址 不然會報錯
public class HelloServiceFallback implements Hello1Service{

    @Override
    public String hello() {
        return "error-hello";
    }

    @Override
    public String hello1(String name) {
        return "error-hello1";
    }

    @Override
    public User addUser1(User user) {
        return null;
    }

    @Override
    public void delUser1(Integer id) {

    }

    @Override
    public void getUserByName(String name) throws UnsupportedEncodingException {

    }
}
@FeignClient(value = "provider",fallback= HelloServiceFallback.class)
public interface Hello1Service extends IUserService {

}

啟動/重啟eureka server和openfeign 斷開provider http://localhost:5000/hellohttp://localhost:5000/hello1
在這里插入圖片描述
在這里插入圖片描述

  • 降級fallbackFactory屬性
@Component
public class HelloServiceFallFactory implements FallbackFactory<Hello1Service> {

    @Override
    public Hello1Service create(Throwable throwable) {
        return new Hello1Service() {
            @Override
            public String hello() {
                return "error1---------";
            }

            @Override
            public String hello1(String name) {
                return "error2---------";
            }

            @Override
            public User addUser1(User user) {
                return null;
            }

            @Override
            public void delUser1(Integer id) {

            }

            @Override
            public void getUserByName(String name) throws UnsupportedEncodingException {

            }
        };
    }
}

//@FeignClient(value = "provider",fallback= HelloServiceFallback.class) fallback和fallbackFactory不能同時使用
@FeignClient(value = "provider",fallbackFactory= HelloServiceFallFactory.class)
public interface Hello1Service extends IUserService {

}

啟動/重啟eureka server和openfeign 斷開provider http://localhost:5000/hellohttp://localhost:5000/hello1
在這里插入圖片描述
在這里插入圖片描述

8 小結

  • openfeign只需要我們提供關鍵的value就行了 自行拼接
  • openfeign環境: 依賴eureka連接依賴 web openfeign
  • yml eureka連接配置
  • 注解開啟openfeign
  • 無參 無需參數直接調用即可
  • 有參 --> 綁定參數、header傳遞 中文要解碼、多參數的話 建議@RequestParam("xxx")
  • 特性繼承 --> provider和openfeign公用一個接口 特別注意(一定要定義名字@RequestHeader("xxx") @PathVariable("xxx")。。。不然會報錯) 它的好處既是壞處
  • 數據壓縮 yml配置 開啟壓縮請求和響應 最小壓縮值標准還有壓縮類型
  • 日志配置 四種級別NONE BASIC HEADERS FULL
  • yml --> logging: level: com.sundown.openfeign: debug
  • 在bean配置 要么在application中或是在config中配置好(還可以超時配置和認證配置或自定義攔截器) 在@FeignClient中配置configuration屬性 例如@FeignClient(value = "provider",configuration= FeignConfig.class)
  • 另外 也可在yml feign.client.config.xxx 配置超時時間 攔截器等
  • openfeign+hystrix降級操作 在yml中開啟hystrix 在@FeignClient中實現fallbackFactory屬性(需要implements FallbackFactory<T>)或fallback(實現接口implements Hello1Service添加@RequestMapping("/xx")作為區分) 2種實現方式都要添加@Component注解


免責聲明!

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



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