SpringCloud

前言

什么是微服务?

就目前而言,微服务并没有统一的标准定义
但是就通常而言,**微服务架构是一种架构模式,或者说是一种架构风格,它提倡将单一的应用程序划分为一组小的服务,每个服务运行在其独立的进程内,服务之间互相协调,互相配置,并提供最终价值,**服务器之间采用轻量级的通信机制互相沟通,每个服务都围绕值具体的业务进行构建,并且能够被独立的部署到生产环境中,另外,应尽量避免统一的,集中式的管理来协调这些服务,可以使用不同的语言来编写服务,也可以使用不同的数据存储
从实际需求来讲,微服务化的核心就是将传统的一站式应用根据业务拆分为一个个的服务,彻底解耦,每一个微服务提供单个业务功能的服务,一个服务做一件事情,从技术角度来看就是一种小而独立的处理过程,类似进程的概念,能够自行单独启动或者销毁,拥有自己独立的数据库
微服务与微服务架构:
微服务强调的是服务的大小,他关注的是某一个点,是具体解决某个问题或者提供落地对应服务的一个服务定义,下一来看,可以看做是idea中的一个个微服务工程,或者是moudel
微服务架构是一种新的架构模式,2014年提出,它提倡将单一应用程序划分为一组小的服务,服务之间互相协调,互相配合,最终组成一个完整的架构

微服务优缺点:

优点:
每个服务足够内聚,足够小,代码容易理解,这样就能聚焦一个指定业务功能或者业务需求
开发简单,开发效率提高,一个服务可能就是专一地只干一件事
微服务能够被小团队单独开发,这个团队可以使2-5人的开发人员组成
微服务是低耦合的,是有功能意义的服务,无论是在开发阶段或者部署阶段都是独立的
微服务可以使用不同的语言开发
易于和第三方集成,微服务允许使用灵活的方式集成自动部署,通过持续集成工具,如jenkins,Hudson,bamboo
微服务易于被开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果,无需通过合作才能体现价值
微服务允许利用融合新技术
微服务只是业务逻辑的代码,不会和html,css或者其他界面混合
每个微服务都有自己的存储能力,可以有自己的数据库,也可以有统一数据库
缺点:
开发人员需要处理分布式系统的复杂性
多服务运维难度,随着服务的增加,压力也不断增大
系统部署依赖
服务件通信成本
数据一致性
系统集成测试
性能监控

微服务技术栈:

在这里插入图片描述

简介

什么是springCloud?
用大白话来说,springCloud就是用来管理springBoot众多服务的,属于依靠关系.
SpringCloud基于springBoot提供了一套微服务解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负载均衡,熔断器等组件,除了基于NetFlix的开源组件做到高度抽象封装之外,还有一些选型中立的开源组件.
springcloud利用springboot的开发便利性,巧妙地简化了分布式系统基础设施的开发,springcloud为开发人员提供了快速构建分布式系统的一些工具,包括配置管理,服务发现,断路器,路由,微服务,事件总线,全局锁,决策精选,分布式会话等,都可以利用springboot的开发风格做到一键启动和部署,
springCloud是分布式微服务框架下的一站式解决方案,是各个微服务架构落地技术的集合体,俗称微服务全家桶.

springcloud和springboot的关系

springBoot专注于快速方便的开发单个个体微服务.
SpringCloud是关注全局微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理,为个个微服务之间提供:配置管理,服务发现,断路器,路由,为代理,事件总线,全局所,决策竞选,分布式回话等集成服务.
SpringBoot可以离开SpringCloud独立使用或开发项目,但是SpringCloud离不开SpringBoot,属于依赖关系
Springboot专注于快速,方便的开发单个个体微服务,springcloud关注全局的服务治理框架
如下为一条完整的网站服务架构流程:
在这里插入图片描述
参考书:
Netflix文档:https://www.springcloud.cc/spring-cloud-netflix.html
中文API文档: https://springcloud.cc/spring-cloud-dalston.html
SpringCloud中国社区:http://springcloud.cn/
SpringCloud中文网: https://springcloud.cc

Rest学习环境搭建

首先创建一个最基本的maven项目,然后导入依赖:

<!--    打包方式 pom-->
    <packaging>pom</packaging>
<!--    properties用来定义版本号-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.16.18</lombok.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <!--            springCloud的依赖-->
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
<!--            springBoot的依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.1.4.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
<!--            数据库,以及连接池-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.10</version>
            </dependency>
<!--            springboot启动器-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.2</version>
            </dependency>
            <!--日志测试~-->
            <dependency>
            <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>1.2.3</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${1og4j.version}
                </version></dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

注意,此时导入的依赖外面包含了一个
< dependencyManagement>< /dependencyManagement>管理标签,此时直接查仓库是找不到的,需要在子项目中引用才能有效,如下:
在这里插入图片描述
在子项目中引用会直接出现一个图标直接定向到父项目依赖
并且可以再父项目的pom文件中进行如下声明:

    <groupId>com.xige</groupId>
    <artifactId>springcloud</artifactId>
    <version>1.0-SNAPSHOT</version>

然后子项目可以直接进行引用父项目中的依赖:

    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>com.xige</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
服务提供者:

数据库新建一个简单的部门表,然后创建实体类,有参构造只写一个id

@Data
@NoArgsConstructor
@Accessors(chain = true) //链式写法

引用父类依赖之后直接再创建一个provider(提供者)子项目
这个提供者子项目因为要使用到实体类,所以直接引用实体类的依赖:

