spring 这个团队之所以能做到今天这样受欢迎,写其说是理念先进不如说是工程上的契合。spring 的产品总能给你惊喜,让你用最少的代价实现你的目标,而且是可继承的,可组合的。在 spring cloud 生态下的服务调用方案更是如此,OpenFeign 可以通过 http 协议实现 rpc 调用,而且可以单独使用,可以结合注册服务器使用,也可以自动负载,更重要的是使用非常简单。
使用你熟悉的方式,创建一个 spring boot 项目,使用使用 Idea 可以直接选择依赖项 Spring Cloud Routing -> OpenFeign
和 Spring Cloud Discovery -> Eureka Discovery Client
,会自动配置必要的依赖项。如果手动添加也没问题,请按照如下步骤:
# 假设使用 maven 管理依赖
# 我们的主角
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
# 如果使用注册服务管理服务必须
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
在主类上添加一个注解
// 在主类上参加开启 OpenFeign 注解
@SpringBootApplication
@EnableFeignClients
如果使用 Eureka 管理服务还需要做以下配置,如果单独使用则不需要。
# application.properties
#向注册中心注册的名字
spring.application.name=feign-client
server.port=8004
# 服务地址
eureka.instance.hostname=localhost
#注册中心路径,表示我们向这个注册中心注册服务,如果向多个注册中心注册,用“,”进行分隔
eureka.client.serviceUrl.defaultZone=http://${user}:${password}@127.0.0.1:8001/eureka/
# 如果没有认证可以去掉用户名和密码
#eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8001/eureka/
# 表示是否将自己注册到EurekaServer 默认true,如果只是消费者不要开启
eureka.client.register-with-eureka=true
#访问路径显示ip地址
eureka.instance.prefer-ip-address=true
// StoreClient.java
// 这是官方文档上的一个例子,简单来说首先需要用 @FeignClient("stores") 来标注一个任意的接口,参数就是 eureka 服务名称,然后在每个接口可以使用 SpringMvc 注解来写格式,注意与服务提供方的保持一致,之后就可以愉快的使用了。
@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);
}
可以编写配置类,不过最方便的还是在配置文件中,截止到现在的 spring cloud 2020.0.3
版本可以直接配置
#application.properties
# 连接超时时间
feign.client.config.default.connect-timeout=1000
# 数据读取时间
feign.client.config.default.read-timeout=5000
在调用 feign 时主要面向内部接口,所以权限验证与用户访问的认证与授权有所区分,一般会更简单不需要太复杂的粒度控制,所以这里统一配置在 header 中。配置 header 值有多种不同的方式。
//FeignConfig.java
@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor requestInterceptor() {
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate template) {
template.header("Auth-Token", "your_token");
}
};
}
}
@RequestMapping
注解是 Spring MVC 系列注解,直接在接口上配置 header 属性即可,不过需要注意语法,需要使用等号连接键与值。
// DateService.java
@FeignClient("provider-service")
public interface DateService {
@GetMapping(value = "/test",headers = {"token=${app.token}"})
public String test();
}
这里的 app.token 值可以在配置文件中,当然直接在代码里写魔术字符串也可以。
# application.properties
app.token: appToken
@RequestHeader
注解也是 Spring MVC 系列的,不过需要加在方法参数中,适合于需要调用接口是由代码输入的参数。
// DateService.java
@FeignClient("provider-service")
public interface DateService {
@GetMapping(value = "/test")
public String test(@RequestHeader("token") String token);
}
这样在调用 test 这个接口时就要动态的传入 token 的值,对于验证来说并不实用。
这是 feign 自带注解,默认情况下是不生效的,要使用需要首先打开 feign 自带的注解。
// 在配置类中直接配置
@Bean
public Contract feignContract() {
return new feign.Contract.Default();
}
之后在接口代码中直接使用
// DateService.java
//configuration 可以更详细的控制来源于哪个配置类
@FeignClient(name="provider-service",configuration = FeignConfig.class)
public interface DateService {
@RequestLine("GET /test")
@Headers({"token: {token}"})
public String test();
}
因为我们主要在 spring 全家桶中使用,所以不推荐这种方式。
仍然是 fiegn 自带注解,开启方式与 @Headers 注解相同,使用上需要加到方法参数中与 @RequestHeader
类似。
// DateService.java
//configuration 可以更详细的控制来源于哪个配置类
@FeignClient(name="provider-service",configuration = FeignConfig.class)
public interface DateService {
@RequestLine("GET /test")
public String test(@HeaderMap HttpHeaders headers);
}
仍然不推荐这种方式,只是做个备注。