Spring Cloud开发实践(六): 基于Consul和Spring Cloud 2021.0的演示项目

这篇具有很好参考价值的文章主要介绍了Spring Cloud开发实践(六): 基于Consul和Spring Cloud 2021.0的演示项目。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

  • Spring Cloud开发实践(一): 简介和根模块
  • Spring Cloud开发实践(二): Eureka服务和接口定义
  • Spring Cloud开发实践(三): 接口实现和下游调用
  • Spring Cloud开发实践(四): Docker部署
  • Spring Cloud开发实践(五): Consul - 服务注册的另一个选择
  • Spring Cloud开发实践(六): 基于Consul和Spring Cloud 2021.0的演示项目

Consul 服务

启动Consul服务, 在Win10下可以执行以下命令, 或者存成bat文件运行, 保持窗口打开

consul agent -dev -client=0.0.0.0 -data-dir .\ -advertise 127.0.0.1 -ui -config-dir .\

浏览器访问 http://127.0.0.1:8500 , 用于观察后面注册的Node和Health情况

Spring Cloud 项目

这个演示项目使用的 Spring Boot 和 Spring Cloud 都不是最新版本, 因为最新版本最低要求 JDK17. 这里选择的是对应 JDK11 可用的最高版本, 各组件版本明细为

  • Consul 1.15
  • JDK 11
  • Spring Boot 2.7.11
  • Spring Cloud 2021.0.6

整体结构

这个用于演示的项目名称为 Dummy, 包含3个子模块, 分别是 dummy-common-api, dummy-common-impl 和 dummy-admin, 其中

  • dummy-common-api 和 dummy-common-impl 逻辑上属于同一个模块 dummy-common. api 是对外输出的接口, impl是对应的实现
  • dummy-admin 依赖 dummy-common-api , 使用其提供的接口

打包后, 需要部署的是两个jar: dummy-common.jar 和 dummy-admin.jar, 前者提供服务接口, 后者消费前者提供的接口, 并对外(例如前端, 小程序, APP)提供接口

项目的整体结构如下

│   pom.xml
├───dummy-admin
│   │   pom.xml
│   ├───src
│   │   ├───main
│   │   │   ├───java
│   │   │   └───resources
│   │   │           application.yml
│   │   └───test
│   └───target
├───dummy-common-api
│   │   pom.xml
│   ├───src
│   │   ├───main
│   │   │   ├───java
│   │   │   └───resources
│   │   └───test
│   └───target
└───dummy-common-impl
    │   pom.xml
    ├───src
    │   ├───main
    │   │   ├───java
    │   │   └───resources
    │   │           application.yml
    │   └───test
    └───target

根模块 Dummy

根模块的 pom.xml 中,

  • 定义了子模块, module标签中的内容, 要和子模块目录名一致.
  • 设置JDK版本 11
  • 引入全局 Spring Boot Dependencies, 版本 2.7.11
  • 引入全局 Spring Cloud Dependencies, 版本 2021.0.6
  • 还有一些是Plugin相关的版本, 略
<?xml version="1.0" encoding="UTF-8"?>
    ...
    <name>Dummy: Root</name>
    <modules>
        <module>dummy-common-api</module>
        <module>dummy-common-impl</module>
        <module>dummy-admin</module>
    </modules>

    <properties>
        <!-- Global encoding -->
        <project.jdk.version>11</project.jdk.version>
        <project.source.encoding>UTF-8</project.source.encoding>

        <!-- Global dependency versions -->
        <spring-boot.version>2.7.11</spring-boot.version>
        <spring-cloud.version>2021.0.6</spring-cloud.version>
    </properties>

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

        </dependencies>
    </dependencyManagement>

    <build>
        ...
    </build>

</project>

Dummy Common API 模块

这个模块用于生成依赖的jar包, 作用非常重要. 以下详细说明

pom.xml 中除了定义和父模块的关系, 需要引入 openfeign

<?xml version="1.0" encoding="UTF-8"?>
    ...
    <parent>
        <groupId>com.rockbb.test</groupId>
        <artifactId>dummy</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>

    <artifactId>dummy-common-api</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>

    <name>Dummy: Commons API</name>

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

    <build>
        ...
    </build>
</project>

定义一个 UserDTO, 这个是用于传输的数据对象

@Data
public class UserDTO implements Serializable {
    private Long id;
    private String name;
}