<!--        我们需要拿到实体类,所以需要配置api  module-->
        <dependency>
            <groupId>com.xige</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

然后还有资源目录中的配置:
在这里插入图片描述
application.xml:(注意看配置的地址)

server:
  port: 8001
mybatis:
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml
  type-aliases-package: com.xige.springcloud.POJO
#spring的配置
spring:
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: org.gjt.mm.mysql.Driver
    url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8&serverTimeZone=UTC
    username: root
    password: 981216

mapper文件:(多看两遍命名空间和文件头)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xige.springcloud.mapper.DeptMapper">
    <insert id="addDept" parameterType="Dept">
        insert into dept(deptName,dept_source)
        values (#{deptName},DATABASE())
    </insert>
    <select id="queryDeptById" resultType="Dept" parameterType="Long">
        select * from dept where deptID = #{deptID};
    </select>
    <select id="queryAll" resultType="Dept">
        select * from dept;
    </select>
</mapper>

mybatis-config.xml只配置了一个开启二级缓存cacheEnabled
Controller层:

//提供restful服务
@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    @GetMapping("dept/add")
    public boolean addDept(Dept dept){
        return deptService.addDept(dept);
    }
    @GetMapping("dept/get/{id}")
    public Dept queryDeptById(@PathVariable("id") Long id){
        return deptService.queryDeptById(id);
    }
    @GetMapping("dept/list")
    public List<Dept> queryAll(){
        return deptService.queryAll();
    }
}

对应的三层框架创建好之后直接新建一个启动类DeptProvider_8001
最后运行,并进行测试(这里的提供者端口为8001)

服务消费者

新建一个module作为消费者,消费者不需要访问数据库,这里的依赖只需要导入最开始的pojo服务的springcloud-api依赖以及web服务和热部署依赖,
首先思考,消费者自己是不需要service层的,那么数据应该如何进行访问呢?
目前仅有的service层就是提供者的,那么肯定就是从提供者那里获取了,那么问题又来了,具体该如何获取呢?
思路:首先消费者和提供者是两个不同的服务,按照常理来说访问一个服务肯定必须要使用url跳转了,那么也就是说或许可以在一个服务中使用url去访问另外一个服务的service层了,而这里就有一个专门用来服务之间通讯的方法了:
RestTemplate
这个类利用restful风格进行服务之间的便捷通讯,这里一个解决办法是直接定义想要访问A服务的url前缀常量,访问时再把A服务固定url前缀拼接上A服务Controller层跳转链接,然后B服务拿到这个完整的跳转连接之后绑定上B服务自己的Controller跳转连接,最后访问的时候直接访问B服务的链接,B服务就直接利用拼接的url访问A服务中的service层信息
restTemplate本身提供了多种便捷访问远程http服务的几种方法,相当于一个简单的restful风格模板,注意RestTemplate类并没有被注册到bean中,需要再新建一个config方法,直接返回new RestTemplate(),然后@Bean即可
具体使用方法如下:

@RestController
public class DeptConsumerController {
    //需求:消费者需要在当前服务中去访问其他服务的数据

    //注意,消费者不应该有service层
    //Restful风格对应的有RestTemplate,里面有方法可以供我们进行调用
    //但是此方法没有被注册到bean里面,所以我们这里直接创建一个config类给它注入进去(新建方法,直接返回然后@Bean)
    @Autowired
    private RestTemplate restTemplate;

    //思路,这里没有service层,所以我们需要去别的服务上面拿
    // 而想要拿到另外的服务首先就需要去访问url,这里也直接先写一个常量:然后再进行拼接
    private static final String REST_URL_PREFIX = "http://localhost:8001";

    //需要注意的是,服务端提供的请求方式是什么,这边也必须对应

    @RequestMapping("/consumer/dept/get/{id}")
    public Dept get(@PathVariable("id") Long id){
        //此处的两个参数分别为请求的url和返回的数据类型
        return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
    }
    @RequestMapping("/consumer/dept/add")
    public boolean add(Dept dept){
        //此处的参数分别为的url以及提交的对象和返回的数据类型
        return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,boolean.class);
    }
    @RequestMapping("/consumer/dept/list")
    public List<Dept> queryAll(){
        //此处的两个参数分别为请求的url和返回的数据类型
        return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class);
    }
}

需要注意的是,A服务提供者提供的controller请求方式是什么,B服务的controller这边也必须对应,否则报错
然后同样创建一个服务的主启动类,这里直接设置端口为80,这样到时候直接就可以按照http://localhost/consumer/XXX进行访问,不需要输入端口号,
两个主启动类都启动成功之后,直接访问B服务的跳转连接,这样也就可以直接访问A服务的服务层,进而进行一系列操作了
https://localhost/consumer/dept/add?deptName=%27aaa%27

Eureka

什么是Eureka?
Eureka是netfix的一个子模块,也是核心模块之一,Eureka是一个基于rest的服务,用于定位服务,以实现云端中间层服务发现和故障转移,服务注册和发现对于微服务来说是非常重要的,有了服务发现和注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于Dubbo的注册中心,比如Zookeeper;
Eureka的基本架构
springcloud封装了Netflix公司开发的Eureka模块来实现服务注册和发现(对比Zookeeper)
Eureka采用了C-S架构设计,EurekaServer作为服务注册功能的服务器,Eureka则作为服务注册中心
而系统中的其他微服务,使用Eureka的客户端连接到EurekaServer并维持心跳连接(服务提供者和消费者连接服务注册中心会每隔多久发送消息,类似于心跳,如果没有那就会被认为死亡),这样系统的维护人员就可以通过EurekaServer来监控系统中各个微服务是否正常运行,springcloud的一些其他模块(比如zuul)就可以通过EurekaServer来发现系统中的其他微服务并执行相关的逻辑

