Eureka 服务注册和服务发现的使用

1. 父子工程的搭建

首先创建一个 Maven 项目,删除 src ,只保留 pom.xml

然后来进行 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>org.example</groupId>
  <artifactId>spring-cloud-demo</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>
  <modules>
    <module>order-service</module>
    <module>product-service</module>
  </modules>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.1.6</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <java.version>17</java.version>
    <mybatis.version>3.0.3</mybatis.version>
    <mysql.version>8.0.33</mysql.version>
    <spring-cloud.version>2022.0.3</spring-cloud.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </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.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>${mybatis.version}</version>
      </dependency>
      <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>${mysql.version}</version>
      </dependency>
      <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter-test</artifactId>
        <version>${mybatis.version}</version>
        <scope>test</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>

在上面的配置中,使用 properties 来进行版本号的统一管理,使用 dependencyManagement 来管理依赖,并通过<packaging>pom</packaging>来生命父工程的打包方式为 pom

dependencyManagement 和 dependencies

  1. dependencies:将依赖的 jar 包添加到父项目的 dependencies 部分时,这些依赖会被父项目及其子项目继承,子项目无需额外操作即可自动包含这些依赖。
  2. dependencyManagement: 仅用于声明依赖,不会将 jar 包引入到父项目或子项目中。当子项目需要使用在父项目 dependencyManagement 中声明的依赖时,需在子项目中显式声明该依赖。子项目不指定版本号时,会从父项目的 dependencyManagement 部分读取相应依赖的版本号;如果子项目指定了版本号,就使用子项目中指定的版本号,不使用父项目声明的版本。

关于打包方式:父项目的打包方式通常应为 pom,而不是 jarwar,因为父项目主要起依赖管理和项目聚合的作用,不包含需要部署或运行的代码。

2. 子工程的搭建

在父工程右键选择新建一个 Module,

创建时 Parent 默认为父工程

接着配置子工程的项目依赖,由于父工程已经对版本号进行了统一管理,直接进行以下配置即可

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
  </dependency>
  <!--mybatis-->
  <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
  </dependency>
</dependencies>

