1,SpringCloud的介绍:

  • SpringCloud是目前国内使用最广泛的微服务框架;官网地址:https://spring.io/
  • SpringCloud集成了各种微服务功能组件,并基于SpringBoot实现了这些组件的自动装配,从而实现了开箱即用的体验;
    • 服务注册发现:Eureka,Nacos,Consul;
    • 服务远程调用:OpenFegin,Dubbo;
    • 服务链路监控:Zipkin,Sleuth;
    • 统一配置管理:SpringCloudConfig,Nacos;
    • 统一网关路由:SpringCloudGateway,Zuul;
    • 流控,降级,保护:Hystix,Sentinel;

      使用的相关组件;


2,SpringCloud与SpringBoot的版本对应:

image.png


3,服务拆分和远程调用:

3.1,服务拆分:

3.1.1,服务拆分的注意事项:

  1. - **不同的微服务,不能重复开发相同的业务;**
  2. - **微服务数据独立,不允许访问其他微服务的数据库;(不允许跨库查询)**
  3. - ** 可以暴露自己的业务接口,以提供给其他微服务使用;实现获得其他微服务数据的目的;**
  4. - **常用的方法:封装两个微服务中的共同数据属性到实体类中进行组合,通过该属性即可获取到需要的数据;**

3.2,* 微服务的远程调用:RestTemplate

3.2.1,远程调用方式分析:

让其中一个服务A暴露自己的接口,由另外一个服务B以发送http的方式进行访问,调用这个接口就能返回B查询到的数据到A中进行组装,就能实现所有数据的获取(查询);

3.2.2,在服务启动类(配置类)中注册RestTemplate:

将RestTemplate对象注入到Spring容器;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

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

3.2.3,在Service中注入并调用restTemplate实现远程调用:

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private RestTemplate restTemplate;

    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        // 2.使用RestTemplate远程调用用户服务获取用户信息
        String url = "http://localhost:8081/user/" + order.getUserId();
        User user = restTemplate.getForObject(url, User.class);
        // 3.将用户信息填充到order对象中
        order.setUser(user);
        // 4.返回
        return order;
    }
}

