spring-cloud 里面,各个服务之间的通信,通常是通过注册中心的服务发现实现的,我待过的公司,有两种实现方案:
1、使用httpclient 调用网关,微服务之间的通信都通过网关来交互;(有点像以前的企业服务总线)
2、使用spring的openfeign框架,微服务直接直接通信;
本文主要介绍如何在spring-cloud里面使用openfeign进行远程调用。
参考文档:Spring Cloud OpenFeign 中文文档
启用feign
自己根据项目情况添加依赖包
<dependencies>
<!-- 其他依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 其他依赖 -->
</dependencies>
Spring Boot应用程序
@SpringBootApplication
@EnableFeignClients
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
StoreClient.java
@FeignClient("stores")
public interface StoreClient {
@RequestMapping(method = RequestMethod.GET, value = "/stores")
List<Store> getStores();
@RequestMapping(method = RequestMethod.GET, value = "/stores")
Page<Store> getStores(Pageable pageable);
@RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
Store update(@PathVariable("storeId") Long storeId, Store store);
@RequestMapping(method = RequestMethod.DELETE, value = "/stores/{storeId:\\d+}")
void delete(@PathVariable Long storeId);
}
feign自定义配置
@FeignClient(name = "stores", configuration = FooConfiguration.class)
public interface StoreClient {
//..
}
如上,我们可以自定义自己的 FooConfiguration 类来重写一些远程调用时的默认配置。
@Slf4j
@Configuration
public class FeignConfig implements FeignFormatterRegistrar, RequestInterceptor {
@Bean
public Feign.Builder defaultFeignBuilder() {
return Feign.builder().client(new OkHttpClient()).options(new Request.Options(5 * 1000, 5 * 1000, false));
}
@Bean
public Decoder feginDecoder(ObjectProvider<HttpMessageConverters> messageConverters) {
return new OptionalDecoder(new ResponseEntityDecoder(new FeignDecoder(messageConverters)));
}
@Override
public void registerFormatters(FormatterRegistry registry) {
/*
* 格式化处理Feign接口上的Date类型参数
*/
registry.addFormatter(new Formatter<Date>() {
private ThreadLocal<SimpleDateFormat> sdfThreadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA));
@Override
public String print(Date object, Locale locale) {
if (object == null) {
return StringUtils.EMPTY;
}
return sdfThreadLocal.get().format(object);
}
@Override
public Date parse(String text, Locale locale) throws ParseException {
if (StringUtils.isBlank(text)) {
return null;
}
return sdfThreadLocal.get().parse(text);
}
});
}
// feign拦截器,主要用于在请求头中携带安全信息
@Override
public void apply(RequestTemplate template) {
try {
String url = template.url();
// 如果是请求的是特定接口,则携带ecpips需要的安全码
if (url.startsWith("/xxx/inner/") || url.startsWith("/aaaa/")) {
template.header("sc", MD5Util.md5Encode(PropertyConfig.getConfigValue("securityNo")));
}
} catch (Exception e) {
log.error("header sc出错!");
}
}
}
以上我们就能愉快的开始使用feign了,其他额外的功能,我们可以在此基础上增加。