前言
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;
@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()) .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); }
@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()); } 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。