3.2.4,提供者user-service和消费者order-service:

     - **服务提供者:在一次业务中,被其他微服务调用的服务(提供接口的服务)** ![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651973767801-5bf38f64-f951-4e11-929e-dba2f296872f.png#clientId=u5986faf8-188a-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=258&id=u4b0c8a2e&margin=%5Bobject%20Object%5D&name=image.png&originHeight=301&originWidth=232&originalType=binary&ratio=1&rotation=0&showTitle=false&size=8592&status=done&style=none&taskId=u75a22b0a-0c26-42cd-93c3-2684d70e545&title=&width=199) **提供者结构**
     - **服务消费者:在一次业务中,调用其他微服务的服务(调用接口的服务)**![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651973733131-2ccbb993-0b0c-4c99-9a3a-e066beef26b6.png#clientId=u5986faf8-188a-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=245&id=u40cf7e53&margin=%5Bobject%20Object%5D&name=image.png&originHeight=336&originWidth=247&originalType=binary&ratio=1&rotation=0&showTitle=false&size=9419&status=done&style=none&taskId=ua66d62b8-02b9-4b06-9e68-069bec8148e&title=&width=180)** 消费者结构;**

4,▲ Eureka注册中心:

4.1,服务调用出现的问题:

在集群中,出现多个服务接口的时候;

  - 服务消费者如何获取服务提供者的地址信息?
  - 服务消费者如何选择接口?
  - 消费者如何得知提供者的健康状态?

4.2,Eureka注册中心的作用:

对上述问题的解答:

  - **服务消费者如何获取服务提供者的地址信息?**
     - 消费者启动时向eureka注册自己的信息;
     - eureka保存这些信息;
     - 消费者根据服务名称向eureka拉取提供者信息;
  - **服务消费者如何选择接口?**
     - 消费者会利用负载均衡算法,从服务列表中挑选一个;
  - **消费者如何得知提供者的健康状态?**
     - 提供者会每隔**30秒**向EurekaService发送心跳请求,报告健康状态;
     - eureka会更新记录服务列表信息,心跳不正常的会被剔除;
     - 消费者就能拉取到最新的信息;
     - 就能避免,消费者拉取到不健康的提供者接口导致宕机的问题;

4.3,Eureka架构中的微服务角色:

有两类:

  1. **EurekaServer:注册中心,服务端**
     1. **记录服务信息;**
     1. **心跳监控;**
  2. **EurekaClient:客户端**
     1. **Provider:服务提供者**
        1. **注册自己的信息到EurekaServer;**
        1. **每隔30秒发送健康状态到EurekaServer;**
     2. **consumer:服务消费者**
        1. **根据服务名称在EurekaServer拉取服务列表;**
        1. **基于服务列表做负载均衡,选中一个微服务然后发起远程调用;**

Ribbon将请求拦下来对其进行处理,Ribbon将请求拦截下来后,会到eureka-server注册中心去根据拉取的服务名称找到映射的服务列表并返回到Ribbon,再通过负载均衡来挑选服务接口实例ip,再将发起的请求中的服务名称利用该实例ip进行替换就能发起真正的服务访问请求;

image.png

4.4,* Eureka注册中心的使用:

4.4.1,搭建Eureka服务:EurekaServer

     1. **导入依赖:spring-cloud-starter-netflix-eureka-server**
<!-- 添加eureka服务端 -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
     2. **编写启动类:**
     - 要在启动类上加上@EnableEurekaServer注解;开启注册中心的功能;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
//开启Eureka服务的注解
@EnableEurekaServer
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}
     3. **编写配置文件:**
     - 编写一个application . yml 文件;
        1. 服务器端口号;
        1. 服务器的服务名称;
        1. 注册中心的访问地址;
# 服务器端口号
server:
port: 10086
spring:
application:
# 服务器的服务名称
name: eureka-server
# 注册中心服务的访问地址
eureka:
client:
service-url: 
      # defaultZone需要手动敲上去,并且URL地址前面有空格
      defaultZone: http://127.0.0.1:10086/eureka
     - **启动服务:**
        - 启动微服务,然后在浏览器访问:http://127.0.0.1:10086

4.4.2,Eureka服务注册:

在服务消费者的模块中进行;

     1. **导入依赖:**
<!-- 注册eureka客户端 -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
     2. **配置文件:**
# 写在spring的配置部分中
spring:
application:
name: userservice
# 指定服务器端的访问地址
eureka:
client:
service-url:
      defaultZone: http://127.0.0.1:10086/eureka
     3. **启动多个服务消费者实例:**
        - 为了演示一个服务有多个实例的场景,我们添加一个SpringBoot的启动配置,再启动一个user-service。

        1. 首先将现前的UserApplication的配置名字改成UserApplication8081![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651722515356-29cc5278-9d33-4982-93ae-f41f1551dc61.png#clientId=u1a84f612-85d4-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=295&id=u483f9f00&margin=%5Bobject%20Object%5D&name=image.png&originHeight=295&originWidth=701&originalType=binary&ratio=1&rotation=0&showTitle=false&size=116357&status=done&style=none&taskId=u9747c18e-7ddc-4f11-aae7-787e978af86&title=&width=701)
        2. 输入新的名字![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651722545416-ccfd3ca1-84e9-496f-be05-765a52f3c334.png#clientId=u1a84f612-85d4-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=283&id=uba34b3b9&margin=%5Bobject%20Object%5D&name=image.png&originHeight=396&originWidth=942&originalType=binary&ratio=1&rotation=0&showTitle=false&size=94126&status=done&style=none&taskId=ub36fc990-b18f-4a6a-851d-87c5a781392&title=&width=673)
        2. 复制原来的user-service启动配置:![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651722567094-7519b12d-a365-4b7a-8cc1-64b8777ebde5.png#clientId=u1a84f612-85d4-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=194&id=ufa0221a8&margin=%5Bobject%20Object%5D&name=image.png&originHeight=194&originWidth=764&originalType=binary&ratio=1&rotation=0&showTitle=false&size=94640&status=done&style=none&taskId=u7fc4c81f-1c80-41cb-a666-414293e3de8&title=&width=764)
        2. 然后,在弹出的窗口中,填写信息:![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651722671889-99df8e09-5e3d-4018-8f44-357030713d06.png#clientId=u1a84f612-85d4-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=438&id=u344995ba&margin=%5Bobject%20Object%5D&name=image.png&originHeight=438&originWidth=603&originalType=binary&ratio=1&rotation=0&showTitle=false&size=92528&status=done&style=none&taskId=ud1e521f7-7e89-479b-9f11-1ed327dcb84&title=&width=603)

-Dserver . port=8082

        5. 现在,SpringBoot窗口会出现两个user-service启动配置:![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651722679761-f120929a-01b7-42d3-b482-8d60af0b09b4.png#clientId=u1a84f612-85d4-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=226&id=uf0a85403&margin=%5Bobject%20Object%5D&name=image.png&originHeight=226&originWidth=458&originalType=binary&ratio=1&rotation=0&showTitle=false&size=72183&status=done&style=none&taskId=u2c73d07d-efde-4374-b576-942d4de004e&title=&width=458)
           1. 第一个是8081端口,第二个是8082端口。
           1. 需要重新启动**两个**userservice实例:![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651722686716-59a09695-1266-4a46-8236-277741ce9ac8.png#clientId=u1a84f612-85d4-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=190&id=ue2f1ce2b&margin=%5Bobject%20Object%5D&name=image.png&originHeight=190&originWidth=438&originalType=binary&ratio=1&rotation=0&showTitle=false&size=61250&status=done&style=none&taskId=ubf798ea4-0b19-4f19-a45f-58e49b79caa&title=&width=438)
        6. 刷新查看eureka-server管理页面:![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651722694421-01606e0f-27fa-4d36-8042-d666c9dc4fe2.png#clientId=u1a84f612-85d4-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=191&id=ua523b690&margin=%5Bobject%20Object%5D&name=image.png&originHeight=191&originWidth=1276&originalType=binary&ratio=1&rotation=0&showTitle=false&size=65364&status=done&style=none&taskId=u81ec5590-059a-48d6-87d9-1d2769ddfa7&title=&width=1276)

4.4.3,服务发现:

     - **接着,对order-service的逻辑进行一个修改:向eureka-service拉取user-service的信息,实现服务发现;**
     1. **导入依赖:spring-cloud-starter-netflix-eureka-client**
<!-- eureka客户端 -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
     2. **配置文件:**
        1. **添加提供者的服务名称;**
        1. **eureka服务端地址同上;**
# 配置在spring的前缀中
spring:
application:
name: orderservice
# 配置服务器的访问地址
eureka:
client:
service-url:
      defaultZone: http://127.0.0.1:10086/eureka
     3. **服务拉取和负载均衡:**
        1. **最后,要去eureka-server中拉取user-service服务(服务提供者)的服务列表,并且实现负载均衡;**
        1. **在order-service中的启动类给RestTemplate这个bean加上@LoadBalanced注解即可;**
        1. **LoadBalanced:负载均衡;**
@SpringBootApplication
@MapperScan("top.jztice5.order.mapper")
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }

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

}
     4. **修改order-service服务中的cn.itcast.order.service包下的OrderService类中的queryOrderById方法。修改访问的url路径,用服务名代替ip、端口:**
public Order queryOrderById(Long orderId) {
    // 1.查询订单
    Order order = orderMapper.findById(orderId);
    //2.获取用户id
    Long userId = order.getUserId();
    //3.使用服务名代替IP地址和端口号
    User user = restTemplate.getForObject("http://userservice/user/" + userId, User.class);
    order.setUser(user);
    // 4.返回
    return order;
}
     5. **启动orderservice服务,查看eureka管理页面:**![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651724356920-1cb4bc51-3940-4ac6-9902-fa66736d309f.png#clientId=u1a84f612-85d4-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=222&id=u6c829112&margin=%5Bobject%20Object%5D&name=image.png&originHeight=222&originWidth=1280&originalType=binary&ratio=1&rotation=0&showTitle=false&size=80787&status=done&style=none&taskId=ue6bdb2d7-ab34-41ce-9701-8639fb34144&title=&width=1280)
     5. **再次启动服务就实现了消费者与提供者的接口访问;**

5,* Ribbon负载均衡的原理:

面试用

5.1,Ribbon负载均衡的作用:

  - 将请求拦下来对其进行处理,Ribbon将请求拦截下来后,会到**eureka-server注册中心**去根据拉取的服务名称找到映射的服务列表并返回到Ribbon,再通过**负载均衡**来挑选服务接口实例ip,再将发起的请求中的服务名称利用该实例**ip进行替换**就能发起真正的服务访问请求;

image.png


5.2,Ribbon负载均衡原理图:

image.png


5.3,* Ribbon负载均衡原理:总结

5.3.1,Ribbon负载均衡是什么:

  - <br />

5.3.2,实现负载均衡的原理:

  1. <br />

6,* Ribbon负载均衡的策略:

默认的负载均衡策略是:ZoneAvoidanceRule(轮询策略)

image.png

6.1,定义负载均衡的策略:

  - 有**两种**方式:

6.1.1,代码方式:

  - 在order-service中的启动类中定义一个新的**IRule**:
     - 这种方式是**全局性**的,只要是order-service发起的请求就会按照这个策略执行负载均衡;
@Bean
//定义随机选择一个服务器的规则;
public IRule randomRule(){
 return new RandomRule();
}

6.1.2,配置文件方式:

  - 在**order-service的application.yml文件**中,添加新的配置也可以修改策略规则:
     - 这种方式是用于针对某个微服务的;**针对性**
# 指定服务提供者的服务名称;
userservice:
 ribbon:
 # 负债均衡规则;
 NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

7,Ribbon的加载:

7.1,Ribbon的默认加载方式:

  - Ribbon的**默认加载方式**为:**懒加载**,即第一次访问的时候才会去加载**LoadBalancerClient,**请求时间会很长**;**

7.2,Ribbon的饥饿加载方式:(推荐)

  - 在**饥饿加载**模式下,Ribbon会在启动项目的时候,就会完成创建,降低第一次的访问耗时;
  - **饥饿加载的开启:**
     - 在**order-service的application.yml文件**中,添加加载的配置
ribbon:
  eager-load:
    # 开启饥饿加载
    enabled:true
    # 指定对userservice这个服务设置饥饿加载
    clients:userservice

8,▲ Nacos注册中心:

Nacos的默认端口是:8848

8.1,什么是Nacos:

  - Nacos是阿里巴巴的产品,是SpringCloud的一个组件,相比Eureka的功能更丰富,在国内比较流行;
  1. **安装Nacos:**
     1. **使用Nacos前需要先安装客户端先,不像Eureka那样直接导入;**
     1. **在GitHub的下载页面:**[https://github.com/alibaba/nacos](https://github.com/alibaba/nacos);

8.2,* Nacos的启动:

  1. **打开Nacos所在的目录,进入bin文件夹,进入cmd页面,输入以下命令;**
startup.cmd -m standalone
  2. **在浏览器进入,**[http://127.0.0.1:8848/nacos](http://127.0.0.1:8848/nacos)** 就能进入到客户端页面;**
     1. **默认账户和密码都是:nacos ;**

8.3,* Nacos的使用:

Nacos是SpringCloudAlibaba的组件,而SpringCloudAlibaba也遵循SpringCloud中定义的服务注册,服务发现的规范,因此,Nacos和Eureka对于微服务来说,没有什么太大的区别;

8.3.1,将服务注册到Nacos:

     1. **导入依赖:**
        1. **在父工程的pom文件中导入SpringCloudAlibaba的依赖:**
<!-- nacos -->
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-alibaba-dependencies</artifactId>
  <version>2.2.6.RELEASE</version>
  <type>pom</type>
  <scope>import</scope>
</dependency>
        2. **在user-service和order-service的pom文件中导入nacos-discovery依赖**
<!-- nacos的服务发现 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

//注意:该依赖不能识别配置,如果要设置配置的话,要导入另外的依赖;

注意:记得要注释掉Eureka的依赖,否则会导致冲突;

     2. **配置Nacos地址:**
        1. **在user-service和order-service的application.yml文件中添加Nacos地址:**
spring:
cloud:
nacos:
      server-addr: localhost:8848

同样的也要注释掉Eureka的地址:

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
     3. **重启服务就能将服务注册到Nacos:**

image.png


8.4,Nacos的命名空间(namespace):

8.4.1,创建命名空间:略详细过程

     - ![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651820422748-64a4dfaa-0bba-42fb-b7f1-b95793bcb71e.png#clientId=ud2dc13a3-9fc1-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=361&id=uaaaf38cb&margin=%5Bobject%20Object%5D&name=image.png&originHeight=361&originWidth=812&originalType=binary&ratio=1&rotation=0&showTitle=false&size=35800&status=done&style=none&taskId=u4053fde3-27ba-442d-bddf-bc0f247db1a&title=&width=812)
     - **注意:命名空间的id要和微服务里面的配置文件一致;**

8.4.2,给微服务定义命名空间:

     1. **修改/添加配置中的命名空间:**
        1. **修改order-service的application.yml文件:**
spring:
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        namespace: 9a8ebcfe-f688-49ce-8ec3-c039e29f76a0 # 命名空间,填ID
        2. **修改user-service的application.yml文件:**
spring:
  application:
    name: userservice

  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        namespace: 9a8ebcfe-f688-49ce-8ec3-c039e29f76a0

注意:命名空间的id要和微服务里面的配置文件一致;

     - **重启服务:可见同一个命名空间内有刚刚我们设置好的实例:**
     - ![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651820631907-3babf90b-e372-496d-8940-142296088a79.png#clientId=ud2dc13a3-9fc1-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=389&id=u20f1f25a&margin=%5Bobject%20Object%5D&name=image.png&originHeight=389&originWidth=1237&originalType=binary&ratio=1&rotation=0&showTitle=false&size=90864&status=done&style=none&taskId=uaaab6f72-f836-429f-9d64-955e51d48ec&title=&width=1237)

9,Nacos和Eureka的区别:

  • Nacos与eureka的共同点
    • 都支持服务注册和服务拉取
    • 都支持服务提供者心跳的方式做健康检测
  • Nacos与Eureka的区别
    • 服务注册:Nacos的实例有永久和临时实例之分;而Eureka只支持临时实例
    • 服务发现:Nacos支持定时拉取和主动推送两种模式;Eureka只支持定时拉取模式
    • 健康检测:Nacos对临时实例采用心跳模式检测,对永久实例采用主动请求来检测;Eureka只支持心跳模式

      10,* Nacos的配置中心:

      10.1,统一配置管理:

        - **统一配置管理方案可以对所有实例配置进行集中管理;**
      

10.1.1,在nacos添加配置文件:

image.png

  - 配置内容如下:
pattern: 
  dateformat: yyyy-MM-dd HH:mm:ss

注意:需要热更新的配置才有放到nacos管理的必要,比如一些偶尔会变动的参数。基本不会变更的一些配置还是保存在微服务本地比较好。

10.1.2,微服务拉取nacos配置:

        1. 微服务要拉取nacos中管理的配置,并且与本地的application.yml配置合并,才能完成项目启动。
        1. **注意:在Spring中引入了一种新的配置文件:bootstrap.yaml文件;**
           1. **该文件会在application文件读取之前会先行读取;**![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651827422481-4809b417-8f6a-4679-bc7d-9450543cb85c.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=391&id=u18ba834c&margin=%5Bobject%20Object%5D&name=image.png&originHeight=391&originWidth=1268&originalType=binary&ratio=1&rotation=0&showTitle=false&size=99868&status=done&style=none&taskId=u9d090c82-249f-4382-959e-9dae39f9b95&title=&width=1268)
        3. **在user-service服务中,导入nacos-config的客户端依赖:**
<!--nacos配置管理依赖-->
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
        4. **在配置文件中添加bootstrap文件:(bootstrap.yaml)**
           1. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651827588010-5f5e7016-fa00-4603-a451-a3dde292f4b1.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=109&id=u9d8b10a2&margin=%5Bobject%20Object%5D&name=image.png&originHeight=109&originWidth=286&originalType=binary&ratio=1&rotation=0&showTitle=false&size=22134&status=done&style=none&taskId=ube6c31b3-d314-4fdb-b410-de976abf82c&title=&width=286)
        5. **bootstrap文件的配置如下:**
spring:
application:
name: userservice # 服务名称,注:要与文件名一致
profiles:
active: dev #开发环境,这里是dev
cloud:
nacos:
server-addr: localhost:8848 # Nacos地址
config:
        file-extension: yaml # 文件后缀名

这里会根据spring.cloud.nacos.server-addr获取nacos地址,再根据 ${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}作为文件id,来读取配置。 本例中,就是去读取userservice-dev.yaml:

image.png

因此,为什么上面的新建配置文件的文件名格式要这样进行设置;

  - **记着还有去application.yml中注释掉相关重复的配置:**
   application:
     name: userservice

   cloud:
     nacos:
       server-addr: localhost:8848
       discovery:
         namespace: a8ace27d-a737-4122-9f3f-92f5ee795b62

10.1.3,读取Nacos配置文件:

     1. 在user-service中的UserController中添加业务逻辑,读取pattern.dateformat配置:
import cn.itcast.user.pojo.User;
import cn.itcast.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @Value("${pattern.dateformat}")
    private String dateformat;

    @GetMapping("now")
    public String now(){
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
    }

}

根据ip地址:http://localhost:8081/user/now 服务页面 效果:image.png 服务接口8082也是同理;因为设置了统一配置,因此都会显示一样的效果;

10.2,* 配置热更新:

10.2.1,什么是配置热更新:

     - 我们最终的目的,是修改nacos中的配置后,微服务中无需重启即可让配置生效,也就是**配置热更新**。
     - Nacos可以在配置变更时,及时通知微服务,实现配置的热更新。

10.2.2,方式一:

     1. 在**@Value**注入的变量所在类上添加注解**@RefreshScope**:
     1. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651828364538-77cd3e1d-c6c3-4551-8bdf-8e278fc80163.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=222&id=u417d2d6a&margin=%5Bobject%20Object%5D&name=image.png&originHeight=382&originWidth=978&originalType=binary&ratio=1&rotation=0&showTitle=false&size=189145&status=done&style=none&taskId=u58c94b2c-9cb8-4132-8abf-80e9634d5f7&title=&width=568)
     1. 然后重启;
     1. 再修改配置管理中的配置:![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651828442398-5d262787-8795-4700-adaf-56b7fa49d9d5.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=333&id=u04519283&margin=%5Bobject%20Object%5D&name=image.png&originHeight=470&originWidth=791&originalType=binary&ratio=1&rotation=0&showTitle=false&size=71599&status=done&style=none&taskId=u80950ba3-b54c-4ac5-bd65-dc86b4e3be7&title=&width=560)
     1. 再次访问地址,效果如下:![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651828473214-0d2160b4-c9d5-40ef-bc70-1c8d702fce34.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=68&id=uc405df17&margin=%5Bobject%20Object%5D&name=image.png&originHeight=119&originWidth=723&originalType=binary&ratio=1&rotation=0&showTitle=false&size=37886&status=done&style=none&taskId=u5875de5e-a865-445f-a2e3-e0180b8c6cb&title=&width=412)

10.2.3,方式二:

  1. 使用**@ConfigurationProperties**注解代替@Value注解。
     1. 去掉UserController上@RefreshScope注解和@Value注解
     1. 在user-service服务的config包中添加PatternProperties类<br />a. 添加@Component注解<br />b. 添加[@ConfigurationProperties(prefix ](/ConfigurationProperties(prefix )  = "pattern")注解 <br />c. 添加String dateformat属性
package cn.itcast.user.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@Data
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
    private String dateformat;
}

注:如果出现红色警告,在user-service的pom.xml中添加以下依赖即可 image.png

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
     3. 在UserController中使用这个类,并且使用**@Autowired**注入

image.png

     4. **完整代码:**
import cn.itcast.user.config.PatternProperties;
import cn.itcast.user.pojo.User;
import cn.itcast.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    private PatternProperties patternProperties;

    @GetMapping("now")
    public String now(){
        return     LocalDateTime.now()
            .format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));
    }

}
  - 重启UserApplication微服务 
  -  再修改nacos的配置<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651828942956-382c5993-802d-4f96-8270-f33c60a8774e.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=100&id=ub9da68f4&margin=%5Bobject%20Object%5D&name=image.png&originHeight=156&originWidth=999&originalType=binary&ratio=1&rotation=0&showTitle=false&size=52062&status=done&style=none&taskId=u9cd69cab-6e6a-45ac-a06b-636d04475dc&title=&width=638) 
  -  在浏览器查看效果<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651828953364-74eebf9b-9022-411b-842b-5d3e5662c2d2.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=89&id=u92ae1b4c&margin=%5Bobject%20Object%5D&name=image.png&originHeight=126&originWidth=730&originalType=binary&ratio=1&rotation=0&showTitle=false&size=31575&status=done&style=none&taskId=u54611507-f0b8-4bc2-bfef-f4bbe1e001f&title=&width=518) 

10.3,配置共享

10.3.1,共享配置的说明:

  - 应用场景:某个配置在开发,测试,生产环境中的配置是一样的,就可以使用共享配置
  - 其实微服务启动时,会去nacos读取多个配置文件,例如:
     - `[spring.application.name]-[spring.profiles.active].yaml`,例如:userservice-dev.yaml
     - `[spring.application.name].yaml`,例如:userservice.yaml
     - 而`[spring.application.name].yaml`不包含环境,因此可以被多个环境共享。

10.3.2,测试配置共享:

1)添加一个环境共享配置:

     1. 我们在nacos中添加一个userservice.yaml文件: 
pattern: 
  envSharedValue: 大家都可以用哦

image.png

     2.  这时有两个配置文件存在<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651829147143-fd9d73b3-163b-4d94-a386-c796b78d8d24.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=214&id=u8ef76b31&margin=%5Bobject%20Object%5D&name=image.png&originHeight=428&originWidth=1132&originalType=binary&ratio=1&rotation=0&showTitle=false&size=103129&status=done&style=none&taskId=ufec72dad-d042-441b-bd71-57c3987de81&title=&width=566) 

2)在user-service中读取共享配置

     1. 在user-service服务中,修改PatternProperties类,读取新添加的属性:![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651829194709-f8533212-6cc0-430d-ab56-edec98a1d042.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=198&id=u8f8b68ca&margin=%5Bobject%20Object%5D&name=image.png&originHeight=292&originWidth=745&originalType=binary&ratio=1&rotation=0&showTitle=false&size=105354&status=done&style=none&taskId=u1014e03f-d847-42ea-85a8-3f0ba423884&title=&width=505)
     1. 在user-service服务中,修改UserController,添加一个方法,直接返回PatternProperties对象 