对应的服务接口. 这里用到了 @FeignClient 注解

  • @FeignClient 是给 dummy-admin 模块用的
    • name= CommonConstant.SERVICE_NAME 就是 "dummy-common", 因为这个API模块中所有Service接口都使用同样的名称, 这边做成常量
    • contextId = "userDTOService" 如果不加这个参数, 多个 FeignClient 使用同样的 name 时, 就会冲突. 这个一般直接定义为这个 service 的bean名称
    • path = "/userDTOService" 用于指定当前类中所有接口的请求前缀. 在更早的版本中, 可以将 @RequestMapping 和 @FeignClient 联用, 这个是定义在 @RequestMapping 中的, 后来不允许了, 因为有安全风险.
  • @GetMapping 和 @PostMapping 同时用于 dummy-admin 和 dummy-common
    • 对于 dummy-admin, 这就是 FeignClient 的请求路径
    • 对于 dummy-common, 这就是 Contoller 方法的服务路径
    • 需要注意 @GetMapping 请求的接口形式, 必须显式添加 @RequestParam("id") 这类 GET 模式的参数注解, 否则使用 @GetMapping 的 Feign 请求也会被转为 POST 而导致请求错误.
@FeignClient(name = CommonConstant.SERVICE_NAME, contextId = "userDTOService", path = "/userDTOService")
public interface UserDTOService {

    @GetMapping("/get")
    UserDTO get(@RequestParam("id") long id);

    @PostMapping("/add")
    int add(@RequestBody UserDTO dto);
}

在 dummy-admin 中, 这个接口会被实例化为 feign 代理, 在模块中可以像普通 service 一样调用, 而在 dummy-common 中, 不引入 feign 依赖, 或者在 @EnableFeignClients 的 basePackages 中避开本包路径, 就会忽略这个注解, 从而实现模块间接口的关联.

与现在很多 Spring Cloud 项目中单独拆出一个 Service 模块的做法, 这种实现有很多的优点

  • 开发过程友好. 与单机开发几乎一样的代码量, 唯一区别是要注意 Get 和 Post 对请求参数的格式和个数的约束
  • 易重构易扩展. 可以借助 IDE 的代码分析能力, 改动自动标红, 避免人为错误和遗漏
  • 性能开销小, 如果 DTO 直接映射到数据库字段, 可以全程使用一个类.

Dummy Common Impl 模块

模块的 pom.xml

  • 引入 spring-boot-starter-web, 因为要提供 RestController 的能力
  • 引入 spring-cloud-starter-consul-discovery 或 spring-cloud-starter-consul-all, 因为要接 Consul
  • 引入 dummy-common-api 依赖, 因为 Controller 请求定义在 API 中
  • 打包使用 spring-boot-maven-plugin 的 repackage, 因为要打 fat jar, 在服务器上实现单包部署
<?xml version="1.0" encoding="UTF-8"?>
    ...
    <name>Dummy: Common Implementation</name>

    <dependencies>
        <!-- Spring Boot Dependencies -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Cloud Dependencies  consul-discovery 和 consul-all 二选一 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-all</artifactId>
        </dependency>
        ...
        <dependency>
            <groupId>com.rockbb.test</groupId>
            <artifactId>dummy-common-api</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>dummy-common</finalName>
        <resources>
            ...
        </resources>
        <plugins>
            ...
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

配置部分 application.yml

  • 定义服务端口 8762
  • 定义 servlet 路径, 必须定义, 否则不会配置 Controller 请求
  • spring.application.name: dummy-common 定义了本服务的名称, 这个名称就是在 FeignClient 中引用的服务名称, 需要与 FeignClient 中的值一致
  • spring.config.import 如果使用这个设置, 依赖要使用 consul-all, 因为 consul-discovery 中不带 consul-config. 使用这个设置后, 会自动使用默认的 Consul 地址和端口
  • cloud.consul.host 和 port 如果使用了config.import, 在这里可以修改默认的值, 如果不使用config.import, 则必须配置 host 和 port, 依赖可以换成 consul-discovery
  • cloud.consul.discovery.health-check-path 用于更改默认的 health 检查请求路径, 默认的是 /actuator/health, 这里改为 /health
  • cloud.consul.discovery.instance-id 用于定义当前实例在 Consul 里的实例ID. 默认使用 application.name-port, 如果正好这个服务在两个服务器上分别跑了一个实例, 且实例端口一样, 就会产生冲突, 可以改为 application.name-[随机串] 的形式避免冲突
server:
  port: 8762
  tomcat:
    uri-encoding: UTF-8
  servlet:
    context-path: /

spring:
  application:
    name: dummy-common

  config:
    import: 'optional:consul:' #This will connect to the Consul Agent at the default location of "http://localhost:8500"

#  cloud:
#    consul:
#      host: 127.0.0.1
#      port: 8500
#      discovery:
#        health-check-path: /health # replace the default /actuator/health
#        instance-id: ${spring.application.name}:${random.value}

代码部分, 首先是实现 health 检查的处理方法, 这部分是普通的 RestController 方法. 返回字符串可以任意指定, 只要返回的 code 是 200 就可以

