yx548634898 发表于 2022-8-25 11:08

微服务系统化学习笔记

本帖最后由 yx548634898 于 2022-8-26 23:03 编辑

目前微服务比较火,自身也有用到,不过鉴于自身使用是只是未有系统化学习,所以近期想系统化学习下微服务的。立个帖子,主要目的是:
1、督促自己每日学习(不求每日大踏步,最少每日都有迈出一小步)
2、日常学习中总会有些问题与困难,想做个笔记。以便于日后查找。

楼层目录
附录:常用git命令……………………………………………5楼
实现服务远程调用-通过restTemplate实现…………6楼
注册中心-Eureka注册中心实现…………………………7楼

锤锤 发表于 2022-8-25 11:27

加油老哥,同是后端

yx548634898 发表于 2022-8-25 11:33

本帖最后由 yx548634898 于 2022-9-15 10:00 编辑

码云仓库: https://gitee.com/yanhan-git/micro-service-demom
楼层目录
实现服务远程调用-通过restTemplate实现      …………………………………………………………………      6楼码云仓库路径:https://gitee.com/yanhan-git/micro-service-demom/tree/1.1.0-resttemplate
      1)在order-service中添加user实体类
      2)在Order实体类中添加user属性值
      3)(关键)注册RestTemplate
      4)在OrderService中实现通过http服务请求获取用户信息功能
注册中心-Eureka注册中心实现      ……………………………………………………………………………………      7楼码云仓库路径:https://gitee.com/yanhan-git/micro-service-demom/tree/1.2.1-eureka
      1)搭建eureka-server(作为客户端)
                i)引入eureka依赖包(服务端)
                ii)编写启动项&开启Eureka注册中心功能
                iii)编写配置文件
      2)服务注册
                i)引入eureka依赖包(客户端)
                ii)修改application.yml配置文件
                iii)扩展知识(idea中一个应用同时启动多个服务)
      3)服务发现
                i)引入eureka依赖包(客户端)
                ii)配置文件
                iii)服务拉取和负载均衡
题外话)Eureka未配置不向自身注册或者获取信息配置踩坑说明      ………………………………      9楼
扩展、自定义SpringCloud负载均衡机制(Ribbon负载均衡)&自定义机制的方法      ……      11楼 码云仓库路径:https://gitee.com/yanhan-git/micro-service-demom/tree/1.2.EXTRA-ribbon
      1)SpringCloud负载均衡实现方式
      2)负载均衡策略
      3)自定义负载均衡策略
                i)使用在配置类中@Bean注解实现一个IRule实现方法
                ii)通过配置文件指定修改某个服务的调用规则
                iii)Ribbon加载模式修改
Nacos注册中心      …………………………………………………………………………………………………………      12楼 码云仓库路径:https://gitee.com/yanhan-git/micro-service-demom/tree/1.2.2-nacos
      1)Nacos下载&安装
      2)访问Nacos
      3)服务注册到nacos
                i)引入nacos依赖包
                ii)配置nacos地址
Nacos注册中心扩展      …………………………………………………………………………………………………      13楼 码云仓库路径:https://gitee.com/yanhan-git/micro-service-demom/tree/1.2.2-nacos
      1)服务分级存储模型
                i)配置集群
                ii)user-service应用多开(模拟)
                iii)同集群优先的负载均衡配置
      2)权重配置
      3)环境隔离
                i)创建namespace
                ii)给微服务配置namespace
      4)实例类型
                i)临时实例
                ii)非临时实例(永久实例)
Nacos和Eureka比较      …………………………………………………………………………………………………      13楼
Nacos注册中心-配置管理      …………………………………………………………………………………………………      14楼 码云仓库路径:https://gitee.com/yanhan-git/micro-service-demom/tree/1.2.2-nacos-ext
      1)统一配置管理
                i)在nacos中添加配置文件
                ii)从微服务拉取配置
      2)配置热更新
                i)添加配置动态刷新注解
                ii)使用配置属性类
      3)配置共享
                i)添加一个环境共享配置
                ii)在user-service中读取共享配置
                iii)运行两个UserApplication,使用不同的profile
      4)配置共享的优先级