package cn.itcast.user.web;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private PatternProperties patternProperties;

    @GetMapping("/prop")
    public PatternProperties prop() {
        return patternProperties;
    }
}

3)运行两个UserApplication,使用不同的profile

     - 修改UserApplication8082这个启动项,改变其profile值:![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651829260214-ea466182-b22b-42cc-97c4-cf8a787fde18.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=90&id=ub925c229&margin=%5Bobject%20Object%5D&name=image.png&originHeight=151&originWidth=892&originalType=binary&ratio=1&rotation=0&showTitle=false&size=81604&status=done&style=none&taskId=u647362b8-7fa2-4ab0-b58a-ac49862c48f&title=&width=533)

注:这个test的profiles是不存在的

image.png

这样,UserApplication8081使用的profile是dev,UserApplication8082使用的profile是test。

4) 执行结果:

     - 启动UserApplication和UserApplication2
        - 访问http://localhost:8081/user/prop,结果:![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651829370299-5ed32717-b643-4660-a3c2-b643ac9fd887.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=149&id=ub21978c8&margin=%5Bobject%20Object%5D&name=image.png&originHeight=235&originWidth=695&originalType=binary&ratio=1&rotation=0&showTitle=false&size=77513&status=done&style=none&taskId=ud02e434a-b0d9-4594-ac07-424ef1a2e4c&title=&width=440)
        - 访问http://localhost:8082/user/prop,结果:![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651829396728-12f91646-28cd-45be-af38-b5cfc2f0d7b8.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=146&id=u51451d5b&margin=%5Bobject%20Object%5D&name=image.png&originHeight=231&originWidth=712&originalType=binary&ratio=1&rotation=0&showTitle=false&size=69029&status=done&style=none&taskId=u76a40e18-404c-4b3b-b717-c54ec23483e&title=&width=450)