<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
  </plugins>
  <resources>
    <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
      <includes>
        <include>**/**</include>
      </includes>
    </resource>
  </resources>
</build>

在一个父项目中搭建两个子工程

然后在这两个子工程中分别写一个查询接口

@RequestMapping("/{orderId}")
public OrderInfo getOrderById(@PathVariable("orderId") Integer orderId){
    return orderService.selectOrderById(orderId);
}
@RequestMapping("/{productId}")
public ProductInfo selectProductById(@PathVariable("productId") Integer productId) {
    return productService.selectProductById(productId);
}

3. 远程调用

如果此时需要实现一个查询订单的功能,查询结果中需要包含商品信息,由于上面的两个子工程现在是分开的,并不是像之前一样写在一个工程中,那么现在就不能直接调用查询的结果了

可以联想一下前端调用后端获取资源的方式,就是通过发送一个 http 请求来获取的,那么后端之间调用也可以使用这种方式,order-service 服务向 product-service 服务发送一个 http 请求,把得到的返回结果和订单结果合并在一起返回给调用方,有许多方式可以构造一个 http 请求,这里采用 Spring 提供的 RestTemplate 来实现一下:

RestTemplate 是 Spring 提供的,封装 http 调用,并强制使用 RESTful 风格,它会处理 http 连接和关闭,只需要提供资源的地址和参数即可

首先定义一下 RestTemplate

@Configuration
public class BeanConfig {
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

之后就可以在 service 中注入 RestTemplate 对象,然后就可以构造 http 请求了,把获取到的资源再通过指定的 ProductInfo 类型进行返回

@Service
public class OrderService {
    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private RestTemplate restTemplate;

    public OrderInfo selectOrderById(Integer orderId){
        OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
        //构建URL
        String url = "http://127.0.0.1:9090/product/" + orderInfo.getProductId();
        //通过get方式发起请求获取资源
        ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
        orderInfo.setProductInfo(productInfo);
        return orderInfo;
    }
}

通过这种方式就实现了远程调用

String url = "http://127.0.0.1:9090/product/" + orderInfo.getProductId();

不过上面的方式存在一些弊端,根据 get,post,put 等来区分对资源的操作类型并不能直观地看出来,通过抓包才能看出具体是哪种类型,不如直接把动作放在 URL 上直观

此外,还存在下面的一些问题:

  1. 由于 IP 地址是固定写的,如果 IP 地址发生了变化就需要修改代码
  2. 如果是多机部署如何处理?
  3. 返回结果怎么共用?
  4. URL 也的书写也容易出现错误
  5. 接口是对外开放的,存在一定风险

4. 注册中心的引入

针对 IP 地址改变的问题,可以通过下面的流程来解决

  1. 服务提供者(Server):一次业务中被其它微服务调用的服务,也就是提供接口给其它微服务
  2. 服务消费者(Client):一次业务中,调用其它微服务的服务,也就是调用其它微服务提供的接口
  3. 服务注册中心(Registry):用于保存 Server 的注册信息,当 Server 节点发生变更时,Registry 会同步变更,服务与注册中心使用一定机制通信,如果注册中心与某服务长时间无法通信,就会注销该实例
  4. 服务注册:服务提供者在启动时,向 Registry 注册自身服务,并向 Registry 定期发送心跳汇报存活状态。
  5. 服务发现:服务消费者从注册中心查询服务提供者的地址,并通过该地址调用服务提供者的接口。服务发现的一个重要作用就是提供给服务消费者一个可用的服务列表。

在上面的流程中,通过一个注册中心来存储应用和 IP 之间的关系,服务消费者以此来获取应用的 IP 地址,然后再去远程调用

5. CAP 理论

C:一致性(强一致性),所有节点在同一时间具有相同的数据

当客户端向数据库集群发送了一个数据修改的请求之后,数据库集群需要向客户端进行响应,此时就会有两种情况:

  1. 主数据库接收到请求并处理成功,不过数据还没有同步到从数据库,随着时间的推移会同步到从数据库
  2. 主数据库接收到请求,所有的从数据库数据同步成功时

弱一致性就是第一种情况,强一致性就是第二种情况,不论何时,主库和从库对外提供的服务都是一致的

A:可用性,保证每个请求都有响应,不过响应结果可能不对

P:分区容错性,当出现网络分区后,系统仍然能够对外提供服务

这三种特性是不能同时兼顾的,比如,在主数据库和从数据库同步数据的过程中网络出现了问题,那么这个过程就会被拉长,如果保证可用性,那么用户此时获取到的信息就不是强一致性的数据,在微服务架构中, P 是必须要保证的,所以 C 和 A 只能兼顾一个,也就是 CP 架构和 AP 架构

6. Eureka

官方文档:https://github.com/Netflix/eureka/wiki

6.1. 搭建 Eureka Server

首先再创建一个 eureka-server 的子模块

然后引入 eureka-server 的依赖和项目构建的插件

<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
  </dependency>
</dependencies>
<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
  </plugins>
</build>

接着还需要编写配置文件

server:
  port: 10010  
spring:
  application:
    name: eureka-server
eureka:
  instance:
    hostname: localhost
  client:
    fetch-registry: false # 表示是否从Eureka Server获取注册信息,默认为true.因为这是一个单点的Eureka Server,不需要同步其他的Eureka Server节点的数据,这里设置为false
    register-with-eureka: false # 表示是否将自己注册到Eureka Server,默认为true.由于当前应用就是Eureka Server,故而设置为false.
    service-url:
      # 设置与Eureka Server的地址,查询服务和注册服务都需要依赖这个地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

然后编写启动类进行启动,和之前的启动类不同的是,这里还需要加上@EnableEurekaServer注解

@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class,args);
    }
}

启动之后访问服务就可以看到注册中心的界面了:

6.2. 服务注册

把 product-service 注册到 eureka-server 中需要在 product-service 中添加客户端的依赖

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

然后配置文件也需要完善一下,把要注册的服务的名称和 eureka 的地址配置一下:

在 product-service 的 yml 文件中添加一下配置,端口号也是之前配置的 eureka 的端口号,

#Eureka Client
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10010/eureka/

然后配置服务名称

spring:
  application:
    name: product-service

接下来先启动 eureka 服务,再启动 product 服务就能够看到已经注册成功了

然后以相同的方式把 order-service 也添加到注册列表中

6.3. 服务发现

之后再进行远程调用的时候就可以从注册中心来获取要调用服务的 IP 和端口号了,需要在原来获取的方式上进行一些修改

接下来就能成功的获取到 product-service 的信息了

Eureka 和 Zookeeper 的区别:

Eureka 和 Zookeeper 都是用于服务注册和发现的工具,区别有以下几点:

  1. Eureka 是 Netflix 开源的项目,而 Zookeeper 是 Apache 开源的项目
  2. Eureka 基于 AP 原则,保证高可用,Zookeeper 基于 CP 原则,保证数据一致性
  3. Eureka 每个节点都是均等的,Zookeeper 的节点区分 Leader 和 Follower 或 Observer,由于这个原因,如果 Zookeeper 的 Leader 发生故障,需要重新选举,选举过程集群会有短暂时间的不可用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/961859.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【PowerShell专栏】实现Terminal工具的安装

微软已经发布了Windows Terminal的版本,提供各个命令操作工具的集成环境,在Windows Terminal中,我们可以集中实现多页签的各个命令方式,相比传统的命令执行分离,着实方便了不少。图为Terminal 界面: 如何实现Windows Terminal的安装呢?有好几种方式可以实现Windows Term…

从0到1:C++ 开启游戏开发奇幻之旅(二)

目录 游戏开发核心组件设计 游戏循环 游戏对象管理 碰撞检测 人工智能&#xff08;AI&#xff09; 与物理引擎 人工智能 物理引擎 性能优化技巧 内存管理优化 多线程处理 实战案例&#xff1a;开发一个简单的 2D 射击游戏 项目结构设计 代码实现 总结与展望 游戏…

九大服务构建高效 AIOps 平台,全面解决GenAI落地挑战

最近,DevOps运动的联合创始人Patrick Debois分享了他对AI平台与软件研发关系的深刻见解,让我们一起来探讨这个话题。 在AI的落地过程中,我们面临着两个主要难题: 引入AI编码工具后的开发者角色转变:随着像GitHub Copilot这样的AI工具的普及,工程师的角色正在发生深刻变革…

LangChain概述

文章目录 为什么需要LangChainLLM应用开发的最后1公里LangChain的2个关键词LangChain的3个场景LangChain的6大模块 为什么需要LangChain 首先想象一个开发者在构建一个LLM应用时的常见场景。当你开始构建一个新项目时&#xff0c;你可能会遇到许多API接口、数据格式和工具。对于…

【浏览器 - Mac实时调试iOS手机浏览器页面】

最近开发个项目&#xff0c;需要在 Mac 电脑上调试 iOS 手机设备上的 Chrome 浏览器&#xff0c;并查看Chrome网页上的 console 信息&#xff0c;本来以为要安装一些插件&#xff0c;没想到直接使用Mac上的Safari 直接可以调试&#xff0c;再此记录下&#xff0c;分享给需要的伙…

【Rust自学】15.4. Drop trait:告别手动清理,释放即安全

喜欢的话别忘了点赞、收藏加关注哦&#xff08;加关注即可阅读全文&#xff09;&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 15.4.1. Drop trait的意义 类型如果实现了Drop trait&#xff0c;就可以让程序员自定义当值…

C动态库的生成与在Python和QT中的调用方法

目录 一、动态库生成 1&#xff09;C语言生成动态库 2&#xff09;c类生成动态库 二、动态库调用 1&#xff09;Python调用DLL 2&#xff09;QT调用DLL 三、存在的一些问题 1&#xff09;python调用封装了类的DLL可能调用不成功 2&#xff09;DLL格式不匹配的问题 四、…

SpringBoot 整合 SSM

文章目录 SpringBoot 整合 SSM第一步&#xff1a;使用 Spring Initializr 创建项目第二步&#xff1a;现在配置类中配置数据库第三步&#xff1a;进行 MyBatis 相关操作编写数据表对应的实体类创建 mapper 接口利用 MyBaitsX 插件快速创建 xml 文件创建 Mapper 接口 SQL 实现在…

JVM 面试题相关总结

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

C++ unordered_map和unordered_set的使用,哈希表的实现

文章目录 unordered_map&#xff0c;unorder_set和map &#xff0c;set的差异哈希表的实现概念直接定址法哈希冲突哈希冲突举个例子 负载因子将关键字转为整数哈希函数除法散列法/除留余数法 哈希冲突的解决方法开放定址法线性探测二次探测 开放定址法代码实现 哈希表的代码 un…

JAVA实战开源项目:网上订餐系统(Vue+SpringBoot) 附源码

本文项目编号 T 039 &#xff0c;文末自助获取源码 \color{red}{T039&#xff0c;文末自助获取源码} T039&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析5.4 用例设计 六、核…

Three.js实战项目02:vue3+three.js实现汽车展厅项目

文章目录 实战项目02项目预览项目创建初始化项目模型加载与展厅灯光加载汽车模型设置灯光材质设置完整项目下载实战项目02 项目预览 完整项目效果: 项目创建 创建项目: pnpm create vue安装包: pnpm add three@0.153.0 pnpm add gsap初始化项目 修改App.js代码&#x…

【C++题解】1055. 求满足条件的整数个数

欢迎关注本专栏《C从零基础到信奥赛入门级&#xff08;CSP-J&#xff09;》 问题&#xff1a;1055. 求满足条件的整数个数 类型&#xff1a;简单循环 题目描述&#xff1a; 在 1∼n 中&#xff0c;找出能同时满足用 3 除余 2 &#xff0c;用 5 除余 3 &#xff0c;用 7 除余…

【PyTorch】6.张量形状操作:在深度学习的 “魔方” 里,玩转张量形状

目录 1. reshape 函数的用法 2. transpose 和 permute 函数的使用 4. squeeze 和 unsqueeze 函数的用法 5. 小节 个人主页&#xff1a;Icomi 专栏地址&#xff1a;PyTorch入门 在深度学习蓬勃发展的当下&#xff0c;PyTorch 是不可或缺的工具。它作为强大的深度学习框架&am…

Brave132 编译指南 Windows 篇:构建与运行(七)

1. 引言 在成功获取 Brave 浏览器 132 版本的源代码之后&#xff0c;构建和启动项目便成为开发流程中至关重要的环节。这一阶段将源代码编译链接成可执行程序&#xff0c;使您能够在本地环境中运行和测试 Brave 浏览器。Windows 平台上的构建过程可能涉及特定的工具配置和环境…

Java-多态(详解)

目录 一、多态的概念 二、多态实现的条件 示例&#xff1a; 分析&#xff1a; 三、关于Java语言中的向上转型和向下转型&#xff1a; 1.向上转型&#xff08;Upcasting&#xff09; (1).示例代码1 (2).示例代码2 2.向下转型&#xff08;Downcasting&#xff09; (1).…

unity商店插件A* Pathfinding Project如何判断一个点是否在导航网格上?

需要使用NavGraph.IsPointOnNavmesh(Vector3 point) 如果点位于导航网的可步行部分&#xff0c;则为真。 如果一个点在可步行导航网表面之上或之下&#xff0c;在任何距离&#xff0c;如果它不在更近的不可步行节点之上 / 之下&#xff0c;则认为它在导航网上。 使用方法 Ast…

node 爬虫开发内存处理 zp_stoken 作为案例分析

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 前言 主要说3种我们补环境过后如果用…

python——Django 框架

Django 框架 1、简介 Django 是用python语言写的开源web开发框架&#xff0c;并遵循MVC设计。 Django的**主要目的是简便、快速的开发数据库驱动的网站。**它强调代码复用&#xff0c;多个组件可以很方便的以"插件"形式服务于整个框架&#xff0c;Django有许多功能…

嵌入式知识点总结 Linux驱动 (五)-linux内核

针对于嵌入式软件杂乱的知识点总结起来&#xff0c;提供给读者学习复习对下述内容的强化。 目录 1.内核镜像格式有几种&#xff1f;分别有什么区别&#xff1f; 2.内核中申请内存有哪几个函数&#xff1f;有什么区别&#xff1f; 3.什么是内核空间&#xff0c;用户空间&…