Feign远程调用      …………………………………………………………………………………………………      15楼 码云仓库路径:https://gitee.com/yanhan-git/micro-service-demom/tree/1.2.3-feign-ext
      1、使用Feign替代RestTemplate
                1)引入依赖
                2)添加注解
                3)编写Feign的客户端
                4)使用 Feign 客户端进行远程调用
                5)总结
      2、自定义配置
                1)配置文件方式
                2)Java代码方式
      3、Feign直接调用url链接(为了解Feign自我测试)
      4、最佳实践
                1)继承方式
                2)抽取方式
                3)实现基于抽取的最佳实践
                        i)抽取
                        ii)在order-service中使用feign-api
                        iii)重启测试
                        iv)解决扫描包问题
      5、Feign使用优化
                1)引入依赖
                2)配置连接池
Gateway服务网关      …………………………………………………………………………………………………      16楼 码云仓库路径:https://gitee.com/yanhan-git/micro-service-demom/tree/1.2.4-gateway
      1、gateway快速入门
                1)创建gateway服务,引入依赖
                2)编写启动类
                3)编写基础配置和路由规则
                4)重启测试
                5)网关路由的流程图
      2、断言工厂
                1)断言工厂描述
                2)查看gateway官方手册
      3、过滤器工厂
                1)路由过滤器的种类
                2)请求头过滤器
                3)默认过滤器
                4)总结
      4、全局过滤器
                1)全局过滤器作用
                2)自定义全局过滤器
                3)过滤器执行顺序
      5、跨域问题
                1)什么是跨域问题
                2)模拟跨域问题
                3)解决跨域问题附录1:常用git命令      ……………………………………………………………………………………………………      5楼
      1、查看分支列表
      2、查看当前分支状态
      3、创建分支
      4、删除分支(本地)
      5、提交分支到远程仓库
      6、删除分支(远程)
      7、合并分支(将指定分支合并到当前分支,可直接合并远程分支)
      8、查看标签列表
      9、新建tag标签
      10、提交tag标签
      11、删除本地tag标签
      12、删除远程tag标签 (注意 空格)
      13、新建一个分支,指向某个tag标签
附录2:Eureka配置详解(网络资料引用仅作参考)      ………………………………………………      10楼

coolcalf 发表于 2022-8-25 11:39

加油!

.net 系的话,或许我能帮点小忙~

yx548634898 发表于 2022-8-26 12:10

本帖最后由 yx548634898 于 2022-8-27 15:58 编辑

# 附录1:常用git命令

## 1、查看分支列表

​        **git命令详解**

```shell
# 列出所有本地分支
git branch
# 列出所有远程分支
git branch -r
# 列出所有本地分支和远程分支
git branch -a
```

​        **具体示例**

```shell
Administrator@Administrator MINGW64 /d/DevWorkSpaces/cloud-demo (feature-resttemplate)
$ git branch
feature-eureka
* feature-resttemplate
master

Administrator@Administrator MINGW64 /d/DevWorkSpaces/cloud-demo (feature-resttemplate)
$ git branch -r
origin/feature-eureka
origin/feature-resttemplate
origin/master

Administrator@Administrator MINGW64 /d/DevWorkSpaces/cloud-demo (feature-resttemplate)
$ git branch -a
feature-eureka
* feature-resttemplate
master
remotes/origin/feature-eureka
remotes/origin/feature-resttemplate
remotes/origin/master

Administrator@Administrator MINGW64 /d/DevWorkSpaces/cloud-demo (feature-resttemplate)
$

```

​        其中,分支前的*表示当前处在哪个分支

## 2、查看当前分支状态

​        **git命令详解**

```shell
# 查看状态
git status
# 查看状态 使输出信息更加简洁
git status –s
```

​        **具体示例**

​        存在未提交文件

```shell
Administrator@Administrator MINGW64 /d/DevWorkSpaces/cloud-demo (feature-resttemplate)
$ git status
On branch feature-resttemplate
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
      modified:   readme.md

no changes added to commit (use "git add" and/or "git commit -a")

Administrator@Administrator MINGW64 /d/DevWorkSpaces/cloud-demo (feature-resttemplate)
$ git status -s
M readme.md
```

​        无任何需要提交文件

```shell
Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (feature-test)
$ git status
On branch feature-test
nothing to commit, working tree clean

Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (feature-test)
$ git status -s

Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (feature-test)
```

## 3、创建分支

​        **git命令详解**

```shell
# 创建分支
git branch <分支名>
```

​        **具体示例**

```shell
Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (master)
$ git branch feature-test

Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (master)
```

## 4、删除分支(本地)

​        **git命令详解**