Eureka三大角色:

Eureka Server:提供服务的注册与发现
Service Provider:将自身服务注册到Eureka总,从而使消费方能够找到
Service Consumer:服务消费方从Eureka中获取注册服务列表,从而找到消费服务

实际操作:

一般大型项目写配置都有一个固定的思路:
1,导入依赖
2,编写配置文件
3,开启功能@EnableXXX
4,配置类(可选)
所以:依然是新建一个module,然后导入eureka的依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    <version>3.0.2</version>
</dependency>

然后编写Eureka的配置文件:

server:
  port: 7001

#Eureka配置
eureka:
  instance:
    hostname: localhost #eureka服务端的实例名称
  client:
    register-with-eureka: false #表示是否向eureka注册中心注册自己
    fetch-registry: false  #fetch-registry如果为false则表示自己为注册中心
    service-url:  #监控页面动态配置,注意此处defaultZone有默认路径,现在属于重写了
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

接下来编写主启动类,并添加@EnableEurekaServer开启功能
最后访问配置的地址,出现Eureka页面:
在这里插入图片描述

服务注册-信息配置-自我保护机制

首先还是需要先在8001端口的项目导入eureka的依赖
ps:此依赖已经停止维护了

<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>

然后还要添加配置信息:声明服务注册到了什么地方,这里直接注册到事先声明好的eureka页面

#Eureka的配置,用于声明服务注册到什么地方
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/

然后在8001端口的启动类添加@EnableEurekaClient开启功能,最后先启动7001的服务端启动类让8001的服务有地方注册,然后再启动8001端口的项目,最后打开eureka的页面就可以发现服务已经注册到eureka页面中了:
在这里插入图片描述
另外eureka页面上的状态描述信息也可以通过配置来修改:

eureka:
  instance:
    instance-id: springcloud-provider-dept8001 #修改eureka页面上的默认描述信息

在这里插入图片描述
保护机制
如果说某个服务和注册中心之间的心跳反馈突然停止,那么注册中心会等待一段时间,默认为90秒后删除该服务,但是如果某个节点出问题,比如大规模停电,倒是很多服务突然全部出问题,那么eureka注册中心会默认保存全部的服务,并一个都不会删除,它本身的设置就是宁可保留错误的注册信息,也不盲目注销任何健康服务.
但是本身在springcloud可以通过使用
eureka.server.enable-self-preservation = false来禁用自我保护机制,当然,不推荐关闭

Eureka集群环境配置

首先上面的7001端口配置成功之后只需要再重新创建两个实验端口就可以当做集群的实验环境,这里创建了7002和7003这两个(再多跑不起来了)
配置eureka-server依赖和yml配置文件,然后修改为对应的7002端口:

server:
  port: 7002
#Eureka配置
eureka:
  instance:
    hostname: eureka7002.com #eureka服务端的实例名称
  client:
    register-with-eureka: false #表示是否向eureka注册中心注册自己
    fetch-registry: false  #fetch-registry如果为false则表示自己为注册中心
    service-url:  #监控页面动态配置,注意此处defaultZone有默认路径,现在属于重写了
      defaultZone: http://eureka7003.com:7003,http://eureka7001.com:7001

需要注意的是这里提前修改了host文件,地址一般为:

C:\Windows\System32\drivers\etc

在其末尾添加了三个映射:这样方便区分不同服务节点

127.0.0.1       eureka7001.com
127.0.0.1       eureka7002.com
127.0.0.1       eureka7003.com

并且可以在上面的配置文件中看到7002端口配置了7001和7003端口的监控页面,其他两个端口也一样配置了除自身之外的端口监控页面
然后在8001的服务端口上直接将服务注册到所有三个端口页面上:

#Eureka的配置,用于声明服务注册到什么地方
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/,http://eureka7003.com:7003/eureka/,http://eureka7002.com:7002/eureka/

这样直接访问任何一个就都能看到服务消息,并且还可以进行节点之间的跳转
在这里插入图片描述
这里我发现了一个问题,集群的eureka地址如果末尾添加了/eureka/就无法在页面进行跳转,但是消息全部都可以接受注册,如果去掉了就可以跳转但是只有部分可以接受服务注册,并且很莫名其妙地只有三个地址中中间的那个可以接受服务注册,或者两个中的第二个可以接受,原因未知~~

CAP原则以及对比zookeeper