@RestController
public class HealthCheckServiceImpl {

    @GetMapping("/health")
    public String get() {
        return "SUCCESS";
    }
}

服务接口的实现类, 这里实现了两个接口方法 get 和 add

  • 使用 @RestController 注解, 与 API Service 中方法上的 @GetMapping 和 @PostMapping 配合, 将 Service 方法映射为 Controller 方法
  • 在类上的 @RequestMapping("userDTOService") 方法是必须的, 因为在 API Service 中与 @FeignClient 冲突无法定义, 只能在这里定义
  • 方法和参数上除了 @Override 不需要任何注解, 因为都在 API Service 上定义过了. 这里加上注解也没问题, 但是要手工保持一致.
@RestController
@RequestMapping("userDTOService")
public class UserDTOServiceImpl implements UserDTOService {

    @Autowired
    private UserRepo userRepo;

    @Override
    public UserDTO get(long id) {
        log.debug("Get user: {}", id);
        UserDTO user = new UserDTO();
        user.setId(id);
        user.setName("dummy");
        return user;
    }

    @Override
    public int add(UserDTO dto) {
        log.debug("Add user: {}", dto.getName());
        return 0;
    }
}

dummy-common 模块运行后会将接口注册到 Consul, 启动后注意观察两部分:

  1. Consul 的日志输出和控制面板显示, 在-dev模式下, 节点注册后 Consul 日志会显示模块的名称和心跳检测记录, 面板上会显示新的 Node
  2. Consul 控制面板中显示的 Health Checks 是否正常, 如果不正常, 需要检查 /health 路径为什么访问失败

Dummy Admin 模块

dummy-admin 是调用接口, 并对外提供服务的模块

pom.xml 和 dummy-common 基本一样, 因为都要连接 Consul, 都要提供 Controller 方法

<?xml version="1.0" encoding="UTF-8"?>
    ...
    <name>Dummy: Admin API</name>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>com.rockbb.test</groupId>
            <artifactId>dummy-common-api</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>dummy-admin</finalName>
        <resources>
           ...
        </resources>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            ...
        </plugins>
    </build>
</project>

在主应用入口, 除了 @SpringBootApplication 以外, 还需要增加两个注解

  • @EnableDiscoveryClient(autoRegister=false) 连接到 Consul 并使用服务发现, 默认会将当前节点也注册到 Consul 作为服务. 对于纯消费节点, 不对其它节点提供接口的, 使用 autoRegister=false 可以避免将自己注册到 Consul
  • @EnableFeignClients(basePackages = {"com.rockbb.test.dummy.common.api"}) 扫描对应的包, 对 @FeignClient 注解实例化接口代理
/* Attach to discovery service without registering itself */
@EnableDiscoveryClient(autoRegister=false)
@EnableFeignClients(basePackages = {"com.rockbb.test.dummy.common.api"})
@SpringBootApplication
public class AdminApp {
    public static void main(String[] args) {
        SpringApplication.run(AdminApp.class, args);
    }
}

在调用方法的地方, 按普通 Service 注入和调用

@Slf4j
@RestController
public class IndexController {

    @Autowired
    private UserDTOService userDTOService;

    @GetMapping(value = "/user_get")
    public String doGetUser() {
        UserDTO user = userDTOService.get(100L);
        return user.getId() + ":" + user.getName();
    }

    @GetMapping(value = "/user_add")
    public String doAddUser() {
        UserDTO user = new UserDTO();
        user.setName("foobar");
        int result = userDTOService.add(user);
        return String.valueOf(result);
    }

可以通过注入的 DiscoveryClient 对象, 查看对应服务的服务地址(一般不需要)

@Autowired
private DiscoveryClient discoveryClient;

@GetMapping("/services")
public Optional<URI> serviceURL() {
    return discoveryClient.getInstances(CommonConstant.SERVICE_NAME)
            .stream()
            .map(ServiceInstance::getUri)
            .findFirst();
}

项目代码

项目的完整代码已经上传至 GitHub, 仓库地址: https://github.com/MiltonLai/spring-cloud-demos

与文中的模块相比, 增加了两个模块 dummy-file-api 和 dummy-file-impl 用于演示多级调用.文章来源地址https://www.toymoban.com/news/detail-448823.html

参考

  • Consul和Spring Boot非常详细的配置教程 https://medium.com/javarevisited/hands-on-consul-with-spring-boot-1ebf2918165c

到了这里,关于Spring Cloud开发实践(六): 基于Consul和Spring Cloud 2021.0的演示项目的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 构建弹性可扩展的微服务架构:基于Spring Cloud Alibaba 的实践

    💂 个人网站:【工具大全】【游戏大全】【神级源码资源网】 🤟 前端学习课程:👉【28个案例趣学前端】【400个JS面试题】 💅 寻找学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】 随着互联网业务的不断发展,传统的单体应用逐渐无法满足日益复杂的业务需求和