```shell
# 删除分支(如果分支已经修改过,则不允许删除)
git branch -d<分支名>
# 强制删除分支
git branch -D<分支名>
```

​        **具体示例**

```shell
Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (master)
$ git branch -d feature-test
Deleted branch feature-test (was 89a11e6).
```

```shell
Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (master)
$ git branch -d feature-test
error: The branch 'feature-test' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature-test'.

Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (master)
$ git branch -D feature-test
Deleted branch feature-test (was 4546a15).
```

## 5、提交分支到远程仓库

​        **git命令详解**

```shell
# 提交分支至远程仓库
git push <仓库简称> <分支名称>
```

​        **具体示例**

```shell
Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (feature-test)
$ git push origin feature-test
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
remote: Powered by GITEE.COM
remote: Create a pull request for 'feature-test' on Gitee by visiting:
remote:   https://gitee.com/yanhan-git/micro-service-demom/pull/new/yanhan-git:feature-test...yanhan-git:master
To https://gitee.com/yanhan-git/micro-service-demom.git
*       feature-test -> feature-test
```

## 6、删除分支(远程)

​        **git命令详解**

```shell
# 删除远程仓库分支
git push <仓库简称> –d <分支名称>
```

​        **具体示例**

```shell
Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (feature-test)
$ git push origin -d feature-test
remote: Powered by GITEE.COM
To https://gitee.com/yanhan-git/micro-service-demom.git
-          feature-test
```

## 7、合并分支(将指定分支合并到当前分支,可直接合并远程分支)

​        **git命令详解**

```shell
# 合并分支 将其他分支合并至当前工作区
git merge <分支名称>
```

​        **具体示例**

```shell
Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (feature-test)
$ git branch -a
* feature-test
master
remotes/origin/HEAD -> origin/master
remotes/origin/feature-eureka
remotes/origin/feature-resttemplate
remotes/origin/feature-test
remotes/origin/master

Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (feature-test)
$ git merge remotes/origin/feature-resttemplate
Updating 89a11e6..4546a15
Fast-forward
assets/1661432091821.png                           | Bin 0 -> 13973 bytes
……中间省略大量记录……
assets/1661459606134.png                           | Bin 0 -> 15136 bytes
.../java/cn/yanhan/order/OrderApplication.java   |   7 ++
.../java/cn/yanhan/order/mapper/OrderMapper.java   |   3 +-
.../src/main/java/cn/yanhan/order/pojo/Order.java|   6 +-
.../src/main/java/cn/yanhan/order/pojo/User.java   |10 +++
.../java/cn/yanhan/order/service/OrderService.java |18 ++++-
order-service/src/main/resources/application.yml   |   6 +-
readme.md                                          |75 +++++++++++++++++++--
.../src/main/java/cn/yanhan/user/pojo/User.java    |   2 +-
20 files changed, 116 insertions(+), 11 deletions(-)
create mode 100644 assets/1661432091821.png
……中间省略大量记录……
create mode 100644 assets/1661459606134.png
create mode 100644 order-service/src/main/java/cn/yanhan/order/pojo/User.java

Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (feature-test)
$ git push origin -d feature-test
remote: Powered by GITEE.COM
To https://gitee.com/yanhan-git/micro-service-demom.git
-          feature-test
```

## 8、查看标签列表

​        **git命令详解**

```shell
# 列出所有tag
git tag
# 查看tag详细信息
git show
```

​        **具体示例**

```shell
Administrator@Administrator MINGW64 /d/DevWorkSpaces/cloud-demo (master)
$ git tag
0.0.0-initialize

Administrator@Administrator MINGW64 /d/DevWorkSpaces/cloud-demo (master)
$ git show 0.0.0-initialize
tag 0.0.0-initialize
Tagger: YanHan <YanHan>
Date:   Thu Aug 25 10:48:14 2022 +0800

初始化版本标签

commit 9c4b707304985d2e6a080b1776600fb32ea6a801 (tag: 0.0.0-initialize)
Author: YanHan <YanHan>
Date:   Tue Aug 23 00:43:45 2022 +0800

    项目初始化
:
tag 0.0.0-initialize
Tagger: YanHan <YanHan>
Date:   Thu Aug 25 10:48:14 2022 +0800

初始化版本标签

commit 9c4b707304985d2e6a080b1776600fb32ea6a801 (tag: 0.0.0-initialize)
Author: YanHan <YanHan>
Date:   Tue Aug 23 00:43:45 2022 +0800

    项目初始化

```

