1. Feign が RestTemplate を置き換える
RestTemplate の例
String url = "http://userservice/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
RestTemplate の欠点:
- コードの可読性は低く、コーディング エクスペリエンスは均一ではありません。
- 複雑なパラメータを持つ URL は保守が困難です
(1) フェギンの概念
Fegin は宣言型 http クライアントであり、公式 Web サイト: https://github.com/OpenFeign/feignは、http リクエストの送信を簡素化するために
使用されます。
(2) Feginの基本的な使い方
1. 依存関係を導入する
<dependency>
<groupId>org.springframework.cloud</gourpId>
<artifactId>spring.cloud.starter.openfeign</artifactId>
</dependency>
2. 起動クラスにアノテーションを追加して Fegin を起動します
@EnableFeignClients //启动Fegin客户端
@MapperScan("xxx.xxx.xxx.mapper")
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
}
3. Fegin クライアントを定義する
@FeignClient("userservice")
public interface UserClient {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
これは主に SpringMVC アノテーションに基づいて、次のようなリモート呼び出し情報を宣言します。
- サービス名: ユーザーサービス
- リクエストメソッド:GET
- リクエストパス: /user/{id}
- リクエストパラメータ: 長い ID
- 戻り値: ユーザー
3.サービスはFeignクライアントを使用します
@Service
public class OrderService {
@Autowired
private OrderMapper mapper;
@Autowired
private UserClient userClient;
public Order queryOrderById(Long orderId) {
Order order = orderMapper.findById(orderId);
User user = userClient.getById(order.getUserId());
order.setUser(user);
return order;
}
}
2. カスタム構成
変更可能な構成テーブル
タイプ | 効果 | 説明する |
---|---|---|
fegin.Logger.Level | ログレベルの変更(共通) |
4 つのレベルが含まれます: NONE、BASIC、HEADERS、FULL
|
fegin.コーデック.デコーダ | 応答結果パーサー |
JSON の解析など、http リモート呼び出しの結果を分析します。
|
fegin.コーデック.エンコーダ | リクエストパラメータのエンコード形式 |
リクエストパラメータをエンコードして http リクエストの送信を容易にする
|
fegin.Contract | サポートされている注釈形式 |
デフォルトは SpringMVC アノテーションです
|
嬉しいリトライアー | 失敗時の再試行メカニズム |
リクエスト失敗時の再試行メカニズム。デフォルトは「いいえ」ですが、リボンの再試行が使用されます。
|
(1) 構成変更の実現
方法 1: 設定ファイルによる方法
fegin:
client:
config:
default: #设置全局配置,若是直接写服务名称,则是针对某一个微服务的配置
loggerLevel: FULL #全日志级别
方法 2: Feign 構成をカスタマイズする
FeignClientConfiguration 構成クラス
//配置注解选择一种即可
//全局配置:在启动类上加上该注解
//@EnableFeginClients(defaultConfiguration = FeignClientConfiguration.class)
//局部配置:具体Client类上加该注解
//@FeginClient(value = "userservice", configuration = FeignClientConfiguration.class)
public class FeignClientConfiguration {
@Bean
public Logger.Level.feignLogLevel(){
return Logger.Level.BASIC;
}
}
3. 最適化を装う
(1) Feign の基礎となるクライアント実装 (3 つのモード)
- URLConnection: デフォルトで実装され、接続プーリングをサポートしません (JDK には付属しています)
- Apache HttpClient: 接続プーリングをサポート
- OKHttp: 接続プールのサポート
(2) Feginのパフォーマンスの最適化
- 1. URLConnection の代わりに接続プールを使用する
- 2. ログ レベル。BASIC または NONE として構成することが望ましい
(3) URLConnectionの代わりに接続プールを設定する
1. HttpClient 依存関係を導入する
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
2. 接続プールを構成する
feign:
client:
config:
default: #全局配置
loggerLevel: BASIC #日志级别,打印最基本的请求和响应信息
httpclient:
enabled: true #开启feign对httpclient的支持
max-connections: 200 #最大连接数
max-connections-per-route: 50 #每个路径的最大连接数
4 番目に、FeignClient の実装経験を実際に要約しました。
(1) 方法 1 (継承):コンシューマの FeignClient とプロバイダのコントローラの統一親インターフェイスを標準で定義します。
1. 次のことを認識します。
親インターフェース
public interface UserAPI{
@GetMapping("/user/{
id})
User findById(@PathVariable("id") Long id);
}
UserClient は親インターフェイスを継承します
@FeignClient(value = "userservice")
public interface UserClient extends UserAPI{
}
UserController は親インターフェイスを実装します
@RestController
public class UserController implements UserAPI {
public User findById(@PathVariable("id") Long id) {
//...实现业务
}
}
2. この方法の欠点
- 密結合されたサービス
- 親インターフェイスのパラメータリストのマッピングは継承されません
(2) 方法 2 (抽出): FeignClient を独立したモジュールとして抽出し、インターフェイス関連の POJO とデフォルトの Feign 構成をすべてのコンシューマーが使用できるようにこのモジュールに配置します。
1. 実現する
(1) モジュールの作成
feign-api という名前のモジュールを作成し、feign のスターター依存関係を導入します。
(2) モジュール関数クラスの抽出
抽出する必要があるクラスを feign-api モジュールに置きます。
(3) feign-apiを利用する
コンシューマ サービスに feign-API 依存関係が導入される
(4) 消費者サービスインポート偽API
2. 考えられる問題
UserClient は Spring によって Bean オブジェクトとして作成されません
-
理由: FeginClient はコンシューマー サービス パッケージのスキャンの範囲外であるため、インスタンスは導入されません。
-
解決:
方法 1: パッケージ内に配置する FeignClient を指定する
@EnableFeignClients(basePackages = "xxx.xxx.xxx.clients")
方法 2: FeignClient バイトコードを指定する
@EnableFeignClients(clients= {
UserClient.class})