前言
SpringCloud基于Eureka 做注册中心,Eureka的客户端提供服务。
这样的结构实现了服务的注册和发现,对!微服务的注册,并被发现,很优秀的结构。
但是,Eureka 直接调用客户端的时候使用 RestTemplate ,然后请求对象,看起来不那么优雅,不是不是基于 接口的了,给程序员的感觉就是基于 Rest服务的调用,不好使啊。
因此就有了Feign 。 这东西将服务的地址调用写成一个接口,再加上一些注解,然后就可以使用了。
看起来就好像 JDBCTemplate 和 MyBatis的区别。
项目基础
首先,这个项目是基于之前项目的基础上做出的,其父项目中引入了若干依赖。
父项目说明:
1 父项目是基于 spring-boot的
2 父项目的 dependencyManagement 有 以下关键依赖:
spring-cloud-dependencies
spring-boot-dependencies
具体的父项目可参见上一篇文章《SpringCloud Eureka测试项目--一个最简单的订单获取功能》
创建项目
创建SpringBoot项目,
项目命名为: test-springcloud-consumer-feign-order8003
项目结构如下:
pom.xml
该文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.pingbu</groupId>
<artifactId>test-springcloud-consumer-feign-order8003</artifactId>
<version>1.0.0</version>
<parent>
<groupId>com.pingbu</groupId>
<artifactId>test-springcloud</artifactId>
<version>1.0.0</version>
</parent>
<dependencies>
<!-- eureka client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- spring boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>test-springcloud-consumer-fergn-order8003</finalName>
</build>
</project>
可以看到,该项目关键的依赖是以下两个:
spring-cloud-starter-netflix-eureka-client :Feign 需要 Ribbon的负载均衡,也需要 Eureka的客户端,所以需要引入这个依赖。
spring-cloud-starter-openfeign: 这个是 引入了 Feigin 依赖,不需要多说。
application.yml
直接上代码,不多说
#eureka的端口号
server:
port: 8003
spring:
application:
name: consumer-feign-order
eureka:
client:
# 表示将自己注册进Eureka Server默认为true
register-with-eureka: false
# 是否从Eureka Server抓去已有的注册信息,默认是true
fetch-registry: true
# 设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
service-url:
defaultZone: http://127.0.0.1:8761/eureka
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: basic
这个确实不需要多说。
SpringBoot主启动类
package com.wanshi.consumer.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class FeignOrderMain8003 {
public static void main(String[] args) {
SpringApplication.run(FeignOrderMain8003.class, args);
}
}
注意看有两个注解
@EnableFeignClients 支持了 Feign客户端
@EnableDiscoveryClient 支持了发现服务的能力
一个简单的Feign 接口
package com.wanshi.consumer.order.feign;
import com.wanshi.consumer.order.bean.Order;
import com.wanshi.consumer.order.bean.ResultBean;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value="provider-order")
public interface OrderFeign {
@GetMapping(value="/provider/order/get/{id}")
ResultBean<Order> getOrder( @PathVariable("id") Long id) ;
}
@FeignClient的 value属性,是 Eureka 服务的名字,对应的是 Eureka 注册的服务名,如下图:
整个接口看起来,就是对应的 服务的 RestFul 的Api定义,看看Eureka 服务提供者的代码是如何定义的,代码如下图:
@GetMapping("/get/{id}")
public ResultBean<Order> getOrderById(@PathVariable("id") Long id) {
Order result = new Order();
result.setId(1L);
result.setSerial("测试序列,算是行了:"+ new Date());
log.info("====== 查询结果:" + result);
if(result != null) {
return new ResultBean(0, "查询成功,服务端口:" + serverPort, result);
}else {
return new ResultBean(500, "查询失败");
}
}
这是服务提供者的代码。
到这里,整体代码就完成了,接下来就是要调用接口了。
调用Feign接口
调用代码就简单了,直接上代码,不解释。
package com.wanshi.consumer.order.controller;
import com.wanshi.consumer.order.bean.Order;
import com.wanshi.consumer.order.bean.ResultBean;
import com.wanshi.consumer.order.feign.OrderFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@Slf4j
public class OrderController {
@Autowired
private OrderFeign orderFeign;
@GetMapping("/consumer/order/get/{id}")
public ResultBean<Order> getOrder(@PathVariable("id") Long id){
ResultBean<Order> rb = orderFeign.getOrder(id);
return rb;
}
}