## 9、新建tag标签

​        **git命令详解**

```shell
# 新建一个tag
git tag
# 新建一个tag,并添加描述信息
git tag -m
```

​        **具体示例**

```shell
Administrator@Administrator MINGW64 /d/DevWorkSpaces/cloud-demo (master)
$ git tag 1.1.0-resttemplate -m "服务远程调用-通过RestTemplate实现http请求方式的远程调用"

Administrator@Administrator MINGW64 /d/DevWorkSpaces/cloud-demo (master)
```

## 10、提交tag标签

​        **git命令详解**

```shell
# 提交指定tag
$ git push [仓库简称]
```

​        **具体示例**

```shell
Administrator@Administrator MINGW64 /d/DevWorkSpaces/cloud-demo (master)
$ git push origin 1.1.0-resttemplate
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 225 bytes | 225.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
remote: Powered by GITEE.COM
To https://gitee.com/yanhan-git/micro-service-demom.git
*          1.1.0-resttemplate -> 1.1.0-resttemplate
```

## 11、删除本地tag标签

​        **git命令详解**

```shell
# 删除本地tag
$ git tag -d
```

​        **具体示例**

```shell
Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (master)
$ git tag 0.0.1-test -m "测试用tag"

Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (master)
$ git tag -d 0.0.1-test
Deleted tag '0.0.1-test' (was 0c61498)
```

## 12、删除远程tag标签 (注意 空格)

​        **git命令详解**

```shell
# 删除远程tag (注意 空格)
$ git push origin :refs/tags/
# 删除远程tag (注意 空格)
$ git push origin -d
```

​        **具体示例**

```shell
Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (master)
$ git push origin :refs/tags/0.0.1-test
remote: Powered by GITEE.COM
To https://gitee.com/yanhan-git/micro-service-demom.git
-          0.0.1-test


Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (master)
$ git push origin -d 0.0.1-test
remote: Powered by GITEE.COM
To https://gitee.com/yanhan-git/micro-service-demom.git
-          0.0.1-test
```

## 13、新建一个分支,指向某个tag标签

​        **git命令详解**

```shell
# 新建一个分支,指向某个tag
$ git checkout -b
```

​        **具体示例**

```shell
Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (master)
$ git tag
0.0.0-initialize

Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (master)
$ git branch
* master

Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (master)
$ git checkout -b feature-test 0.0.0-initialize
Switched to a new branch 'feature-test'

Administrator@Administrator MINGW64 /d/DevWorkSpaces/版本情况验证/micro-service-demom (feature-test)

```

​        根据tag标签创建分支,并切换到新建分支下

yx548634898 发表于 2022-8-26 15:11

本帖最后由 yx548634898 于 2022-8-26 23:01 编辑

# 实现服务远程调用

​      user-service、order-service两模块数据彼此隔离,现需实现order-service通过userid关联获取用户信息

## 通过restTemplate实现

​      **原理:**既然服务可以通过http服务地址访问,则可使用RestTemplate(Spring自带的http请求工具来实现)在order-service中通过http://localhost:8081/user/1服务地址获取用户信息。

### 1)在order-service中添加user实体类


### 2)在Order实体类中添加user属性值

!(assets/1661433228830.png)

### 3)(关键)注册RestTemplate

​      需要将RestTemplate注册到启动类中,在项目启动时加载RestTemplate的bean。否则会出现的异常。

> Field restTemplate in cn.yanhan.order.service.OrderService required a bean of type 'org.springframework.web.client.RestTemplate' that could not be found.

​      在启动类OrderApplication中注册RestTemplate bean。

```
    @Bean
    public RestTemplate restTemplate () {
      return new RestTemplate();
    }
```

### 4)在OrderService中实现通过http服务请求获取用户信息功能

```
      // 1. 查询订单
      //return orderMapper.findById(id);
    Order order = orderMapper.findById(id);
    // 2. 远程调用。利用RestTemplate发起http请求,查询用户
    // 2.1. 拼接url地址 http://localhost:8081/user/{userId}
    String url = "http://localhost:8081/user/" + order.getUserId();
    // 2.2.发送http请求,实现远程调用
    User user = restTemplate.getForObject(url, User.class); // 通过url服务获取数据,并将数据转换为USER类型
    // 3.封装user到Order
    order.setUser(user);
    // 4.返回
    return order;
```

