一、寫在前邊
最近開發任務比較忙,下班也開始鍛煉了,這個系列的文章就放了很久,看github我提交的Feign的入門程序已經好久了,今天正好得空,這就更上一貼,准備分幾部分寫
注意:之前幾個項目中,筆者忽略了一個問題,pom文件中如果parent節點下的是spring-cloud-starter-parent而不是spring-boot-starter-parent的話,這樣就可以不用寫如下代碼了
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Camden.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
二、Feign簡介
通過前面的學習對Ribbon和Hystrix來進行開發,通過這兩個重磅武器學會了如何在微服務實現客戶端的負載均衡、服務調用和斷路保護,實踐中我們發現這兩個基礎工具總是成對出現的,那么有沒有更高層次的封裝來簡化開發呢?
Spring為我們提供了Spring Cloud Feign就是這樣的一個工具,基於Netflix Feign實現,除了負載均衡、服務調用和斷路保護的功能外,還提供了聲明式Web服務客戶端的定義方式以及兼容SpringMVC的注解支持。
三、快速入門
繼續使用之前的整個項目,沒有這個項目的同學請clone下來代碼,地址:https://github.com/HellxZ/SpringCloudLearn.git
新建一個項目名為FeignCustomer
,
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.cnblogs.hellxz</groupId>
<artifactId>FeignCustomer</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Dalston.SR5</version>
<relativePath/>
</parent>
<dependencies>
<!-- Hystrix,Feign是基於Hystrix的-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<!-- Eureka依賴,連接注冊中心的都需要有這個依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- Feign依賴,聲明式開發 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<!-- SpringMVC依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
如同常規在resources
包下創建application.yml
server:
port: 9001
spring:
application:
name: feign-customer
eureka:
client:
serviceUrl:
defaultZone: http://peer1:1111/eureka
創建主類,相較於其他只需添加@EnableFeignClients
來開啟Feign的支持
package com.cnblogs.hellxz;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
@EnableFeignClients //開啟Feign
@SpringCloudApplication
public class FeignApp {
public static void main(String[] args) {
SpringApplication.run(FeignApp.class, args);
}
}
除了以上的我們需要一個用來調用服務提供者的工具,在Ribbon那幾章我們使用的是RestTemplate,Feign是一種聲明式調用工具,下面就來探索一下
在com.cnblogs.hellxz.client
創建EurekaServiceFeign
,這個是用來當做Service一樣的用法,代碼如下:
package com.cnblogs.hellxz.client;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* 服務提供者的Feign
* 這個接口相當於把原來的服務提供者項目當成一個Service類,
* 我們只需在聲明它的Feign-client的名字,會自動去調用注冊中心的這個名字的服務
* 更簡單的理解是value相當於MVC中的Controller類的父路徑,通過"父路徑+子路徑和參數來調用服務"
*/
@FeignClient(value = "eureka-service") //其中的value的值為要調用服務的名稱
public interface EurekaServiceFeign {
/**
* 第一個Feign代碼
* Feign中沒有原生的@GetMapping/@PostMapping/@DeleteMapping/@PutMapping,要指定需要用method進行
*/
@RequestMapping(value = "/hello", method=RequestMethod.GET)
String helloFeign();
}
剛才說過我們可以使用這個Feign當做Service來使用服務提供者的方法,得出返回值,這里我們寫一個Controller來示范一下使用
package com.cnblogs.hellxz.controller;
import com.cnblogs.hellxz.client.EurekaServiceFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("feign")
public class HelloController {
@Autowired
private EurekaServiceFeign eurekaServiceFeign; //注入Feign
@GetMapping("/hello")
@ResponseBody
public String sayHello(){
//在方法中調用feign的方法
return eurekaServiceFeign.helloFeign();
}
}
好了,我們分別啟動注冊中心、服務提供者、還有這個Feign項目
使用postman進行測試,使用Get請求訪問http://localhost:9001/feign/hello
四、參數綁定
Spring官方在整合NetFlix Feign的時候,加入了SpringMVC的注解支持,這使得Feign讓習慣了SpringMVC的程序員更好的過渡過來,下面我舉幾個例子,就舉項目中最常用的吧。
1. @PathVariable
擴充EurekaServiceFeign
,添加如下代碼,注釋很詳細,不多說
/**
* 在服務提供者我們有一個方法是用直接寫在鏈接,SpringMVC中用的@PathVariable
* 這里邊和SpringMVC中有些有一點點出入,SpringMVC中只有一個參數而且參數名的話是不用額外指定參數名的,而feign中必須指定
*/
@RequestMapping(value = "/greet/{dd}",method = RequestMethod.GET)
String greetFeign(@PathVariable("dd") String dd);
在HelloController
中也添加對應的代碼,用來調用上邊的方法
/**
* 注意這里是SpringMVC,URL中的參數與方法中的參數名相同無需在注解中注明參數名
*/
@GetMapping("/greet/{test}")
@ResponseBody
public String greet(@PathVariable String test){
return eurekaServiceFeign.greetFeign(test);
}
測試這個方法
2. @RequestParam
為聲名為Feign的類添加方法,調用服務提供者的方法
如下代碼中使用的User類是從服務提供者模塊中復制出來的
/**
* 這里說下@RequestParam 注解和SpringMVC中差別也是不大,我認為區別在於Feign中的是參數進入URL或請求體中,
* 而SpringMVC中是參數從請求體中到方法中
* @param ids id串,比如“1,2,3”
* @return
*/
@RequestMapping(value = "/users",method = RequestMethod.GET)
public List<User> getUsersByIds(@RequestParam("ids") List<Long> ids);
調用這個方法的方法
/**
* 調用Feign中使用@RequestParam的方法
*/
@GetMapping("/users")
@ResponseBody
public List<User> getUserListByIds(@RequestParam("ids") List<Long> ids){
return eurekaServiceFeign.getUsersByIds(ids);
}
測試
3. @RequestHeader
這里是為請求的Header中加入參數的注解,但是之前我們的服務提供者並沒有這個方法,這里為GetRequestController
添加一個方法如下
@GetMapping("/headers")
public String getParamByRequestHeader(@RequestHeader("name") String name){
return name;
}
現在我們為Feign這個類添加一個調用上邊方法的方法
/**
* 這里是將參數添加到Headers中
* @param name 參數
*/
@RequestMapping(value = "/headers")
String getParamByHeaders(@RequestHeader("name") String name);
在Controller中,添加代碼
@GetMapping("/headers")
@ResponseBody
public String getParamByHeaders(@RequestHeader("name") String name){
return eurekaServiceFeign.getParamByHeaders(name);
}
測試
5. @RequestBody
使用這個注解需要使用Post請求,這里簡單舉例
Feign類中添加方法
/**
* 調用服務提供者的post方法,接收回來再被服務提供者丟回來
* @param user User對象
*/
@RequestMapping(value = "/user", method = RequestMethod.POST)
User getUserByRequestBody(@RequestBody User user);
Controller中添加
@PostMapping("/requestBody")
@ResponseBody
public User getParamByRequestBody(@RequestBody User user){
return eurekaServiceFeign.getUserByRequestBody(user);
}
測試
需要注意的是
@RequestParam
和@RequestHeader
,以及最先提到的@PathVariable
這三個注解都需要寫明參數名稱,這點與SpringMVC中不同,否則會報IllegalStateException異常,所以一定要指明參數名!
時間不早了,明天繼續更