0%

Spring Boot整合feign

前言

feign 是一个非常好用的 http 客户端工具,它是一种声明式的 http 客户端,只需要声明好接口即可调用,不需要关注底层的请求细节。
通常情况下都是在 Spring Cloud 项目中使用,这里我把它单独整合到 Spring Boot 中,用来替代RestTemplate,提高项目可维护性。

整合 feign

添加依赖

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-spring4</artifactId>
<version>11.0</version>
</dependency>

<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-gson</artifactId>
<version>11.0</version>
</dependency>

声明接口

通过feign-spring4这个依赖,可以支持使用 SpringMVC 的注解来声明接口,示例:

1
2
3
4
5
6
7
8
9
10
public interface UserFeign {
@PostMapping("/users")
Result<Void> add(@RequestBody UserAddDTO dto);

@GetMapping("/users")
Result<UserVO> find(@RequestParam("name") String name);

@GetMapping("/test/404")
Result<UserVO> error404();
}

可以看到代码和controller方法声明基本一致,非常的清晰易懂。

配置 feign

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
@Configuration
public class FeignConfig {

@Autowired
private Environment environment;
@Autowired
private ObjectMapper objectMapper;

// 构造user服务的feign客户端
@Bean
public UserFeign userFeign() {
// 这里是因为方便演示,直接调用自身服务的接口
String userServer = "http://127.0.0.1:" + environment.getProperty("server.port");
return Feign.builder()
.client(new FeignClient(null, null))
.encoder(new GsonEncoder())
.decoder(new GsonDecoder())
.contract(new SpringContract()) // 这里很关键,要使用SpringMVC注解必须配置这个contract
.retryer(Retryer.NEVER_RETRY)
.requestInterceptor(template -> {
template.header("Content-Type", "application/json");
})
.options(new Request.Options(10, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true))
.target(UserFeign.class, userServer);
}

public class FeignClient extends Client.Default {

public FeignClient(final SSLSocketFactory sslContextFactory, final HostnameVerifier hostnameVerifier) {
super(sslContextFactory, hostnameVerifier);
}

// 重写execute方法,在接口请求失败时抛出异常
@Override
public Response execute(final Request request, final Request.Options options) throws IOException {
Response response = super.execute(request, options);
if (response.status() == 200) {
String body = Util.toString(response.body().asReader(Charset.forName("UTF-8")));
Result result = null;
try {
result = objectMapper.readValue(body, Result.class);
} catch (Exception e) {

}
if (result == null || result.getCode() != 200) {
throw new FeignException.FeignServerException(200, "http request fail", request, body.getBytes());
}
// 注意这里因为把响应流读完了,所以要重新把body赋值,不然后续后报错
response = response.toBuilder()
.body(body.getBytes())
.build();
}
return response;
}
}
}

配置好了之后,后续有新的接口只要去接口上声明新的方法就可以了,维护起来也是非常的方便。

调用接口

前面已经将UserFeign注册在 spring 容器中了,使用的时候只需要注入到类中,然后和调用本地方法一样使用就行了,示例:

1
2
3
4
5
6
7
8
@Autowired
private UserFeign userFeign;

public void query() throws Exception {
// 调用用户服务查找接口
Result<UserVO> result = userFeign.find("java");
System.out.println(result.toString());
}

附录

本文完整代码放在github


我是MonkeyWie,欢迎扫码👇👇关注!不定期在公众号中分享JAVAGolang前端dockerk8s等干货知识。

如果觉得本文对您有帮助,可以请我喝一杯咖啡☕