### 结果

!(assets/1661459606134.png)

yx548634898 发表于 2022-8-26 22:46

本帖最后由 yx548634898 于 2022-8-27 16:12 编辑

# 注册中心

## 1、Eureka注册中心

​      通过RestTemplate使用http请求的方式调用远程服务,业务需明确知道对应服务IP端口信息等问题,如有多个服务负载均衡,相对不便(通过Nginx也可变通实现负载均衡,此处不做讲解),而且代码不美观。

- order-service在发起远程调用的时候,该如何得知user-service实例的ip地址和端口?
- 有多个user-service实例地址,order-service调用时该如何选择?
- order-service如何得知某个user-service实例是否依然健康,是不是已经宕机?

​      为更好的解决上述问题,引入SpringCloud的注册中心功能。其中最广为人知的注册中心就是Eureka,其结构如下:

!(assets/1661503403061.png)



### 1)搭建eureka-server(作为服务端)

​      新建模块命名为eureka-server

#### i)引入eureka依赖包(服务端)

```xml
      <!-- Eureka服务端依赖包 -->
      <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
      </dependency>
```

​      **特别说明:**Eureka为Springcloud服务,依赖于SpringCloud依赖包,本项目就是使用SpringCloud搭建微服务项目,故须在父模块的pom.xml中添加SpringCloud依赖包,以便于子模块都能使用到该依赖包

```xml
            <!-- springCloud 依赖包,使用SpringCloud组件需要添加本依赖。如:Eureka就需要依赖于这个包。-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
```

另外:SpringCloud与SpringBoot有版本依赖关系

!(assets/1661506572518.png)

#### ii)编写启动项&开启Eureka注册中心功能

​      编写个SpringBoot启动项。

​      **特别说明:**启动项需添加@EnableEurekaServer注解,从而达到开启eureka的注册中心功能的目的。

```java
package cn.yanhan.eureka;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer //开启Eureka服务功能
@SpringBootApplication
public class EurekaApplication {
    public static void main(String[] args) {
      SpringApplication.run(EurekaApplication.class, args);
    }
}
```

#### iii)编写配置文件

​      SpringBoot项目必不可少的是application.yml配置文件,在配置文件中配置Eureka服务信息

```yaml
server:
port: 10086
spring:
application:
    name: eureka-server
eureka:
client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
```

​      完成上述最简单的SpringBoot三步走,就可以启动一个最简单的Eureka服务了。效果

!(assets/1661508047641.png)

### 2)服务注册

​      如上,Eureka搭建好后,其他服务想要通过Eureka进行管理的,只需把服务信息送给Eureka即可。此处叫做服务注册。

#### i)引入eureka依赖包(客户端)

​      本项目user-service需要请,eureka进行服务管理,在user-service的pom.xml中添加依赖包

```xml
<!--      <!– Eureka客户端依赖包(不是导入这个别错了) –>-->
<!--      <dependency>-->
<!--            <groupId>org.springframework.cloud</groupId>-->
<!--            <artifactId>spring-cloud-netflix-eureka-client</artifactId>-->
<!--      </dependency>-->
      <!-- Eureka客户端依赖包 -->
      <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
      </dependency>
```

​      注意:有两个相似的包,别导错了。

#### ii)修改application.yml配置文件

​      在user-serviceapplication.yml配置中添加eureka服务地址信息,达到将服务注册到eureka的目的。

```xml
      <!-- Eureka客户端依赖包 -->
      <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-netflix-eureka-client</artifactId>
      </dependency>
```

重载下项目,重启服务即可在eureka中看到user-service服务了。

#### iii)扩展知识(idea中一个应用同时启动多个服务)

> 右键需要启动多个的应用。选择“复制配置... Ctrl+D”,弹出应用配置。

!(assets/1661509781905.png)

> 在“VM选项”中添加新的端口配置,避开已使用的端口。配置示例: -Dserver.port=8082

!(assets/1661509906417.png)

​      查看eureka页面即可看到多个服务

!(assets/1661510056142.png)

​      注:上图Application下面的名字为unknown,说明我们的user-service服务中忘记配置服务名了。配置下。

```yml
spring:
datasource:
    url: jdbc:mysql://localhost:3306/cloud_user?useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver # 需要在pom中导入驱动包
application: # 此处漏了
    name: userserver
```

​      重启服务,看eureka页面结果

!(assets/1661510658005.png)

