SpringCloud微服務實戰——搭建企業級開發框架(十一):整合OpenFeign用於微服務間呼叫

全棧程式猿發表於2021-11-01

作為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呼叫測試介面,可以檢視微服務呼叫成功
image.png
image.png

本文原始碼在https://gitee.com/wmz1930/GitEgg 的chapter-11分支。

相關文章