@FeignClient常用屬性
- 2021 年 8 月 3 日
- 筆記
- SpringCloud
@FeignClient(name = "gateway-test", value = "gateway-test", url = "localhost:9997", fallbackFactory = FallbackFactory.class, contextId = "GatewayClient")
name/value: 服務名稱
//查看源碼可知: 兩個屬性等價
public @interface FeignClient {
@AliasFor("value")
String name() default "";
@AliasFor("value")
String name() default "";
}
//查看源碼可知: 兩個屬性至少要配置一個
FeignClientsRegistrar {
private String getClientName(Map<String, Object> client) {
if (client == null) {
return null;
}
String value = (String) client.get("contextId");
if (!StringUtils.hasText(value)) {
value = (String) client.get("value");
}
if (!StringUtils.hasText(value)) {
value = (String) client.get("name");
}
if (!StringUtils.hasText(value)) {
value = (String) client.get("serviceId");
}
if (StringUtils.hasText(value)) {
return value;
}
throw new IllegalStateException("Either 'name' or 'value' must be provided in @"
+ FeignClient.class.getSimpleName());
}
}
url: 請求地址, 沒配置的話, 會把name/value的屬性值當成服務名進行調用, 配置的話則使用url的值
示例:
Product服務: 服提供者, 服務名product-client, 存在一個介面/product/test, 返回”test”字元串
User服務: 調用方, 服務名user-client, 存在一個介面/user/test, 調用product服務的test介面
//配置url方式,請求地址為url的地址
@FeignClient(name = "product-client", url = "localhost:9997")
public interface ProductClient {
/**
* ..
* @return .
*/
@GetMapping("/product/test")
String test();
}
@RequestMapping("/user")
public class UserController {
@Resource
private ProductClient client;
@GetMapping("/test")
public String test() {
return client.test();
}
}
//訪問//localhost:8200/user/test報錯:
//Connection refused: connect executing GET //localhost:9997/product/test with root cause
//說明配置了url屬性後,確實是根據url的值作為請求地址進行調用
//使用服務名調用方式
@FeignClient(name = "product-client")
public interface ProductClient {
/**
* ..
* @return .
*/
@GetMapping("/product/test")
String test();
}
//調用成功,後台能看到獲取註冊中心(nacos)的數據解析獲取真實的url地址的日誌
//用一個不存在的服務名再驗證一下
@FeignClient(name = "product-client123")
public interface ProductClient {
/**
* ..
* @return .
*/
@GetMapping("/product/test")
String test();
}
//報錯資訊:
com.netflix.client.ClientException: Load balancer does not have available server for client: product-client123
fallbackFactory: 獲取異常資訊
示例:
user服務開啟hystrix
feign:
hystrix:
enabled: true
//user服務添加fallback,用於在調用服務出現錯誤時,返回自定義資訊
@Component
public class ProductClientFallback implements ProductClient{
@Override
public String test() {
return "error";
}
}
//user服務添加fallbackFactory,用戶在調用服務出現錯誤時,獲取錯誤資訊
@Component
public class ProductClientFallbackFactory implements FallbackFactory<ProductClient> {
@Resource
ProductClientFallback fallback;
@Override
public ProductClient create(Throwable cause) {
System.out.println("cause.getMessage() = " + cause.getMessage());
return fallback;
}
}
//product服務修改/product/test介面,模擬出現異常
@RestController
@RequestMapping("/product")
public class ProductController {
@GetMapping("/test")
public String test() throws Exception {
throw new Exception("test Exception");
}
}
Postman訪問 //localhost:8200/user/test ,成功返回自定義的異常資訊
查看服務調用方User的日誌, 成功列印出錯誤日誌
message資訊為空的話,配置一下Product服務:
server:
error:
include-message: ALWAYS
具體原因請查看 部落格, 也可以通過使用@ControllerAdvice來解決
contextId: 別名
假設一個User服務有兩個FeignClient,都需要調用Product服務, 因為name屬性值一樣,所以需要通過配置contextId來區分,否則啟動項目時會報錯
@FeignClient(name = "product-client", fallbackFactory = ProductClientFallbackFactory.class, contextId = "ProductClientCopy")
public interface ProductClientCopy {
/**
* ..
* @return .
*/
@GetMapping("/product/testCopy")
String test();
}
@FeignClient(name = "product-client", fallbackFactory = ProductClientFallbackFactory.class, contextId = "ProductClient")
public interface ProductClient {
/**
* ..
* @return .
*/
@GetMapping("/product/testCopy")
String test();
}