可以看出来,不管是dev,还是test环境,都读取到了envSharedValue这个属性的值。

10.3.3.,配置共享的优先级

1. 优先级说明:

当nacos、服务本地同时出现相同属性时,优先级有高低之分:image.png

     - 服务器控制台显示:
 Located property source: [BootstrapPropertySource {name='bootstrapProperties-userservice-dev.yaml,DEFAULT_GROUP'}, BootstrapPropertySource {name='bootstrapProperties-userservice.yaml,DEFAULT_GROUP'}, BootstrapPropertySource {name='bootstrapProperties-userservice,DEFAULT_GROUP'}]

2. 演示:

     - 在PatternProperties中添加新的username属性 
@Component
@ConfigurationProperties(prefix = "pattern")
@Data
public class PatternProperties {

    private String dateformat;
    private String envSharedValue;
    private String username;
}
     - 在application.yml中添加新的username属性,查看浏览器运行效果 
pattern:
  username: 孙悟空
         ![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651829613227-95fd9193-bffe-405d-99fb-e95620215dad.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=140&id=ue49d5f2f&margin=%5Bobject%20Object%5D&name=image.png&originHeight=223&originWidth=585&originalType=binary&ratio=1&rotation=0&showTitle=false&size=78176&status=done&style=none&taskId=ub9adc886-a2a3-44fa-8a8e-8d2c2ec626e&title=&width=366)

     - 在userservice.yaml中添加新的username属性,查看浏览器运行效果  <br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651829651644-5781f88b-fb10-4e8f-8600-cb1c26d3f050.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=292&id=u3053dc49&margin=%5Bobject%20Object%5D&name=image.png&originHeight=542&originWidth=833&originalType=binary&ratio=1&rotation=0&showTitle=false&size=85830&status=done&style=none&taskId=u8ef6f348-f3ef-4fb8-9227-a9744cbcfb0&title=&width=449) ![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651829670413-4859a532-fb74-48d7-acbe-beca60dca994.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=130&id=u991c7bf8&margin=%5Bobject%20Object%5D&name=image.png&originHeight=175&originWidth=545&originalType=binary&ratio=1&rotation=0&showTitle=false&size=71247&status=done&style=none&taskId=ua58fe59e-a319-49e0-aab9-4c564733f0f&title=&width=405)
     - 在userservice-dev.xml中添加新的username属性,查看浏览器运行效果  <br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651829694397-4121283b-2b71-4497-a4db-8890abc4ecbb.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=224&id=u15bb513a&margin=%5Bobject%20Object%5D&name=image.png&originHeight=375&originWidth=802&originalType=binary&ratio=1&rotation=0&showTitle=false&size=116597&status=done&style=none&taskId=ue70fd669-9ca3-41c9-9266-eaf59d8365c&title=&width=478) 

