GitHub Open Feign 使用总结

原文地址

公司项目目前使用 SOA 架构(Service-oriented architecture:服务导向架构),每个服务作为一个单体对外提供接口,服务之间使用 GitHub OpenFeign 调用接口。

服务提供者正常提供接口,把需要暴露的接口封装为一个 client jar 包,服务调用者正常引入 jar 包,直接调用 jar 方法即可调用服务提供者接口。此文相关代码示例

Provider Api

@RestController
public class UserController {

@PostMapping("/signin")
public ApiResponse<Void> doSignin(@RequestParam("username") String username, @RequestParam("password") String password) {
if (username.equals("") && password.equals("")) {
return ApiResponse.fail(500);
}
return ApiResponse.success();
}
}

Provider Client

ProviderClientBuilder

@Configuration
public class ProviderClientBuilder {
@Value("${provider.domain}")
public String providerDomain;
@Value("${provider.socketTimeout:60000}")
public int socketTimeout;
@Value("${provider.connectTimeout:10000}")
public int connectTimeout;

@Bean
public UserApi buildProviderApi() {
Preconditions.checkArgument(StringUtils.isNotBlank(providerDomain));
return Feign.builder()
.decoder(new GsonDecoder())
.encoder(new FormEncoder())
.logger(new Slf4jLogger(UserApi.class))
.retryer(Retryer.NEVER_RETRY)
.logLevel(Logger.Level.FULL)
.client(new AccessTraceHttpClient(httpClient(), requestConfig()))
.target(UserApi.class, providerDomain);
}
...
}

UserApi

@Headers("Content-Type: application/x-www-form-urlencoded") // 请求的编码格式为 application/x-www-form-urlencoded
public interface UserApi {
@RequestLine("POST /signin")
public ApiResponse<Void> signin(@Param("username") String username, @Param("password") String password);

@RequestLine("GET /status/version")
public ApiResponse<String> statusVersion();
}

Consumer Api

引入依赖

<dependency>
<groupId>wang.depp</groupId>
<artifactId>provider-client</artifactId>
<version>1.0.6</version>
</dependency>
@RestController
public class HomeController {
@Autowired
private UserApi userApi;

@PostMapping("/signin")
public ApiResponse<Void> signin() {
return userApi.signin("admin","admin");
}
}
@ComponentScan(basePackages = "wang.depp")
@SpringBootApplication
public class ConsumerApiApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApiApplication.class, args);
}
}

ProviderClientBuilder 为配置类,当 Provider 和 Consumer 的 package 路径不同时,需要指定包扫描路径,使引入包配置类在容器启动时就能加载到容器。

application.properties 配置提供方 domain。可通过配置文件为不同环境配置不同的服务提供者 domain

server.port=8888
provider.demain=http://localhost:8080/ # 完整书写,不能是 localhost:8080
provider.socketTimeout=60000
provider.connectTimeout=10000

踩过的坑

1、java.lang.IllegalArgumentException: target values must be absolute.

  • 读取配置文件的配置出了问题,如:provider-api 的 domain 没写全;或命名错误,没有读取到

2、Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $

  • **Api 和 Controller 方法的返回值类型对不上,比如:Provider Api 的拦截器给 ApiResponse 又包装了一层 ApiResponse

3、接收参数不能直接为 Date

  • 因为使用 application/x-www-form-urlencoded 传输时将参数使用 && 链接到一起,此时可以认为是 String 类型,Date 类型不能接受 String 类型参数
Depp Wang wechat
个人公众号