!(assets/1661510708506.png)

!(assets/1661510738690.png)

​      Eureka服务地址不会直接删除之前注册的服务,只有在客户端服务心跳测试后,会删除。(理论是30秒一次心跳,本次观察好像不止30秒)。

​      又是三步走,搭好了user-service服务。

### 3)服务发现

​      上文两点,搭好了Eureka以及user-service。现在就要搭下使用服务使用方order-service的服务了。

​      此处我们需要从Eureka注册中心中拉取所需服务。也是三步走。

#### i)引入eureka依赖包(客户端)

​      和uer-service一样,对于eureka来说,他们都是客户端(Eureka服务的使用者、消费者)。所以在pom.xml中引入eureka依赖包(客户端)

```xml
      <!-- Eureka客户端依赖包 -->
      <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
      </dependency>
```

#### ii)配置文件

​      服务发现也需要知道eureka地址,因此第二步与服务注册一致,都是配置eureka信息:

​      在order-service中,修改application.yml文件,添加服务名称、eureka地址:

```yaml
eureka:
client:
    service-url: # 配置eureka地址信息,达到将服务注册到eureka的目的
      defaultZone: http://127.0.0.1:10086/eureka
```

​      不加配置信息的化,order-service不知道去哪个服务地址拿服务信息

#### iii)服务拉取和负载均衡

​      我们从eureka-server中拉取user-service服务的实例列表,并且实现负载均衡。此处仅需使用注解即可。

​      在order-service的OrderApplication中,给RestTemplate这个Bean添加一个@LoadBalanced注解

```java
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate () {
      return new RestTemplate();
    }
```

​      修改order-service服务中的cn.yanhan.order.service包下的OrderService类中的queryOrderById方法。用服务名代替ip、端口:

```java
    public Order queryById (Long id) {
      // 1. 查询订单
      //return orderMapper.findById(id);
      Order order = orderMapper.findById(id);
      // 2. 远程调用。利用RestTemplate发起http请求,查询用户
      // 2.1. 拼接url地址 http://localhost:8081/user/{userId}
      //String url = "http://localhost:8081/user/" + order.getUserId();
      String url = "http://userserver/user/" + order.getUserId(); // 用eureka上看到的服务名替代localhost:8081
      // 2.2.发送http请求,实现远程调用
      User user = restTemplate.getForObject(url, User.class); // 通过url服务获取数据,并将数据转换为USER类型
      // 3.封装user到Order
      order.setUser(user);
      // 4.返回
      return order;
    }
```

​      结果:

!(assets/1661521567295.png)

yx548634898 发表于 2022-8-26 22:57

eureka注册中心示例,码云源码:https://gitee.com/yanhan-git/micro-service-demom/tree/1.2.1-eureka

yx548634898 发表于 2022-8-27 15:37

#### 题外话)Eureka未配置不向自身注册或者获取信息配置踩坑说明

​      因为application.yml配置文件在项目启动之初就回去加载,如果Eureka未配置不向自身注册或者获取信息。在项目运行之初就会有报错。项目会在“未成功注册”或者“未成功获取到注册信息”时,不断的发起“Getting all instance registry info from the eureka server”获取请求。

​      此时就会出现项目启动之初报错,项目启动好后,无其他异常报错的情况而且功能也无任何异常。

​      具体启动日志如下:

```java
2022-08-27 15:00:37.361INFO 13184 --- [         main] com.netflix.discovery.DiscoveryClient    : Getting all instance registry info from the eureka server
2022-08-27 15:00:39.426INFO 13184 --- [         main] c.n.d.s.t.d.RedirectingEurekaHttpClient: Request execution error. endpoint=DefaultEndpoint{ serviceUrl='http://127.0.0.1:10086/eureka/}, exception=java.net.ConnectException: Connection refused: connect stacktrace=com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused: connect
```

​      项目启动好后,还会多次"Getting all instance registry info from the eureka server"获取信息

```java
2022-08-27 15:00:39.692INFO 13184 --- [         main] cn.yanhan.eureka.EurekaApplication       : Started EurekaApplication in 5.403 seconds (JVM running for 5.899)
      ……中间省略多字……
2022-08-27 15:01:39.482INFO 13184 --- com.netflix.discovery.DiscoveryClient    : Getting all instance registry info from the eureka server
      ……中间省略多字……
2022-08-27 15:02:09.512INFO 13184 --- com.netflix.discovery.DiscoveryClient    : Getting all instance registry info from the eureka server
      ……中间省略多字……
```