    2024年02月14日
    浏览(297)
  • Spring Cloud Alibaba 2021.0.1.0之Nacos升级

    1 背景 本次隆重发布的 Spring Cloud Alibaba 2021.0.1.0 版本在 Spring Cloud 2021.0.1、Spring Boot 2.6.3 的基础上对其中包括注册配置中心、分布式消息等在内的众多组件进行重大升级: Nacos :升级 Nacos 客户端到 1.4.2 版本,修复了 Nacos 1.4.1 所存在的相关问题,支持了 Nacos 服务发现失败容错

    2024年02月08日
    浏览(38)
  • 【Spring Cloud】基于 Feign 实现远程调用,深入探索 Feign 的自定义配置、性能优化以及最佳实践方案

    在微服务架构中,服务之间的通信是至关重要的,而远程调用则成为实现这种通信的一种常见方式。在 Java 中,使用 RestTemplate 是一种传统的远程调用方式,但它存在一些问题,如代码可读性差、编程体验不一致以及参数复杂URL难以维护等。 在本文中,我们将探讨如何通过使

    2024年02月04日
    浏览(54)
  • 微服务 Spring Cloud 2021 Spring Boot 2.7.x Java JDK8升级到JDK17研究

    项目正在使用jdk8 如果要升级到jdk17 则需要升级springboot版本及springcloud版本 (springcloud版本和springboot版本必须匹配 要一块升级) 。目前使用的版本如下: spring boot 版本为 2.1.5.RELEASE spring cloud 版本为 Greenwich.SR2 spring 版本为 5.1.7.RELEASE jdk 由 8 升级到 17 spring boot 由 2.1.5.RELEASE

    2024年02月01日
    浏览(56)
  • 智慧工地云平台源码,基于微服务+Java+Spring Cloud +UniApp +MySql开发

    智慧工地可视化系统利用物联网、人工智能、云计算、大数据、移动互联网等新一代信息技术,通过工地中台、三维建模服务、视频AI分析服务等技术支撑,实现智慧工地高精度动态仿真,趋势分析、预测、模拟,建设智能化、标准化的智慧工地综合业务系统,解决传统工地

    2024年02月14日
    浏览(71)
  • 互联网+建筑工地源码,基于微服务+Java+Spring Cloud +Vue+UniApp开发

    一、智慧工地概念 智慧工地就是互联网+建筑工地,是将互联网+的理念和技术引入建筑工地,然后以物联网、移动互联网技术为基础,充分应用BIM、大数据、人工智能、移动通讯、云计算、物联网等信息技术,通过人机交互、感知、决策、执行和反馈等,实现对工程项目内人

    2024年02月03日
    浏览(43)
  • 智慧工地源码,互联网+建筑工地,基于微服务+Java+Spring Cloud +Vue+UniApp开发

    基于微服务+Java+Spring Cloud +Vue+UniApp +MySql开发的智慧工地云平台源码 智慧工地就是互联网+建筑工地,是将互联网+的理念和技术引入建筑工地,然后以物联网、移动互联网技术为基础,充分应用BIM、大数据、人工智能、移动通讯、云计算、物联网等信息技术,通过人机交互、感

    2024年02月13日
    浏览(50)
  • 基于微服务+Java+Spring Cloud开发的建筑工地智慧平台源码 云平台多端项目源码

    建筑工地智慧平台源码,施工管理端、项目监管端、数据大屏端、移动APP端全套源码 技术架构:微服务+Java+Spring Cloud +Vue+UniApp +MySql+自主版权+实际应用案例+演示 建筑工地智慧平台已应用于线上巡查、质量管理、实名制管理、危大工程管理、运渣车管理、绿色施工、视频监控

    2024年02月07日
    浏览(55)
  • 解决 Spring Cloud 2021.0.5 版本,使用 nacos 做配置中心,报 No spring.config.import property has been defined 的问题

    报错信息如下 Description: No spring.config.import property has been defined Spring 官方给出的解决方案如下 Add a spring.config.import=nacos: property to your configuration. If configuration is not required add spring.config.import=optional:nacos: instead. To disable this check, set spring.cloud.nacos.config.import-check.enabled=false. 这里只

    2024年02月11日
    浏览(62)
  • spring cloud zuul实践

    一、 描述 Spring Cloud Zuul是基于Netflix开源的Zuul项目构建而成,它作为微服务架构中的网关服务,主要用于实现动态路由、负载均衡和请求过滤等功能。 动态路由:Zuul根据预设的路由规则将进来的请求路由到相应的服务实例上。路由规则可以通过配置文件或代码进行定义,接

    2024年02月15日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包