作為Spring Cloud的子專案之一,Spring Cloud OpenFeign以將OpenFeign整合到Spring Boot應用中的方式,為微服務架構下服務之間的呼叫提供瞭解決方案。首先,利用了OpenFeign的宣告式方式定義Web服務客戶端;其次還更進一步,通過整合Ribbon或Eureka實現負載均衡的HTTP客戶端。
OpenFeign 可以使消費者將提供者提供的服務名偽裝為介面進行消費,消費者只需使用“Service 介面+ 註解”的方式。即可直接呼叫 Service 介面方法,而無需再使用 RestTemplate 了。其實原理還是使用RestTemplate,而通過Feign(偽裝)成我們熟悉的習慣。
GitEgg框架除了新建Fegin服務之外,還定義實現了消費者Fegin-api,在其他微服務呼叫的時候,只需要引入Fegin-api即可直接呼叫,不需要在自己重複開發消費者呼叫介面。
1、在GitEgg-Platform工程的子工程gitegg-platform-cloud中引入spring-cloud-starter-openfeign依賴,重新install GitEgg-Platform工程,然後GitEgg-Cloud專案需要重新在IDEA中執行Reload All Maven Projects。
<!--?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>GitEgg-Platform</artifactid>
<groupid>com.gitegg.platform</groupid>
<version>1.0-SNAPSHOT</version>
</parent>
<modelversion>4.0.0</modelversion>
<artifactid>gitegg-platform-cloud</artifactid>
<name>${project.artifactId}</name>
<version>${project.parent.version}</version>
<packaging>jar</packaging>
<dependencies>
<!-- Nacos 服務註冊發現-->
<dependency>
<groupid>com.alibaba.cloud</groupid>
<artifactid>spring-cloud-starter-alibaba-nacos-discovery</artifactid>
</dependency>
<!-- Nacos 分散式配置-->
<dependency>
<groupid>com.alibaba.cloud</groupid>
<artifactid>spring-cloud-starter-alibaba-nacos-config</artifactid>
</dependency>
<!-- OpenFeign 微服務呼叫解決方案-->
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-openfeign</artifactid>
</dependency>
</dependencies>
</project>
我們從系統架構設計方面考慮,GitEgg-Cloud下的gitegg-service作為業務邏輯處理模組,gitegg-service-api作為微服務統一對外提供介面的模組,這裡在測試的時候需要用到兩個微服務之間的呼叫,我們這裡在gitegg-service下gitegg-service-base裡面新建測試程式碼,和gitegg-service-system之間相互呼叫。注意,這裡需要說明,gitegg-service-api並不是繼承gitegg-service做業務擴充套件,而是對外提供介面的抽象,比如現在有A、B、C三個系統A、B都需要呼叫C的同一個方法,如果按照業務邏輯來羅列程式碼的話,那麼就需要在A和B中寫相同的呼叫方法來呼叫C,這裡我們抽出來一個api模組,專門存放呼叫微服務C的呼叫方法,在使用時,A和B只需要引入C的jar包即可直接使用呼叫方法。
2、在gitegg-service-system-api工程中,引入SpringBoot,SpringCloud,Swagger2的依賴,新建ISystemFeign.java和ApiSystemDTO.java,作為OpenFeign呼叫微服務的公共方法:
<!--?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>GitEgg-Cloud</artifactid>
<groupid>com.gitegg.cloud</groupid>
<version>1.0-SNAPSHOT</version>
</parent>
<modelversion>4.0.0</modelversion>
<artifactid>gitegg-service-api</artifactid>
<name>${project.artifactId}</name>
<version>${project.parent.version}</version>
<packaging>pom</packaging>
<modules>
<module>gitegg-service-base-api</module>
<module>gitegg-service-bigdata-api</module>
<module>gitegg-service-system-api</module>
</modules>
<dependencies>
<!-- gitegg Spring Boot自定義及擴充套件 -->
<dependency>
<groupid>com.gitegg.platform</groupid>
<artifactid>gitegg-platform-boot</artifactid>
</dependency>
<!-- gitegg Spring Cloud自定義及擴充套件 -->
<dependency>
<groupid>com.gitegg.platform</groupid>
<artifactid>gitegg-platform-cloud</artifactid>
</dependency>
<!-- gitegg swagger2-knife4j -->
<dependency>
<groupid>com.gitegg.platform</groupid>
<artifactid>gitegg-platform-swagger</artifactid>
</dependency>
</dependencies>
</project>
package com.gitegg.service.system.api.feign;
import com.gitegg.platform.boot.common.base.Result;
import com.gitegg.service.system.api.dto.ApiSystemDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "gitegg-service-system")
public interface ISystemFeign {
/**
* OpenFeign測試Get
*
* @param id
* @return
*/
@GetMapping("/system/api/by/id")
Result<object> querySystemById(@RequestParam("id") Long id);
/**
* OpenFeign測試Post
*
* @param apiSystemDTO
* @return ApiSystemDTO
*/
@PostMapping("/system/api/by/dto")
Result<apisystemdto> querySystemByDto(@RequestBody ApiSystemDTO apiSystemDTO);
}
package com.gitegg.service.system.api.dto;
import lombok.Data;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@Data
public class ApiSystemDTO {
@NotNull
@Min(value = 10, message = "id必須大於10")
@Max(value = 150, message = "id必須小於150")
private Long id;
@NotNull(message = "名稱不能為空")
@Size(min = 3, max = 20, message = "名稱長度必須在3-20之間")
private String name;
}
2、在gitegg-service-system工程中,修改SystemController.java,新增需要被微服務呼叫的方法:
package com.gitegg.service.system.controller;
import com.gitegg.platform.boot.common.base.Result;
import com.gitegg.service.system.dto.SystemDTO;
import com.gitegg.service.system.service.ISystemService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RestController
@RequestMapping(value = "system")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Api(tags = "gitegg-system")
@RefreshScope
public class SystemController {
private final ISystemService systemService;
@Value("${spring.datasource.maxActive}")
private String nacosMaxActiveType;
@GetMapping(value = "list")
@ApiOperation(value = "system list介面")
public Object list() {
return systemService.list();
}
@GetMapping(value = "page")
@ApiOperation(value = "system page介面")
public Object page() {
return systemService.page();
}
@GetMapping(value = "exception")
@ApiOperation(value = "自定義異常及返回測試介面")
public Result<string> exception() {
return Result.data(systemService.exception());
}
@PostMapping(value = "valid")
@ApiOperation(value = "引數校驗測試介面")
public Result<systemdto> valid(@Valid @RequestBody SystemDTO systemDTO) {
return Result.data(systemDTO);
}
@PostMapping(value = "nacos")
@ApiOperation(value = "Nacos讀取配置檔案測試介面")
public Result<string> nacos() {
return Result.data(nacosMaxActiveType);
}
@GetMapping(value = "api/by/id")
@ApiOperation(value = "Fegin Get呼叫測試介面")
public Result<object> feginById(@RequestParam("id") String id) {
return Result.data(systemService.list());
}
@PostMapping(value = "api/by/dto")
@ApiOperation(value = "Fegin Post呼叫測試介面")
public Result<object> feginByDto(@Valid @RequestBody SystemDTO systemDTO) {
return Result.data(systemDTO);
}
}
3、參照gitegg-service-system工程,在gitegg-service-base工程下,引入gitegg-service-system-api依賴,新建BaseController.java、GitEggBaseApplication.java、bootstrap.yml作為服務呼叫方:
pom.xml:
<dependencies>
<!-- gitegg-service-system 的fegin公共呼叫方法 -->
<dependency>
<groupid>com.gitegg.cloud</groupid>
<artifactid>gitegg-service-system-api</artifactid>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
BaseController.java:
package com.gitegg.service.base.controller;
import com.gitegg.platform.boot.common.base.Result;
import com.gitegg.service.system.api.dto.ApiSystemDTO;
import com.gitegg.service.system.api.feign.ISystemFeign;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RestController
@RequestMapping(value = "base")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Api(tags = "gitegg-base")
@RefreshScope
public class BaseController {
private final ISystemFeign systemFeign;
@GetMapping(value = "api/by/id")
@ApiOperation(value = "Fegin Get呼叫測試介面")
public Result<object> feginById(@RequestParam("id") Long id) {
return Result.data(systemFeign.querySystemById(id));
}
@PostMapping(value = "api/by/dto")
@ApiOperation(value = "Fegin Post呼叫測試介面")
public Result<object> feginByDto(@Valid @RequestBody ApiSystemDTO systemDTO) {
return Result.data(systemFeign.querySystemByDto(systemDTO));
}
}
GitEggBaseApplication.java:
package com.gitegg.service.base;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
/**
* gitegg-base 啟動類
*/
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.gitegg")
@ComponentScan(basePackages = "com.gitegg")
@MapperScan("com.gitegg.*.*.mapper")
@SpringBootApplication
public class GitEggBaseApplication {
public static void main(String[] args) {
SpringApplication.run(GitEggBaseApplication.class,args);
}
}
bootstrap.yml:
server:
port: 8002
spring:
application:
name: gitegg-service-base
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
prefix: gitegg-service-system
group: DEFAULT_GROUP
enabled: true
4、分別啟動gitegg-service-base和gitegg-service-system專案,開啟瀏覽器,訪問http://127.0.0.1:8002/doc.html(這裡gitegg-service-base的埠設定為8002,所以訪問gitegg-service-base的服務進行測試),在頁面左側選單分別點選Fegin Get呼叫測試介面和Fegin Post呼叫測試介面,可以檢視微服務呼叫成功
本文原始碼在https://gitee.com/wmz1930/GitEgg 的chapter-11分支。