​      这很影响对项目的BUG的分析定位,这里添加两个配置,避免启动时报错。

```yaml
server:
port: 10086
spring:
application:
    name: eurekaserver
eureka:
client:
    service-url: # 配置eureka地址信息,达到将服务注册到eureka的目的
      defaultZone: http://127.0.0.1:10086/eureka
    # 是否向注册中心注册自己,缺省: true, 一般情况下,Eureka服务端是不需要再注册自己的
    register-with-eureka: false
    # 是否从Eureka获取注册信息,缺省: true
    # 一般情况下,Eureka服务端是不需要的
    fetch-registry: false
```

​      效果

!(assets/1661585701834.png)

yx548634898 发表于 2022-8-27 15:42

本帖最后由 yx548634898 于 2022-8-27 15:48 编辑

# 附录:Eureka配置详解(网络资料引用仅作参考)
参考引用自: https://blog.csdn.net/qq_37604054/article/details/121068579
正确性尚未考证,仅作参考
```yaml
eureka:
      # 实例配置
instance:
    # 客户端在注册时使用自己的IP而不是主机名,缺省: false
    prefer-ip-address: true
    # 用实例IP
    ip-address: ${spring.cloud.client.ip-address}
    # Eureka客户端向服务端发送心跳的时间间隔,单位: 秒,默认: 30
    lease-renewal-interval-in-seconds: 30
    # Eureka服务端在收到最后一次心跳之后等待的时间上限,单位为秒。
    # 超过该时间之后服务端会将该服务实例从服务清单中剔除,从而禁止服务调用请求被发送到该实例上
    lease-expiration-duration-in-seconds: 90
    # ????????spring.application.name?????????unknown
    appname: eureka-server
    # 服务名,默认取spring.application.name的配置值,如果没有则为unknown
    hostname: localhost
    # 状态页面的URL,相对路径,默认使用 HTTP 访问,如需使用 HTTPS则要使用绝对路径配置,默认: /info
    status-page-url-path: /info
    # 健康检查页面的URL,相对路径,默认使用 HTTP 访问,如需使用 HTTPS则要使用绝对路径配置,默认: /health
    health-check-url-path: /health
# 客户端配置
client:
    # Eureka服务器的地址,类型为HashMap,默认的Key为 defaultZone;默认的Value为 http://localhost:8761/eureka
    # 如果服务注册中心为高可用集群时,多个注册中心地址以逗号分隔。
    service-url:
      defaultZone: http://localhost:8762/eureka
    # 是否向注册中心注册自己,缺省: true, 一般情况下,Eureka服务端是不需要再注册自己的
    register-with-eureka: true
    # 是否从Eureka获取注册信息,缺省: true
    # 一般情况下,Eureka服务端是不需要的
    fetch-registry: true
    # 客户端拉取服务注册信息间隔,单位: 秒,缺省: 30
    registry-fetch-interval-seconds: 30
    # 是否启用客户端健康检查
    healthcheck:
      enabled: false
    # 更新实例信息的变化到Eureka服务端的间隔时间,单位为秒
    instance-info-replication-interval-seconds: 30
    # 初始化实例信息到Eureka服务端的间隔时间,单位为秒
    initial-instance-info-replication-interval-seconds: 30
    # 轮询Eureka服务端地址更改的间隔时间,单位为秒。当我们与Spring CLoud Config整合,
    # 动态刷新Eureka的serviceURL地址时需要关注该参数
    eureka-service-url-poll-interval-seconds: 300
    # 读取Eureka Server信息的超时时间,单位为秒
    eureka-server-read-timeout-seconds: 30
    # 链接Eureka Server的超时时间,单位为秒
    eureka-server-connect-timeout-seconds: 5
# server端配置
server:
    # 是否允许开启自我保护模式,当eureka服务器在短时间丢失过多客户端时,
    # 自我保护模式可以使服务端不在删除失去连接的客户端,默认: true
    enable-self-preservation: true
    # Peer节点更新间隔,单位毫秒
    peer-eureka-nodes-update-interval-ms: 4000
    # eureka服务器清理无效节点的时间间隔,单位: 毫秒,默认: 60000
    eviction-interval-timer-in-ms: 60000
```
页: [1] 2
查看完整版本: 微服务系统化学习笔记