10.4,* 搭建Nacos集群:

10.4.1,集群结构图

  - 官方给出的Nacos集群图:
  - **SLB:负载均衡器**,负责将我们的请求分发到不同的nacos节点

image.png

其中包含3个nacos节点,然后一个负载均衡器代理3个Nacos。这里负载均衡器可以使用nginx。

  - 我们计划的集群结构:
  - 三个nacos节点的地址:
节点 换成实际服务器的IP地址 port
nacos1 192.168.132.2 8845
nacos2 192.168.132.2 8846
nacos3 192.168.132.2 8847

10.4.2,搭建集群:

  - 搭建集群的基本步骤:(参考nacos集群搭建.md文档)
     - 搭建数据库,初始化数据库表结构
     - 下载nacos安装包
     - 配置nacos
     - 启动nacos集群
     - nginx反向代理

10.4.2.1),初始化数据库:

  - Nacos默认数据存储在内嵌数据库Derby中,不属于生产可用的数据库。
  - 官方推荐的最佳实践是使用带有主从的高可用数据库集群,主从模式的高可用数据库可以参考**传智教育**的后续高手课程。这里我们以单点的数据库为例来讲解。
  - 首先新建一个数据库,命名为nacos。这个表结构已经由官方提供了。

注:要使用mysql5.7以上的版本,5.5运行不了。

