SpringCloud Feign 以及 一个标准的微服务的制作

一个标准的微服务制作

以一个咖啡小程序项目的订单模块为例,这个模块必将包括:

各种实体类(pojo,dto,vo....)

控制器 controller 服务类service

......

其中控制器中有的接口需要提供给其他微服务,订单模块也需要其他微服务提供接口。

那么在项目开发和维护的过程中,如果一个模块里面的内容发生变动,相关的模块的业务也要修改,有种"牵一发而动全身"的感觉。(如订单模块修改了一个订单pojo里面的一个字段,那么用户模块用到这个订单pojo的所有业务也要同时修改,十分麻烦)

于是乎,我们需要将一个完整的微服务模块拆成三个部分

baoder_orders是项目的订单模块,它被拆成了三个部分

其中:

baoder_orders_model :包含了订单模块要用的所有的实体类

baoder_orders_service :包含了订单模块的所有的业务,它会调用baoder_orders_model

baoder_orders_api :包含了订单模块向其他微服务暴露的接口(基于Feign的声明式的http客户端) 其他微服务可以通过引入 baoder_orders_api 来调用baoder_orders_service的服务

********************************************************************

那么这三个部分是怎么相互协作的呢?且看下文细细道来

*********************************************************

我们先分别分析三个部分的结构,最后再通过最上面的这个图来加深理解

baoder_orders_model

目录结构如下,baoder_orders_model模块用于保存订单模块需要的所有实体类,包括统一封装结果,自定义异常等,异常拦截器仍然放在baoder_orders_service里面。

打开它的pom文件,可以看到它确确实实只是作为存储实体类的模块,甚至连bulid标签都没有

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.gmgx</groupId>
    <artifactId>baoder_orders_model</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>baoder_orders_model</name>
    <description>baoder_orders_model</description>
<!--    baoder_parent用于管理项目需要的所有的依赖的版本-->
    <parent>
        <groupId>com.gmgx</groupId>
        <artifactId>baoder_parent</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
        </dependency>
        <!--模板引擎-->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>

    </dependencies>

</project>

我们需要做的事情就是让他被service和api引用,那么就需要把它安装到我们本地的maven仓库里面,需要的时候作为依赖在pom文件中引用即可。

执行完这三步后,去我们本地的maven仓库所在的文件夹里面,可以看到打包好的baoder_orders_model依赖

baoder_orders_service

目录结构如下,baoder_orders_service包含了订单模块的所有业务,这个模块是要被打包发布到docker上的,所以会有有关docker的两个文件

打开application.properties文件,可以看到关于数据库,nacos,redis的相关配置。

其中数据库和redis是业务需要的

同时利用nacos将这个微服务注册到nacos注册中心上,服务名为baoder-orders-service

XML 复制代码
# 应用服务 WEB 访问端口
server.port=8090

# 数据库配置
spring.datasource.url=jdbc:mysql://192.168.2.222:3306/baoder-orders?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&connectTimeout=10000&socketTimeout=30000&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts.html
spring.application.name=baoder-orders-service
# Nacos认证信息
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
# Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
spring.cloud.nacos.discovery.server-addr=192.168.2.222:8848
# 注册到 nacos 的指定 namespace,默认为 public
spring.cloud.nacos.discovery.namespace=public

# redis配置
spring.data.redis.host=192.168.2.222
spring.data.redis.database=0

(重头戏)打开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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.gmgx</groupId>
    <artifactId>baoder_orders_service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>baoder_orders_service</name>
    <description>baoder_orders_service</description>

    <parent>
        <groupId>com.gmgx</groupId>
        <artifactId>baoder_parent</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
        </dependency>
        <!--        redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        <dependency>
            <groupId>com.gmgx</groupId>
            <artifactId>baoder_orders_model</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.gmgx.BaoderOrdersServiceApplication</mainClass>
                    <skip>false</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <!--            跳过测试-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.4.2</version>
                <configuration>
                    <skipTests>true</skipTests>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

可以看到我们刚才install到本地仓库的baoder_orders_model

我们随便打开一个服务,能看到baoder_orders_model里面的实体类已经被引进来了

这样一来,负责其他模块的同事们只需要拿到最新的baoder_orders_model,就可以愉快地做自己的模块了,只需要我把最新的 baoder_orders_model给他们,让他们在他们的本地仓库install就可以了。

baoder_orders_api(被调用方)

目录结构如下。baoder_orders_api 负责向其他调用者(其他微服务)提供baoder_service_api暴露出来的接口,我们需要详细说明这个模块是怎么做的,这就是SpringCloud中Feign组件的应用。

1.引入依赖

我们需要引入如下依赖(这两个依赖是feign要用的)

XML 复制代码
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

最终的pom文件是这样的,声明http请求需要实体类,因此引入了baoder_orders_model

其实只需要三个依赖(2+1)就行了,boot的依赖调用者肯定会有

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.gmgx</groupId>
    <artifactId>baoder_orders_api</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>baoder_orders_api</name>
    <description>baoder_orders_api</description>

    <parent>
        <groupId>com.gmgx</groupId>
        <artifactId>baoder_parent</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.gmgx</groupId>
            <artifactId>baoder_orders_model</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.gmgx.BaoderOrdersApiApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

