3.【Spring Cloud Alibaba】聲明式HTTP客戶端-Feign

使用Feign實現遠程HTTP調用

什麼是Feign

  • Feign是Netflix開源的聲明式HTTP客戶端
  • GitHub地址:https://github.com/openfeign/feign
實現
pom.xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>
@MapperScan("com.itmuch.contentcenter.dao")
@SpringBootApplication
@EnableFeignClients// (defaultConfiguration = GlobalFeignConfiguration.class)
@EnableBinding({Source.class})
public class ContentCenterApplication {
@FeignClient(name = "user-center")
public interface UserCenterFeignClient {
    /**
     * http://user-center/users/{id}
     *
     * @param id
     * @return
     */
    @GetMapping("/users/{id}")
    UserDTO findById(@PathVariable Integer id);
}
private final UserCenterFeignClient userCenterFeignClient;

// 1. 代碼不可讀
// 2. 複雜的url難以維護:https://user-center/s?ie={ie}&f={f}&rsv_bp=1&rsv_idx=1&tn=baidu&wd=a&rsv_pq=c86459bd002cfbaa&rsv_t=edb19hb%2BvO%2BTySu8dtmbl%2F9dCK%2FIgdyUX%2BxuFYuE0G08aHH5FkeP3n3BXxw&rqlang=cn&rsv_enter=1&rsv_sug3=1&rsv_sug2=0&inputT=611&rsv_sug4=611
// 3. 難以相應需求的變化,變化很沒有幸福感
// 4. 編程體驗不統一
UserDTO userDTO = this.userCenterFeignClient.findById(userId);

Feign的組成

image

細粒度配置自定義

  • Java代碼方式
  • 配置屬性方法

指定日誌級別

image

Java代碼方式

UserCenterFeignClient
@FeignClient(name = "user-center", configuration = GlobalFeignConfiguration.class)
public interface UserCenterFeignClient {
    /**
     * http://user-center/users/{id}
     *
     * @param id
     * @return
     */
    @GetMapping("/users/{id}")
    UserDTO findById(@PathVariable Integer id);
}
GlobalFeignConfiguration
/**
 * feign的配置類
 * 這個類別加@Configuration註解了,不然必須挪到@ComponentScan能掃描的包之外
 */
public class GlobalFeignConfiguration {
    @Bean
    public Logger.Level level(){
        // 讓feign打印全部請求的細節
        return Logger.Level.FULL;
    }
}
application.yml
logging:
  level:
    com.itmuch.contentcenter.feignclient.UserCenterFeignClient: debug

配置屬性方法

image

image

全局配置

  • Java代碼方式
  • 配置屬性方式

Java代碼方式

ContentCenterApplication

EnableFeignClientsjava

// 掃描mybatis哪些包裏面的接口
@MapperScan("com.itmuch.contentcenter.dao")
@SpringBootApplication
@EnableFeignClients(defaultConfiguration = GlobalFeignConfiguration.class)
@EnableBinding({Source.class})
public class ContentCenterApplication {
/**
 * feign的配置類
 * 這個類別加@Configuration註解了,不然必須挪到@ComponentScan能掃描的包之外
 */
public class GlobalFeignConfiguration {
    @Bean
    public Logger.Level level(){
        // 讓feign打印全部請求的細節
        return Logger.Level.FULL;
    }
}

配置屬性方式

// 掃描mybatis哪些包裏面的接口
@MapperScan("com.itmuch.contentcenter.dao")
@SpringBootApplication
@EnableFeignClients// (defaultConfiguration = GlobalFeignConfiguration.class)
@EnableBinding({Source.class})
public class ContentCenterApplication {

image

支持的配置項

Java代碼方式支持的配置項

image

配置屬性方式支持的配置項

image

配置最佳實踐

Ribbon配置 VS Feign配置

image

Feign代碼方式 vs 屬性方式

image

最佳實踐

image

Feign的繼承

關於繼承的爭議

  • 官方觀點:官方不推薦使用
  • 業界觀點:不少公司使用
  • 我的觀點:權衡利弊

多參數請求構造

Get請求

TestController
@GetMapping("test-get")
public UserDTO query(UserDTO userDTO) {
    return testUserCenterFeignClient.query(userDTO);
}

方法1

TestUserCenterFeignClient
import com.itmuch.contentcenter.domain.dto.user.UserDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient(name = "user-center")
public interface TestUserCenterFeignClient {
    @GetMapping("/q")
    UserDTO query(@SpringQueryMap UserDTO userDTO);
}

方法二

@FeignClient(name = "user-center")
public interface UserFeignClient {
  @RequestMapping(value = "/q", method = RequestMethod.GET)
  public UserDTO query(@RequestParam("id") Long id, @RequestParam("username") String username);
}

POST請求包含多個參數

下面來討論如何使用Feign構造包含多個參數的POST請求。假設服務提供者的Controller是這樣編寫的:git

@RestController
public class UserController {
  @PostMapping("/post")
  public User post(@RequestBody User user) {
    ...
  }
}
咱們要如何使用Feign去請求呢?答案很是簡單,示例:
@FeignClient(name = "microservice-provider-user")
public interface UserFeignClient {
  @RequestMapping(value = "/post", method = RequestMethod.POST)
  public User post(@RequestBody User user);
}

Feign脫離Ribbon的使用

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

// 脫離ribbon的使用
@FeignClient(name = "baidu", url = "http://www.baidu.com")
public interface TestBaiduFeignClient {
    @GetMapping("")
    String index();
}

RestTemplate vs Feign

image

Feign性能優化

  • 鏈接池[提高15%左右]
feign:
  sentinel:

    # 爲feign整合sentinel
    enabled: true
  client:
    config:
      # 全局配置
      default:
        loggerLevel: full
        requestInterceptors:
          - com.itmuch.contentcenter.feignclient.interceptor.TokenRelayRequestIntecepor
  httpclient:
    # 讓feign使用apache httpclient作請求;而不是默認的urlconnection
    enabled: true
    # feign的最大鏈接數
    max-connections: 200
    # feign單個路徑的最大鏈接數
    max-connections-per-route: 50
目前,在Spring cloud中服務之間經過restful方式調用有兩種方式
  • restTemplate+Ribbon
  • feign

從實踐上看,採用feign的方式更優雅(feign內部也使用了ribbon作負載均衡)。github

相關文章
相關標籤/搜索