数据库执行资料中的sql脚本:nacos.sql

10.4.2.2),配置Nacos:

  1. 创建一个目录名为:nacos-cluster
  1. 进入目录nacos-cluster目录,重新解压安装一份新的nacos
  1. 进入nacos的conf目录,修改配置文件cluster.conf.example,重命名为cluster.conf![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651830297057-eb06129f-4826-4d1c-b870-d401100eb3b3.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=269&id=u48dbf648&margin=%5Bobject%20Object%5D&name=image.png&originHeight=410&originWidth=437&originalType=binary&ratio=1&rotation=0&showTitle=false&size=71093&status=done&style=none&taskId=ua929ba21-8908-47ba-af56-db5bdd3c47a&title=&width=287)
  - 然后添加内容,注意:此处的IP是你自己机器的IP地址,不要写成127.0.0.1,否则会导致微服务注册失败
192.168.132.2:8845
192.168.132.2:8846
192.168.132.2:8847
//此处的ip和虚拟机ip一致;

在cmd下使用ipconfig来查看自己的IP地址

  - 然后修改**application.properties**文件,修改数据库配置。
# mysql的数据库集群
spring.datasource.platform=mysql
# 数据库的数量
db.num=1
# 连接字符串
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
# 用户名
db.user.0=root
# 密码
db.password.0=root