2.写客户端接口

java 复制代码
package com.gmgx.api;

import com.gmgx.common.Result;

import com.gmgx.dto.OrderSearchDto;
import com.gmgx.dto.SubmitDto;
import com.gmgx.entity.Orders;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;

@FeignClient(
        name = "baoder-orders-service",
        contextId = "baoder-orders-service"
)
@Component
public interface OrdersClient {
    static final String prefix = "order";

    @PutMapping(prefix + "/cancel")
    public Result<Object> cancel(@RequestBody Orders order);

    @PutMapping(prefix + "rejection")
    public Result<Object> rejection(@RequestBody Orders order);

    @PutMapping(prefix + "confirm")
    public Result<Object> confirm(@RequestBody Orders order);

    @PutMapping(prefix + "delivery/{id}")
    public Result<String> delivery(@PathVariable(value = "id") String id);

    @PutMapping(prefix + "complete/{id}")
    public Result<Object> complete(@PathVariable(value = "id") String id);

    @PostMapping(prefix + "conditionSearch")
    public Result<Object> conditionSearch(@RequestBody OrderSearchDto dto);

    @GetMapping(prefix + "details/{oId}")
    public Result<Object> getDetails(@PathVariable(value = "id") String oId);

    @PutMapping(prefix + "cancel/{id}/{cancelReason}")
    public Result<Object> cancelByMember(@PathVariable("id") String id, @PathVariable(value = "cancelReason") String cancelReason);

    @GetMapping(prefix + "historyOrders/{memberId}")
    public Result<Object> getHistoryOrders(@PathVariable(value = "memberId") String memberId);

    @PostMapping(prefix + "submit")
    public Result<String> submit(@RequestBody SubmitDto submitDto);

    @PutMapping(prefix + "payment/{oId}/{type}")
    public Result<Object> payment(@PathVariable(value = "oId") String oId, @PathVariable(value = "type") String type);

    @PostMapping(prefix + "repetition/{oId}")
    public Result<Object> repetition(@PathVariable(value = "oid") String oId);
}

*************************************************************************************************************

@FeignClient用于声明要调用哪个service,这个从service的配置文件里面找,即nacos注册的服务名(所有的微服务都要注册到nacos)

要把这个接口注册成一个组件,这样调用方就可以通过@Resource 自动装配使用Feign客户端了

feign客户端的接口路径,访问方法,请求参数,返回值等要和service那边的控制器一样

最后,baoder_orders_api也要被install到本地仓库,我们只需要把这个模块给需要调用我们接口的同事就可以了

调用api

现在用一个demo-useOrders项目来模拟baoder_orders_service的调用方

创建好项目后,打开它的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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.gmgx</groupId>
    <artifactId>demo-useOrders</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo-useOrders</name>
    <description>demo-useOrders</description>
    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>3.0.2</spring-boot.version>
        <spring-cloud-alibaba.version>2022.0.0.0-RC2</spring-cloud-alibaba.version>
        <spring-cloud.version>2022.0.0-RC2</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
            <version>4.5.0</version>
        </dependency>

        <dependency>
            <groupId>com.gmgx</groupId>
            <artifactId>baoder_orders_api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.gmgx</groupId>
            <artifactId>baoder_orders_model</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.gmgx.DemoUseOrdersApplication</mainClass>
                    <skip>false</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

导入的依赖如下(注意导入了api和model)

控制器中直接注入就可以使用feign客户端了

applicaton.properties如下

XML 复制代码
# 应用服务 WEB 访问端口
server.port=8088
# Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts.html
spring.application.name=useOrders-service
# Nacos认证信息
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
# Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
spring.cloud.nacos.discovery.server-addr=192.168.2.222:8848
# 注册到 nacos 的指定 namespace,默认为 public
spring.cloud.nacos.discovery.namespace=public

# 数据库配置
spring.datasource.url=jdbc:mysql://192.168.2.222:3306/baoder-orders?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&connectTimeout=10000&socketTimeout=30000&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

现在把service和demo-useOrders都跑起来(我服务器已经部署了baoder_orders_service容器和demo-useOrders,但是本地连服务器访问会超时,干脆直接启动本地的service模块,效果是一样的)

***********************************************************************************************************

最后再回到这张图,思路是否清晰了点,这就是一个标准的微服务的制作流程。(其中baoder_orders_api和demo-useOrders那里用到了SpringCloud的feign组件)

相关推荐
xlsw_2 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹3 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭3 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫4 小时前
泛型(2)
java
超爱吃士力架4 小时前
邀请逻辑
java·linux·后端
南宫生4 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石4 小时前
12/21java基础
java
李小白664 小时前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp4 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea
装不满的克莱因瓶5 小时前
【Redis经典面试题六】Redis的持久化机制是怎样的?
java·数据库·redis·持久化·aof·rdb