关系型数据库(Mysql,Oracle等)一般遵循ACID原则:
A:原子性 C:一致性 I:隔离性 D:持久性
非关系型数据库(redis,mongDB)一般遵循CAP原则:
C:强一致性 A:可用性 P:分区容错性
CAP原则只能三进二:CA CP AP
不可能同时满足三个要求
又由于分区容错性P在分布式系统中是必须要满足的,所以我们只能在A(可用性),C(强一致性)之间进行权衡,而这就是eureka和zookeeper之间的区别了:
Zookeeper保证的是CP(一致性和分区容错性):
zookeeper 是保证数据的一致性的,但不是强一致性的,比如现在客户端 A 提交一个写操作,zookeeper 在过半数节点操作成功之后返回,但此时客户端 B 的读操作请求的是 A 写操作尚未同步到的节点,那么读取的就不是 A 最新提交的数据了。
为了保证强一致性,我们可以在读取数据的时候先执行一下 sync 操作,即与 leader 节点先同步一下数据,再去取,这样才能保证数据的强一致性。
但是 zookeeper 也有个缺陷,zookeeper本身有主从节点,当 master 主节点因为网络故障与其他节点失去联系时,剩余节点会重新进行 leader 选举。并且选举 leader 的时间需要30 ~ 120s, 且选举期间整个 zookeeper 集群都是不可用的,这就导致在选举期间注册服务瘫痪。
Eureka保证的是AP(可用性和分区容错性):
Eureka 各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而 Eureka 的客户端在向某个 Eureka 注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台 Eureka 还在,就能保证注册服务可用.只不过查到的消息可能不是最新的
正因为应用实例的注册信息在集群的所有节点间并不是强一致的,所以需要客户端能够支持负载均衡以及失败重试。在 Netflix 的生态中,ribbon 可以提供这个功能。
并且eureka自身有一定的保护机制(重申):
如果在15分钟之内有超过85%的节点有没有正常的心跳,那么eureka就认为客户端和注册中心出现了网络故障,此时会有以下几种情况:

  • eureka不再从注册列表中移除因为长时间没有收到心跳而应该过期的服务
  • eureka依然可以接受新服务的注册和查询请求,但是不会被同步到其他节点上(即保证当前节点依然可用)
  • 当网络稳定时,当前节点新的注册信息会被同步到其他节点上

因此, Eureka 可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像 zookeeper 那样使整个注册服务瘫痪。

负载均衡和Ribbon

Ribbon是什么?

Ribbon官方文档:https://www.springcloud.cc/spring-cloud-netflix.html
SpringCloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具,主要功能是提供客户端的软件负载均衡算法,ribbon的客户端组件提供一系列完整的配置项,比如连接超时和重试等等.并且在连接类似于Eureka节点的时候会基于某种规则(比如轮询和随机连接等)来进行选择性连接,同时也可以使用ribbon来实现自定义的负载均衡算法
Ribbon能干嘛?
LB,即负载均衡(Load Balance),在微服务或者分布式集群中是一种常见应用
负载均衡简单来说就是将用户端请求平摊到多个服务节点上,从而达到系统的HA(高可用)
常见的负载均衡软件有Nginx,Lvs等
dubbo,springcloud中都给我们提供了负载均衡,springcloud的负载均衡算法还可以自定义,

负载均衡的简单分类:

集中式:即在服务的消费方和提供方之间使用独立的LB设施,比如Nginx就是用了反向代理服务器,由该设施负责把访问请求通过某种策略转发至服务的提供方
进程式:即将LB逻辑继承到消费方,消费方从服务注册中心获取可用的地址,然后自己在这些地址中选择一个合适的服务器
Ribbon就属于进程式LB,它只是一个类库,属于消费方进程,消费方通过它来获取到服务提供方的地址
接下来就是实际演示了,首先还是要导入依赖:

<!--        Ribbon-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    <version>2.2.9.RELEASE</version>
</dependency>

<!--        Eureka 服务端的eureka,而不是eureka注册中心-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    <version>1.4.7.RELEASE</version>

然后添加消费者配置文件:(消费者可以从三个地址节点获得数据)

eureka:
  client:
    register-with-eureka: false #不响eureka中注册自己,消费者只需要拿
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