这里的数据库地址、用户名、密码请根据实际情况配置。

10.4.2.3),启动:

  - 将nacos改名成nacos1,并且复制两份,分别命名为:nacos2、nacos3![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651830493336-d4053cbb-d88d-4114-b192-69e94f0740ec.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=100&id=u9f198d59&margin=%5Bobject%20Object%5D&name=image.png&originHeight=100&originWidth=441&originalType=binary&ratio=1&rotation=0&showTitle=false&size=11367&status=done&style=none&taskId=u97a17600-43c9-41fe-ad3d-6b48a0a7a5b&title=&width=441)

然后分别修改三个文件夹中的application.properties,大约在21行
nacos1:

server.port=8845

nacos2:

server.port=8846

nacos3:

server.port=8847
  - 然后打开三个cmd窗口,分别启动三个nacos节点,不需要带参数,默认是集群启动方式,也可以双击运行
startup.cmd

看到以下提示表示启动成功

INFO Nacos started successfully in cluster mode. use external storage

10.4.2.4),* nginx 反向代理:

  - 找到课前资料提供的nginx安装包:![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651830711544-d2df90d1-961e-47dc-8f9d-5ff4516c54b0.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=75&id=u8ea6c61d&margin=%5Bobject%20Object%5D&name=image.png&originHeight=152&originWidth=314&originalType=binary&ratio=1&rotation=0&showTitle=false&size=20804&status=done&style=none&taskId=u919cb6fe-3c83-4cbc-bc1e-4bb37239901&title=&width=154)

  - 解压到任意非中文目录下:![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651830739419-6d9820e7-ca8e-4335-8551-da342649d2fd.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=143&id=u842c4404&margin=%5Bobject%20Object%5D&name=image.png&originHeight=405&originWidth=371&originalType=binary&ratio=1&rotation=0&showTitle=false&size=32579&status=done&style=none&taskId=u83960f74-444e-4c99-9073-7c047d9cf1a&title=&width=131)
  -  修改**conf/nginx.conf**文件,配置如下<br />这里使用127.0.0.1不影响 
