該系列項目整體介紹及源代碼請參照前面寫的一篇文章【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
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 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配置文件
server:port: 80eureka: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)新增啟動類和配置類
啟動類
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
配置類
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@LoadBalancedpublic RestTemplate restTemplate() {return new RestTemplate();}/*** 設置ribbon負載均衡的算法,默認是輪詢算法,也即每個都輪詢一次。* @return*/@Beanpublic IRule myRule() {return new RoundRobinRule(); //默認是輪詢算法,也即每個都輪詢一次。// return new RandomRule(); //現在采用隨機的算法// return new RetryRule(); //如果provider都是正常的話,則輪詢。如果有1個不可用的話,則在嘗試幾次失敗后,會自動輪詢能正常使用的服務}
}
然后在控制器controller
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";@Autowiredprivate GoodsClientService goodsClientService;@Autowiredprivate 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硬編碼)