该系列项目整体介绍及源代码请参照前面写的一篇文章【springcloud学习(dalston.sr1)】项目整体介绍(含源代码)(一)
(一)Feign的理解
前面文章【springcloud学习(dalston.sr1)】服务消费者通过restTemplate来访问服务提供者(含源代码)(五)里提到了通过restTemplate进行接口调用,这里有个不好的地方,就是不同的接口,都需要手写restTemplate来调用,且需要自己实现返回结果的处理,自己转换json数据到实体类,且需要手工指定不同的请求类型(post、get、delete、put),极为不方便。
我们知道像mybaitis,我们直接声明一个DAO接口,结合mapper.xml文件,就能访问数据库了。那么访问http的URL,能否也声明一个接口,就能实现http请求的访问呢?答案是肯定的,feign就可以用来实现这个需求。
(二)通过Feign来实现http请求的访问
(1)首先我们在microservicecloud-api项目中,新建一个接口GoodsClientService,注意这个接口我们加了注解FeignClient,并且这个注解里,我们指定了服务名称为MICROSERVICECLOUD-GOODS。然后在其getGoods方法里,我们也加入了熟悉的GetMapping注解,并设置了请求的url为/goods/list
java
package com.company.api.service;
import com.company.api.entity.Goods;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;
@FeignClient(value = "MICROSERVICECLOUD-GOODS", fallbackFactory = GoodsClientServiceFallbackFactory.class)
public interface GoodsClientService {
@GetMapping("/goods/list")
List<Goods> getGoods();
}
因为在前面microservicecloud-provider-8001项目中,我们有在controller提供这个http接口

(2)新建一个microservicecloud-consumer-feign模块,类似于microservicecloud-consumer-80项目,同样作为消费者,其整体结构如下:

(4)修改POM文件,增加其相关依赖(注意这个项目依赖于前面提到的microservicecloud-api的接口,所以需要引入microservicecloud-api项目)
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">
<parent>
<artifactId>springcloud2025</artifactId>
<groupId>com.company</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microservicecloud-consumer-feign</artifactId>
<dependencies>
<dependency>
<groupId>com.company</groupId>
<artifactId>microservicecloud-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Feign相关支持 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<!-- ribbon相关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</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-config</artifactId>
</dependency>
</dependencies>
</project>
(5)新增application.yml配置文件
java
server:
port: 80
eureka:
client:
register-with-eureka: false #false表示不向注册中心注册自己
service-url:
defaultZone: http://localhost:7001/eureka/ #http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
#启用服务降级
feign:
hystrix:
enabled: true
(7)新增启动类和配置类
启动类
java
package com.company.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
//这里需要手动制定包扫描路径,否则识别不到API项目中的GoodsClientServiceFallbackFactory,导致项目无法启动
@SpringBootApplication(scanBasePackages = {"com.company.consumer","com.company.api.service"})
@EnableEurekaClient
@EnableFeignClients(basePackages = "com.company.api.service")
//因为Feign接口在另一个API项目中,且API项目的包和当前项目有点不一样,所以需要加上扫描包的范围,确保能扫描到
public class Consumer80FeignApplication {
public static void main(String[] args) {
SpringApplication.run(Consumer80FeignApplication.class, args);
}
}
这里需要注意的是启动类上面@EnableFeignClients(basePackages = "com.company.api.service"),需要能扫描到前面提到的microservicecloud-api项目中的接口GoodsClientService
配置类
java
package com.company.consumer.config;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.RetryRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
/**
* 设置ribbon负载均衡的算法,默认是轮询算法,也即每个都轮询一次。
* @return
*/
@Bean
public IRule myRule() {
return new RoundRobinRule(); //默认是轮询算法,也即每个都轮询一次。
// return new RandomRule(); //现在采用随机的算法
// return new RetryRule(); //如果provider都是正常的话,则轮询。如果有1个不可用的话,则在尝试几次失败后,会自动轮询能正常使用的服务
}
}
然后在控制器controller
java
package com.company.consumer.controller;
import com.company.api.entity.Goods;
import com.company.api.service.GoodsClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
@RequestMapping("/consumer")
public class GoodsConsumerContrller {
//private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-GOODS";
@Autowired
private GoodsClientService goodsClientService;
@Autowired
private RestTemplate restTemplate;
@GetMapping("/goods/list")
public List<Goods> getGoods() {
return restTemplate.exchange(REST_URL_PREFIX + "/goods/list", HttpMethod.GET,
null, new ParameterizedTypeReference<List<Goods>>(){}).getBody();
}
@GetMapping("/goods/list/feign")
public List<Goods> getGoodsByFeign() {
return goodsClientService.getGoods();
}
}
注意:我们前面在microservicecloud-api项目中定义了一个接口GoodsClientService,需要注入到controller中,然后就可以使用该接口,调用getGoods方法,来实现对microservicecloud-provider-8001项目的对应接口的调用。
(三)前面准备工作做好后,我们可以启动相关服务了,按照如下顺序,依次启动服务microservicecloud-eureka-7001 作为eureka注册服务端
microservicecloud-provider-8001 作为eureka 客户端,同时作为服务提供者
microservicecloud-consumer-feign 作为eureka 客户端,同时作为服务消费者

(四)启动正常后,我们在浏览器地址栏输入localhost/consumer/goods/list/feign
通过打断点,确认调用的是GoodsClientService接口,如图

然后放行该断点,在浏览器看到响应即为正常。如下图。这说明我们可以通过GoodsClientService接口来完成相关接口的调用(直接声明个接口,避免了通过restTemplate硬编码)