upstream nacos-cluster {
    server 127.0.0.1:8845;
    server 127.0.0.1:8846;
    server 127.0.0.1:8847;
}

server {
    listen       80;
    server_name  localhost;

    location /nacos {
        proxy_pass http://nacos-cluster;
    }
}

粘贴到http元素的内部位置都可以,不用删除以前的server配置

  - 在命令行下输入:start nginx.exe启动nginx服务器,也可以双击运行,运行后查看任务管理器<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651831387913-2ea8a1b7-13d3-4038-9424-b36e77032621.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=86&id=uddaf6279&margin=%5Bobject%20Object%5D&name=image.png&originHeight=86&originWidth=435&originalType=binary&ratio=1&rotation=0&showTitle=false&size=11640&status=done&style=none&taskId=u2c2b6b2c-09ca-4fa9-84af-965e57abe6e&title=&width=435) 
  - 在浏览器访问:http://localhost/nacos即可。   
  - 查看`**集群管理->节点列表**`**    **
     - ![image.png](https://cdn.nlark.com/yuque/0/2022/png/25975946/1651831423241-4a5287cf-e624-4f9f-9644-8e27e7dff786.png#clientId=u28f0e064-85b7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=234&id=ua00e86f0&margin=%5Bobject%20Object%5D&name=image.png&originHeight=418&originWidth=970&originalType=binary&ratio=1&rotation=0&showTitle=false&size=63829&status=done&style=none&taskId=u1938e245-5219-42b3-8528-1f127d9a504&title=&width=544)

10.4.2.4),* Java代码的修改:

  1. 修改userservice服务的bootstrap.yaml文件配置如下:

    spring:
    cloud:
     nacos:
       server-addr: localhost:80 # Nacos地址
    
  2. 在nacos管理页面创建新的配置管理:userservice.yaml文件,同时修改java代码:在PatternProperties里增加属性username image.png

  3. 重新启动UserApplication微服务
  4. 浏览器上访问
    image.png
  5. 就会在mysql的nacos库的config_info表中出现上面的配置信息
    image.png
    注意点:启动Nacos集群服务时,确定启动IP是否本机IP地址,如果启动的服务地址是虚拟机IP地址,需要关闭虚拟网卡

*,Nacos和Eureka的区别?

  • 相同点:

1)两者支持服务注册服务拉取
2)两者都支持服务者心跳机制实现健康检测(续约)

  • 不同点:

1)Nacos可以实现服务注册发现,也可以做配置管理;Eureka只能做服务注册发现。
2)Nacos临时实例心跳不正常会被剔除,非临时实例(永久实例)则不会被剔除;而Eureka只能注册临时实例,实例失效会被剔除(Eureka不支持永久实例)
spring.cloud.nacos.discovery.ephemeral=false 创建永久实例
3)Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式;而Eureka只有心跳模式;
4)Nacos支持服务列表变更消息主动通知模式,服务列表更新更及时减少服务调用失败的机率;而Eureka采用被动定时服务列表拉取更新