在上一章中,讲解了如何使用RestTemplate来消费服务,如何结合Ribbon在消费服务时做负载均衡。本章将全面讲解Feign,包括如何使用Reign来远程调试其他服务、FeignClient的各项详细配置,并从源码的角度深入讲解Feign。
Feign受Retrofit、JAXRS-2.0和WebSocket影响,采用了声明式API接口的风格,将Java Http客户端绑定到它内部。Feign的首要目标是将Java Http客户端调用过程变得简单。Feign的源码地址:https://github.com/OpenFeign/feign。
本章的案例基于上一章的案例,在6.3节的工程基础之上进行改造。本节的案例讲解了如何使用Feign进行远程调用。
新建一个Spring Boot的Module工程,取名为eureka-feign-client。首先,在工程的pom文件中加入相关的依赖,包括继承了主Maven工程的pom文件、Feign的起步依赖spring-cloud-starter-feig、Eureka Client的起步依赖spring-cloud-starter-eureka、Web功能的起步依赖spring-boot-starter-web,以及Spring Boot测试的起步依赖spring-boot-starter-test,代码如下:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
引入这些依赖之后,在工程的配置文件application.yml做相关的配置,包括配置程序名为eureka-feign-client,端口号为8765,服务注册地址为http://localhost:8761/eureka/,代码如下:
spring:
application:
name: eureka-feign-client
server:
port: 8765
eureka:
client:
service-url:
dufaultZone: http://localhost:8761/eureka/
在程序的启动类EurekaFeignClientApplication加上注解@EnableEurekaClient开启EurekaClient的功能,通过注解@EnableFeignClients开启Feign Client的功能。代码如下:
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class EurekaFeignClientApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaFeignClientApplication.class, args);
}
}
通过以上3个步骤,该程序就具备了Feign的功能,现在来实现一个简单的Feign Client。新建一个EurekaClientFeign的接口,在接口上加@FeignClient注解来声明一个Feign Client,其中value为远程调用其他服务的服务名,FeignConfig。class为Feign Client的配置类。在EurekaClientFeign的接口内部有一个sayHiFromClientEureka()方法,该方法通过Feign来调用eureka-client服务的“/hi”的API接口,代码如下:
@FeignClient(value = "eureka-client",configuration = FeignConfig.class)
public interface EurekaClientFeign {
@GetMapping(value = "/hi")
String sayHiFromClientEureka(@RequestParam(value = "name")String name);
}
在FeignConfig类加上@Configuration注解,表明该类是一个配置类,并注入一个BeanName为feignRetryer的Retryer的Bean。注入该Bean之后,Feign在远程调用失败后会进行重试。代码如下:
public class FeignConfig {
@Bean
public Retryer feignRetryer(){
return new Retryer.Default(100,SECONDS.toMillis(1),5);
}
}
在Service层的HiService类注入EurekaClientFeign的Bean,通过EurekaClientFeign去调用sayHiFromClientEureka()方法,其代码如下:
@Service
public class HiService {
@Autowired
EurekaClientFeign eurekaClientFeign;
public String sayHi(String name){
return eurekaClientFeign.sayHiFromClientEureka(name);
}
}
在HiController上加上@RestController注解,开启RestController的功能,写一个API接口“/hi”,在该接口调用了HiService的sayHi()方法。HiService通过EurekaClientFeign远程调用eureka-client服务的API接口“/hi”。代码如下
@RestController
public class HiController {
@Autowired
HiService hiService;
@GetMapping("/hi")
public String sayHi(@RequestParam(defaultValue = "rock",required = false)String name){
return hiService.sayHi(name);
}
}
启动eureka-server工程,端口号为8761;启动两个eureka-client工程的实例,端口号分别为8762和8763;启动eureka-feign-client工程,端口号为8765。
在浏览器上多次访问http://localhost:8765/hi,浏览器会轮流显示以下内容:
hi rock,i am from port:8762
hi rock,i am from port:8763
由些可见,Feign Client远程调用了eureka-client服务(存在端口为8762和8763的两个实例)的"/hi"API接口,Feign Client有负载均衡的能力。
查看起步依赖sping-cloud-starter-feign的pom文件,可以看到该起步依赖默认引入了Ribbon和Hystrix的依赖,即负载均衡和熔断器的依赖。关于Hystrix将在下一章讲解。spring-cloud-starter-feign的pom文件的代码如下:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-slf4j</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-archaius</artifactId>
</dependency>
</dependencies>