然后在消费者主启动类开启配置@EnableEurekaClient
注意,此处还需要在客户端配置类中添加Ribbon注解@LoadBalanced ,这样在最初的客户端controller层中配置的service层服务节点8001固定地址(http://localhost:8001)就可以利用注解本身的方法替换为服务节点中服务名来进行访问(http://SPRINGCLOUD-PROVIDER-DEPT)
最后开启集群,服务节点,客户端节点,然后打开打开客户节点的地址(http://localhost/consumer/dept/list)访问一下集合:(默认80端口不需要加端口号)最后访问成功:
在这里插入图片描述

使用Ribbon实现负载均衡

在前面我们已经组建好了三个节点组成的简单集群(700X端口)以及一个消费者(80端口)和服务端口(8001),接下来按照上面的继续来搭建负载均衡测试环境.因为eureka是在消费者处直接进行的负载均衡,所以这里再添加两个服务提供者来方便进行负载均衡后的效果展示.
首先创建两个服务提供者(8002,8003)并分别再连接两个新的数据库,所有数据库的表只有dept_source对应各自数据库名称,其他的全都一样,同时新建的两个服务提供者的主启动类,数据库配置信息以及yml配置文件的数据库url连接配置需要进行对应修改,其他的依赖以及大致架构不变,此时再访问Eureka页面时会发现三个服务提供者已经注册到每个服务节点上面:
在这里插入图片描述
此时进行访问也可以正常进行,但是点击刷新的时候有时会跳转到不同服务提供者上面,因为数据库表中dept_source列不同,所以可以明显发现不一样,这个时候就说明默认的负载均衡(轮询)已经起作用了:
在这里插入图片描述

自定义负载均衡算法

负载均衡有一个核心接口IRule,里边包含了一些负载均衡时用到的实现方法:

  • AvailabilityFilteringRule 会先过滤崩溃的服务,然后再对剩下服务器的进行轮询(算是优化版轮询)
  • RoundRobinRule 轮询
  • RandomRule 随机
  • RetryRule 会按照轮询进行获取服务,如果服务获取失败则会在指定时间内重试

  • 这里我们可以进行简单的自定义负载均衡算法,但是需要注意要放在一个单独的不重叠包中:
    在这里插入图片描述
    因为Ribbon官方文档(https://www.springcloud.cc/spring-cloud-netflix.html)有说明:
    在这里插入图片描述
    如果直接配置在application也就是主应用程序中只要被扫描到也会生效,但是会被所有客户端共享也就是变为全局配置,我们可以配置在主应用程序之外,用来针对个别服务配置
    注意,在创建完自定义负载均衡算法之后还要在主启动类中添加注解
    @RibbonClient(name = “springcloud-provider-cons”,configuration = xgRule.class),其中name属性是客户端配置文件中声明过的:
    在这里插入图片描述
    configuration是自定义负载均衡算法的方法名,最好创建多个,然后只需要把使用的那一个注入进一个总的方法中,然后把总的方法注入到主启动类中:
    在这里插入图片描述
    这里的自定义算法失败了,不作赘述,知道怎么将自定义算法用上就好
Feign

什么是Feign?

Feign是声明式的web Service客户端,可以让微服务之间的调用更加简单,类似于controller调用service,springcloud继承了Ribbon和Eureka,可以再使用Feign时提供负载均衡的http客户端,只需要创建一个借口,然后使用注解即可
如今调用微服务有两种办法:

  • 通过微服务的名字[Ribbon]
  • 通过接口和注解[Feign]

Feign能做什么?

Feign目的是使java http客户端的编写更加容易,在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置它(类似于以前Dao接口上标注Mapper的注解,现在是一个微服务接口上面标注一个Feign注解就行了)即可完成对服务提供方的接口绑定,简化了使用springcloud Ribbon时,自动封装服务调用客户端的开发量
feign集成了Ribbon
依然是实际操作一下:
创建一个和80端口相同的模块,修改一下主启动类的名字以及一些其他细节.
然后导入对应的openFeign依赖:

<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign -->
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-openfeign</artifactId>
   <version>3.0.4</version>
</dependency>

然后在api模块中创建service层,写好对应接口方法,并在接口上标注@FeignClient,注意,这个@FeignClient是可以进行传递参数的,而这里传递的参数就是服务名SPRINGCLOUD-PROVIDER-DEPT:

@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptClientService {

    @GetMapping("/dept/get/{id}")
    public Dept queryById(@PathVariable("id") int id);

    @GetMapping("/dept/list")
    public List<Dept> queryAll();

    @PostMapping("/dept/list")
    public Dept AddDept(Dept dept);
}

注意,此处是service层,只不过加上了controller层的注解,这里是为了将此接口直接注入到controller层中,当然,service层也需要注入到容器中,所以feign的controller层就变成了:

@RestController
public class DeptConsumerController {
    //需求:消费者需要在当前服务中去访问其他服务的数据
    //注意,消费者不应该有service层
    //Restful风格对应的有RestTemplate,里面有方法可以供我们进行调用
    //但是此方法没有被注册到bean里面,所以我们这里直接创建一个config类给它注入进去(新建方法,直接返回然后@Bean)
    //@Autowired
    //private RestTemplate restTemplate;
    //restTemplate本身提供了多种便捷访问远程http服务的几种方法,相当于一个简单的restful风格模板

    //思路,这里没有service层,所以我们需要去别的服务上面拿
    // 而想要拿到另外的服务首先就需要去访问url,这里也直接先写一个常量:然后再进行拼接
    //通过ribbon实现的时候,地址应该是一个变量,通过服务名来进行访问
    //private static final String REST_URL_PREFIX = "http://localhost:8001";
    //private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
    @Autowired
    private DeptClientService service= null;

    //需要注意的是,服务端提供的请求方式是什么,这边也必须对应
    @RequestMapping("/consumer/dept/get/{id}")
    public Dept get(@PathVariable("id") Long id){
        //此处的两个参数分别为请求的url和返回的数据类型
        return this.service.queryById(id);
    }
    @RequestMapping("/consumer/dept/add")
    public boolean add(Dept dept){
        //此处的参数分别为的url以及提交的对象和返回的数据类型
        return this.service.addDept(dept);
    }
    @RequestMapping("/consumer/dept/list")
    public List<Dept> queryAll(){
        //此处的两个参数分别为请求的url和返回的数据类型
        return this.service.queryAll();
    }
}

如上所示,关于service层的常量就不需要再次声明了,注入进来就能直接用,接下来就是和原本的80端口一样使用了,
总结:
feign是通过一种新的接口方法调用,但是本质还是去找了eureka的服务,feign只是在进行服务调用的时候融合了ribbon,所以间接性的也支持负载均衡,作用就是替代原来ribbon中:

private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";

这一句代码,使代码可读性更高,但是性能又低了一些,毕竟多了一层,这玩意仁者见仁智者见智,会用就好

Hystrix

服务熔断机制

分布式系统面临的问题:
复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免的失败
服务雪崩:
多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的扇出,如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的雪崩效应.
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源
都在几秒钟内饱和,比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障,这些都表示需要对故障和延迟进行隔离和管理,一遍单个依赖关系的失败不能取消整个应用程序或者系统.
这里的思路是’弃车保帅’
什么是Hystrix?
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统中,许多依赖不可避免的会调用失败,比如超时,异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务的失败,避免级联故障,以提高分布式系统的弹性
'断路器’本身是一种开关装置,当某个服务单元发生故障的时候,通过断路器的故障监控(类似于保险丝),向调用方返回一个服务预期的,可处理的备选相应FallBack而不是长时间的等待或者抛出调用方法无法处理的异常,这样就保证了服务调用方的线程不会被长时间,不必要的占用,从而避免了故障在分布式系统中的蔓延,甚至雪崩
Hystrix能干嘛?

  • 服务降级
  • 服务熔断
  • 服务限流
  • 接近实时的监控

什么是服务熔断?
熔断机制是对应雪崩效应的一种微服务链路保护机制,
当扇出链路的某个微服务不可用或者响应时间太长的时候,会进行服务降级,进而熔断该节点微服务的调用,快速返回错误的响应信息当检测到该节点微服务调用响应正常后恢复调用链路,当失败的调用达到一定阀值,一般是5秒内20次调用失败就会启动熔断机制,熔断机制的注解是@HystrixCommand,里面包含了一些关于回滚之类的方法:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface HystrixCommand {
    String groupKey() default "";

    String commandKey() default "";

    String threadPoolKey() default "";

    String fallbackMethod() default "";

    HystrixProperty[] commandProperties() default {};

    HystrixProperty[] threadPoolProperties() default {};

    Class<? extends Throwable>[] ignoreExceptions() default {};

    ObservableExecutionMode observableExecutionMode() default ObservableExecutionMode.EAGER;

    HystrixException[] raiseHystrixExceptions() default {};

    String defaultFallback() default "";
}

实操:
首先创建一个8001端口的Hystrix副本,以这个Hystrix的副本中controller层的queryById为例,添加一个实体类非空判断并抛出异常,这个时候就用到了Hystrix中的fallbackMethod方法了,报错之后回滚到指定方法中,交给另外一个方法来执行,保证整体流程不受单个错误而阻拦:

@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    @HystrixCommand(fallbackMethod="hystrixGet")
    @GetMapping("/dept/get/{id}")
    public Dept get(@PathVariable("id") Long id){
        Dept dept = deptService.queryDeptById(id);
        if (dept==null){
            throw new RuntimeException("id=>"+id+":不存在该用户或信息未找到~");
        }
        return dept;
    }
    //备选方案,此处直接返回了一个新的,原数据库中不存在的对象
    public Dept hystrixGet(@PathVariable("id") Long id){
        Dept dept = deptService.queryDeptById(id);
        return new Dept()
                .setDeptID(id)
                .setDeptName("id=>"+id+"没有发现对应的信息,null---@Hystrix")
                .setDept_source("Mysql中没有该数据源");
    }
}

注意,依赖与注解写完之后一定要开启配置才会生效,这里在主启动类开启的配置为:

@EnableCircuitBreaker //添加对熔断的支持

简单测试一下:
在这里插入图片描述
PS:Eureka页面左下角链接地址修改

 instance:
    instance-id: springcloud-provider-Hystrix-dept8001 #修改eureka页面上的默认描述信息
    prefer-ip-address: false  #ip显示修改服务的ip地址为具体的端口号(从localhost:XXX改为192.168.XXX)

服务降级

什么是服务降级?
服务降级就是在特定时间或者特定情况对于用户的部分请求进行优先处理,用户的其他服务就牺牲一部分服务器资源给特定服务,用人话来说就是医院急救病房就那么多,你一个感冒的就没必要往里面凑了,等人家救完命再说.
注意,服务降级的时候用户的非主要请求会被定位到一个特殊的地方用来提示用户该服务暂时已经被注销,而不是直接一棍子打死跳出一个404或者500页面
接下来实际操作模拟特殊时段服务降级的操作,
首先这里创建了一个用户服务被降级的service层的工厂类,这个工厂类会在服务降级的时候直接拦截,并进行返回声明:

@Component
public class DeptClientServiceFallBackFactory  implements FallbackFactory{

    @Override
    public DeptClientService create(Throwable throwable) {
        return new DeptClientService() {
            @Override
            public Dept queryById(Long id) {
                System.out.println("已执行~~~");
                return new Dept().setDeptID(id)
                        .setDeptName("id:"+id+"没有对应的信息~")
                        .setDept_source("客户端提供了降级的信息,这个服务现在已经被关闭了,没有数据");
            }

            @Override
            public List<Dept> queryAll() {
                return null;
            }

            @Override
            public Boolean addDept(Dept dept) {
                return null;
            }
        };
    }
}

同时要在提供者(8001端口)开启服务降级的支持:

#开启降级
feign:
  hystrix:
    enabled: true

这个时候开启消费者(80端口)提供者(8001端口)和Eureka节点(7001端口)后关闭提供者,此时消费者依然可以访问到数据,不过是自定义的提示信息:
PS:一定要注意访问的url路径,因为路径问题一直访问不了
在这里插入图片描述
服务熔断和服务降级的区别:
服务熔断是在服务端进行处理的,当单个服务器上某个服务超时或者异常就会自动引起熔断
服务降级是在客户端进行处理的,当**服务器中(可以是整个集群)**某个服务熔断或者关闭时就自动停止访问,并且提示用户服务不再被调用,
思路是准备一个FallBackFactory,返回一个默认的缺省值(类似固定提示信息),整体的服务水平下降了,但是保证了核心业务

Dashboard流监控

监控肯定是监控客户端的用户请求,所以对应的依赖都在客户端中导入
首先创建一个新的module,然后先导入用户(80端口)的依赖和hystrix以及监控的依赖:

<!--        hystrix依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

        <!-- 监控页面依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>
        
        <!--        Ribbon-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            <version>2.2.9.RELEASE</version>
        </dependency>

        <!--        Eureka 服务端的eureka,而不是eureka注册中心-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.xige</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

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

导入依赖之后模块肯定要启动起来才可以进行监控,所以这边建好包,编写个启动类(启动类添加@EnableHystrixDashboard开启监控页面),并在系统配置文件中声明端口号9001,并且服务端8001端口要存在监控的依赖:(这里早就配置上了)

        <!--        actuator完善监控信息-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

这里启动之后打开localhost:9001/hystrix就可以进入初始监控页面了:
在这里插入图片描述

接下来在服务提供者端口(8001)中添加一个配置类:

@Configuration
public class Dashboard {
    //增加一个Servlet
    @Bean
    public ServletRegistrationBean a(){
        ServletRegistrationBean bean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
        bean.addUrlMappings("/actuator/hystrix.stream");
        return bean;
    }
}

注意,这段配置类是死代码,bean.addUrlMappings("/actuator/hystrix.stream")中的UrlMapping是hystrix监控初始页面标明的默认尾部映射地址,并且服务端口需要有hystrix依赖,老秦的视频被剪辑过,有坑
然后依次启动消费者端口(80),eureak服务节点(7001),Dashboard监控页面(9001)和服务提供者(8001),首先在保证可以正常访问数据库数据的时候(访问数据库时url请求为http://localhost:8001/dept/get/2)
访问配置类设置的地址http://localhost:8001/actuator/hystrix.stream可以发现能ping很多字符数据,并且只要发送请求,这里就会多一些数据
在这里插入图片描述
然后将这个地址输入在hystrix监控初始页面中,就可以进入监控了:
在这里插入图片描述
并且每次请求,此处图表都会有对应变化:
在这里插入图片描述

Zuul路由网关

什么是Zuul?
Zuul包含了对请求的路由和过滤两个最主要的功能
其中路由功能负责将外部请求转发到具体的微服务实例中,是实现外部访问统一入口的基础,而过滤器功能则负责dUI请求的处理过程进行干预,是实现请求消炎,服务聚合等功能的基础,Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得的.
注意:Zuul服务最终还是会注册进Eureka
提供:代理+路由+过滤三大功能
接下来实操一下:
首先创建一个新的zuul模块,导入对应依赖:

    <dependencies>
    <!--zuul依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zuul</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

        <!--        hystrix依赖-->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-hystrix -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

        <!-- 监控页面依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

        <!--        Ribbon-->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-ribbon -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            <version>2.2.9.RELEASE</version>
        </dependency>
        <!--        Eureka 服务端的eureka,而不是eureka注册中心-->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.xige</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

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

然后编写application配置文件:

server:
  port: 9527

#首先要有自己的名字,zuul的官方名字是getaway
spring:
  application:
    name: springcloud-zuul
#因为最终都是在eureka中,所以还需要配置eureka相关信息
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: Zuul9527.com #修改eureka页面上的默认描述信息
    prefer-ip-address: false
info:
  app.name: xg_777
  company.name: xg777.com

再编写启动类,并开启zuul注解@EnableZuulProxy
最后依次启动服务节点,服务端口,以及zuul,再保证可以正常访问的情况下通过zuul再进行访问:(这里的xg777是修改了host文件)
http://www.xg777.com:9527/springcloud-provider-dept/dept/get/3
可以发现依然能正常访问:
在这里插入图片描述
格式为本机地址+端口号+微服务名字+映射路径
其中springcloud-provider-dept自然是服务端口的名字,不过只能小写
当然,这里的服务端口名字可以通过zuul的配置进行自定义替换:

#zuul路由网关设置默认名
zuul:
  routes:
    mydept.serviceId: springcloud-provider-dept
    mydept.path: /mydept/**
    #设置原服务名跳转不可用
  ignored-services: springcloud-provider-dept

这样访问地址就变为:
http://www.xg777.com:9527/mydept/dept/get/3
注意,如果没有设置最后一句使用原来的名字依然可以进行访问,并且一般配置通配符(mydept.path: “*”)来隐藏全部真实项目名
同时还可以通过prefix: XX来进行前缀设置,这样跳转的时候还必须加上前缀才可以

Config分布式配置

分布式系统面临的配置文件的问题
微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务,每个服务又有要有配置信息,所以一套集中式的,动态的配置管理设施是必不可少的
springcloud提供了configServer来解决这个问题,我们每一个微服务自己都带着一个application.yml,如果微服务很多的,那配置文件一个个修改起来更是折磨.所以:

springCloud config分布式配置中心

springcloud config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环节提供了一个中心化的外部配置
springcloud config分为服务端和客户端两个部分
服务端也称为分布式配置中心,她是一个独立的微服务应用,用来连接配置服务器并未客户端提供获取配置信息,加密,解密信息等访问接口
客户端则是通过指定的配置中心来管理应用资源,以及业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息,配置服务器默认采用git来储存配置信息,这样就有助于对环境配置进行版本管理,并且可以通过git客户端工具来方便的管理和访问配置内容
springcloud config分布式配置中心能干嘛?

  • 集中管理配置文件
  • 不同环境,不同配置,动态化的配置更新,分环境部署,比如/dev /test/等
  • 运行期间动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务会想配置中心统一拉取配置自己的信息
  • 当配置发生变动时,服务不需要重启,即可感知到配置的变化,并应用新的配置
  • 将配置信息以Rest接口的形式暴露
回顾git

首先创建一个远程仓库,然后在指定文件夹打开git bash,使用git clone+url克隆到本地,url使用ssh,接下来创建一个简单的环境配置文件,用来在不同情况下使用不同的环境配置文件:

spring:
 profiles:
  active: dev
---
spring:
  profiles: dev
  application:
    name: springcloud-config-dev
---
spring:
  profiles: test
  application:
    name: springcloud-config-test

注意,不同环境之间必须要有—来分开,不然接下来就找不到配置信息
然后四步操作上传到远程仓库:
首先git add. 添加到暂存区
然后 git status 查看状态
接着 git commit -m “frist commit” 提交到本地仓库
最后 git push origin master 提交到远程仓库

服务端连接远程git配置

既然gitee上面可以有配置文件,自然也就可以想办法读取上面的配置了
这里首先创建一个新模块,配置好springBoot和springcloud-config-server依赖,一定要注意版本问题,这里比如这里的config-server版本如果使用2.2.1的就500,使用2.1.1的就可以:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
    <version>2.1.1.RELEASE</version>
</dependency>

接下来就是老套路了,导入依赖,编写配置,主启动类开启使用:
配置文件如下:

server:
  port: 3344

#连接远程仓库  注意uri是https的克隆方式,而不是ssh
spring:
  application:
    name: springcloud-config-server
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/wind-in-the-snowy-night/spring-cloud-config.git

注意,这里的uri后面就是远程仓库的http地址
然后编写主启动类并开启注解@EnableConfigServer,最后启动主启动类,搜索http://localhost:3344/application-dev.yml,即可找到对应配置文件,如果使用test环境,就是application-test.yml,这种方式访问出来的格式都是yml格式.
还有其他格式可访问:
在这里插入图片描述
更多详细信息可查看springcloud官方文档:
https://www.springcloud.cc/spring-cloud-dalston.html#_quick_start

客户端连接服务端访问远程

上面的部分只是服务端连接远程仓库,接下来就是创建一个客户端进行联动服务端:
这里首先在原本的远程仓库项目中编写好客户端对应的远程配置文件,然后push到gitee远程仓库:
配置了两个环境,并对应不同的端口号,内含eureka以及springBoot

spring:
  profiles:
    actives: dev
---
server:
  port: 8201
spring:
  profiles: dev
  application:
    name: springcloud-provider-dept

#Eureka的配置,用于声明服务注册到什么地方
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
---
server:
  port: 8202
spring:
  profiles: test
  application:
    name: springcloud-provider-dept

#Eureka的配置,用于声明服务注册到什么地方
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

需要注意的是这里push的时候突然出现push被拒绝,网上搜的原因说是推送的时候不知道你是谁,不让你往里面push,明明已经配置好公钥了,这里换了个思路,先clone下来,然后再在文件夹里面创建配置文件,最后再push一条龙,然后就成功了
然后再创建一个新的模块,并导入依赖,编写配置,开启配置
首先是依赖,仍然是springboot和actuator监控器以及一个config依赖以及bootstrap依赖(用于读取系统级配置文件,高版本springcloud把bootstrap禁用了)
需要注意的是前面服务端config依赖是config-server,调用方则是config-starter:

    <dependencies>
        <!--        actuator完善监控信息-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--        springcloud config starter依赖 注意,服务方是config-server,调用方是config-starter-->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-config -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
            <version>3.0.5</version>
        </dependency>

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

<!--        用于读取系统级配置文件-->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-bootstrap -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
            <version>3.0.3</version>
        </dependency>
    </dependencies>

PS:
一般的系统配置文件除了可以以application来命名,还可以使用bootstrap来命名,其中bootstrap为系统级别的配置,而application则是用户级别的配置,这里使用bootstrap来保证配置的优先级大于一般的用户配置,所以:
bootstrap.yml:

spring:
  cloud:
    config:
      uri: http://localhost:3344 #地址
      name: config-client #需要从git上读取的配置名称
      profile: dev  #环境
      label: master #分支
      #之前访问远程配置的地址是:http://localhost:3344/application-dev.yml,这里只是将其拆分开了

注意,此处编写的客户端只需要跟服务端交互就行,不可能让用户直接接触远程仓库的数据,所以这里只连接服务端远程仓库的uri来获取自身客户端配置
而用户配置只需要配置个名字就行了
application.yml:

spring:
  application:
    name: springcloud-config-client-3355

然后这里可以写一个主启动类和controller测试一下客户端能不能通过访问服务端拿到远程仓库的配置信息,当然服务端也需要启动,controller如下:

@RestController
public class configClientController {

    @Value("${spring.application.name}")
    private String applicationName;
    @Value("${eureka.client.service-url.defaultZone}")
    private String eurekaServer;
    @Value("${server.port}")
    private String port;

    @RequestMapping("/config")
    public String getConfig(){
        return "applicationName:" +applicationName+"\t"+
                "eurekaServer"+eurekaServer+"\t"+
                "port"+port;
    }
}

注意了,因为此处根据远程配置,使用的是dev开发环境的配置,所以端口号也就是远程仓库标明的8201,访问一下就可以发现能通过服务端获取

远程配置实战测试

既然上面的远程配置都有了,那么接下来就将服务节点7001和服务器8001的配置全都发布到git远程,然后再通过远程读取后运行,
整体流程与上面一样,都是首先创建号配置文件,配置文件对应不同的环境,然后push到git上面,然后再把原项目的application配置文件都删得只剩一个applicationName,然后将远程仓库的链接写在bootstrap上面.最后运行读取就好了,这里已经成功了,就不过多赘述了

至此,完结~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值