文章目录
1、SpringCloud
回顾之前的知识
- JaveSE
- 数据库
- 前端
- Servlet
- Http
- Mybatis
- Spring
- SpringMVC
- SpirngBoot
- Dubbo、Zookeeper,分布式基础
- Maven、Git
- Ajax、Json
- …
2、SpringCloud怎么学习
-
三层架构 + MVC 框架: Spring IOC AOP SpringBoot 新一代的JavaEE开发标准 自动装配 模块化 all in one 模块化的开发,代码没变化 //微服务架构四个核心问题? 1.服务很多,客户端怎么访问 2.服务很多,服务之间如何通信 3.这么多服务,如何治理 4.服务挂了怎么办 解决方案: Spring Cloud解决这四个问题 它是生态 //1.spirng Cloud NetFlix一站式(什么都能干,四个都能解决)解决方案 api网关,zuul组件 Feign ---HttpClinet ----Http通信方式,同步,阻塞 服务注册发现:Eureka 熔断机制:Hystrix //2.Apache Dubbo Zookeeper半自动,需要整合别人的 API:没有,找第三方组件,或者自己实现 Dubbo:通信框架 Zookeeper 没有熔断机制,借助Hystrix 这个方案并不完善 //3.Spring Cloud Alibaba一站式解决方案,更简单,2019年诞生 新概念:服务网格~Server Mesh istio 1.API网关 2.通信:HTTP.RPC 3.注册和发现(高可用) 4.熔断机制 由于网络的不可靠,会丢包丢帧,诞生了这些
现代化的Java开发
SpringBoot构建+SpringCloud协调
3、微服务概述:
微服务是一种架构模式,提倡将单一的应用程序划分成一组小的服务,每个服务围绕具体的业务进行构建,并且能够被独立的部署到生产环境中。
解耦,每一个微服务提供单个业务功能的服务,一个服务做一件事情,从技术角度看就是一种小而独立的处理过程,类似进程的概念,能够自行单独启动或销毁,拥有自己独立的数据库。
3.1、微服务优缺点
4、SpringCloud是什么
SpringCloud,基于SpringBoot提供了一套微服务解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负载均衡,熔断器等组件
4.1、SpringCloud和SpringBoot关系
- SpringBoot专注于快速方便的开发单个个体微服务
- SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,为各个微服务之间提供:配置管理,服务发现,断路由,路由,微代理,事件总线,全局锁,决策竞选,分布式等等集成服务。
- SpringBoot可以离开SpringCloud独立使用,开发项目,但是SpringCloud离不开SpringBoot,属于依赖关系。
- SpringBoot专注于快速、方便的开发单个个体微服务,SpringCloud关注全局的服务治理框架
4.2、SpringCloud能干什么
- Distributed/versioned configuration(分布式/版本控制配置)
- Service registration and discovery(服务注册与发现)
- Routing(路由)
- Service-to-service calls(服务到服务的调用)
- Load balancing(负载均衡配置)
- Circuit Breakers(断路由)
- Distributed messaging(分布式消息管理)
- …
4.3、SpringCloud在哪儿下
-
官网:https://spring.io/projects/spring-cloud
-
SpringCloudNetflix中文文档:https://springcloud.cc/spring-cloud-netflix.html
-
中文Api文档:https://springcloud.cc/spring-cloud-dalston.html
-
SpringCloud中国社区:https://springcloud.cn/
-
SpringCloud中文网:https://springcloud.cc
5、Rest学习环境搭建
-
创建maven项目
-
导入父依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>SpringCloud</artifactId> <version>1.0-SNAPSHOT</version> <modules> <module>SpringCloud-api</module> <module>SpringCloud-provider-dept-8001</module> <module>SpringCloud-provide-dept-80</module> </modules> <!-- 打包方式 --> <packaging>pom</packaging> <!-- 版本号 --> <properties> <junit.version>4.12</junit.version> <lombok.version>1.16.10</lombok.version> <log4j.version>1.2.17</log4j.version> </properties> <dependencyManagement> <dependencies> <!-- SpringCloud依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR5</version> <type>pom</type> <scope>import</scope> </dependency> <!-- SpringBoot依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.3.0.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> <!-- junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> <!-- log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> </dependencies> </dependencyManagement> </project>
-
创建服务端8001端口
-
创建model:SpringCloud-provider-dept-8001
-
创建db01数据库
-
配置文件application
server: port: 8001 #mybatis配置 mybatis: #扫包 type-aliases-package: com.springclouod.pojo #mybatis配置文件映射 config-location: classpath:mybatis/mybatis-config.xml #mapper映射 mapper-locations: classpath:mybatis/mapper/*.xml #spirng配置 spring: application: name: SpringCloud-provider-dept-8001 #数据源 datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: root
-
mapper层及mapperxml
@Mapper public interface DeptMapper { /** * 添加部门 * @param dept * @return */ public boolean addDept(Dept dept); /** * 查询员id查询部门 * @param id * @return */ public Dept queryById(Long id); /** * 查询部门信息 * @return */ public List<Dept> queryAll(); }
<?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.springcloud.mapper.DeptMapper"> <insert id="addDept" parameterType="com.springcloud.pojo.Dept"> insert into dbpt( dname, db_source) values (#{dname},DATABASE()) </insert> <select id="queryById" resultType="com.springcloud.pojo.Dept" parameterType="long"> select * from dbpt where dbptno = #{deptno} </select> <select id="queryAll" resultType="com.springcloud.pojo.Dept"> select * from dbpt; </select> </mapper>
-
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 get(@PathVariable("id") Long id){ return deptService.queryById(id); } @GetMapping("/dept/list") public List<Dept> queryAll(){ return deptService.queryAll(); } }
-
-
创建用户端80端口
-
创建model:SpringCloud-provide-dept-80
-
配置端口号
server: port: 80
-
注册RestTemplate的bean
@Configuration public class ConfigBean { @Bean public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
-
远程访问8001端口
@ResponseBody @RestController public class DeptConsumerContorller { // 消费者,不应该有service层 // RestTemplate 供我们直接调用 注册到spring中 //(url,实体:Map,class<T> responseType) @Autowired private RestTemplate restTemplate;//提供多种便捷访问远程HTTP服务的方法,简单的Restful服务模板 private static final String REST_URL_PREFIX = "http://localhost:8001"; @RequestMapping("/consumer/dept/add") public boolean addDept(Dept dept){ //请求的地址,相应的类型,以及携带的参数 return restTemplate.getForObject(REST_URL_PREFIX+"/dept/add",Boolean.class); } @RequestMapping("/consumer/dept/get/{id}") public Dept get(@PathVariable("id")Long id){ return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class); } @RequestMapping("/consumer/dept/list") public List<Dept> queryAll(){ return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class); } }
-
6、Eureka(注册中心)服务注册与发现
6.1、什么是Eureka
- Netfilx在设计Eureka时,遵循AP原则
- Eureka是Netflix的一个子模块,也是核心模块之一。Eureka是一 个基于REST的服务, 用于定位服务,以实现云端中间层服务发现和故障转移,服务注册与发现对于微服务来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于Dubbo的注册中心,比如Zookeeper;
6.2、原理讲解
- Eureka(优瑞卡)的基本架构
- SpringCloud封装了NetFlix公司开发的Eureka模块来实现服务注册和发现(对比Zookeeper)
- Eureka采用了C-S的架构设计,EurekaServer 作为服务注册功能的服务器,他是服务注册中心
- 而系统中的其他微服务。使用Eureka的客户端连接到EurekaServer并维持心跳连接。这样系统的维护人员就可以通过EurekaServer来监控系统中各个微服务是否正常运行,SpringCloud的- -些其他模块(比如Zuul)就可以通过EurekaServer来发现系统中的其他微服务,并执行相关的逻辑
- Eureka包含两个组件: Eureka Server和Eureka Client。
- Eureka Server提供服务注册服务,各个节点启动后,会在EurekaServer中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
- Eureka Client是一个Java客户端, 用于简化EurekaServer的交互, 客户端同时也具备-一个内置的,使用轮询负载算法的负载均衡器。在应用启动后,将会向EurekaServer发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将 会从服务注册表中把这个服务节点移除掉(默认周期为90秒)
- 三大角色
- Eureka Server:提供服务的注册于发现。
- Service Provider:将自身服务注册到Eureka中,从而使消费方能够找到。
- Service Consumer:服务消费方从Eureka中获取注册服务列表,从而找到消费服务。
6.3、代码实现
-
创建model:SpringCloud-eureka-7001
-
7001导入依赖
<dependencies> <!--springcloud依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <!--热部署--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies>
-
写配置文件
server: port: 7001 #Eureka配置 eureka: instance: hostname: localhost #eureka服务端的实例名称 client: register-with-eureka: false #表示是否向eureka注册中心注册自己 fetch-registry: false #如果为flase表示自己为客户注册中心 #别人连它怎么连 service-url: #监控页面 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
-
写启动类
@SpringBootApplication @EnableEurekaServer //服务端的启动类,它可以接受别人接受进来 public class EurekaService_7001 { public static void main(String[] args) { SpringApplication.run(EurekaService_7001.class,args); } }
-
启动测试
-
配置8001端口为服务端
<!-- eureka服务注册 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.7.RELEASE</version> </dependency>
#eureka的配置,将服务注册进去 eureka: client: service-url: defaultZone: http://127.0.0.1:7001/eureka/ instance: instance-id: springcloud-provider-dept8001 #修改eureka上默认描述信息
@SpringBootApplication @EnableEurekaClient //自动在服务启动后自动注册到eureka中 public class DeptProvider_8001 { //启动类 public static void main(String[] args) { SpringApplication.run(DeptProvider_8001.class,args); } }
-
先启动7001eureka注册中心,再启动服务端,页面测试
-
如果关闭掉8001,eureka会开启保护机制
自我保护机制
- 某时刻某一 个微服务不可以用了,eureka不会立刻清理,依旧会对该微服务的信息进行保存!
- 默认情况下,如果EurekaServer在一定时间内没有接收到某 个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka之间无法正常通行,以上行为可能变得非常危险了,因为微服务本身其实是健康的,此时本不应该注销这个服务。Eureka通过 自我保护机制来解决这个问题,当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式, EurekaServer就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该EurekaServer节点会自动退出自我保护模式。
- 在自我保护模式中,EurekaServer会保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该EurekaServer节 点就会自动退出自我保护模式。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。
- 综上,自我保护模式是一 种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮和稳定
- ●在SpringCloud中, 可以使用eureka. server . enable-self-preservation = false 禁用自我保护模式[不推荐关闭自我保护机制]
6.4、拿取微服务的一些信息
//获取一些配置信息
@Autowired
private DiscoveryClient discoveryClient;
//从注册进来的微服务获取一些信息
@GetMapping("/dept/discovery")
public Object discovery(){
//获取微服务列表
List<String> services = discoveryClient.getServices();
System.out.println("discovery下的service"+services);
//得到一个具体的微服务信息,通过具体的微服务id来取
List<ServiceInstance> instances = discoveryClient.getInstances("SPRINGCLOUD-PROVIDER-DEPT-8001");
for (ServiceInstance instance : instances) {
System.out.println(
instance.getHost()+"\t"+
instance.getServiceId()+"\t"+
instance.getPort()+"\t"+
instance.getUri()
);
}
return this.discoveryClient;
}
启动类
@SpringBootApplication
@EnableEurekaClient //自动在服务启动后自动注册到eureka中
@EnableDiscoveryClient //服务发现
public class DeptProvider_8001 {
//启动类
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8001.class,args);
}
}
6.5、搭建Eureka集群
创建model:SpringCloud-eureka-7001,SpringCloud-eureka-7002,SpringCloud-eureka-7003,分别导入依赖,创建启动类。更改配置文件
通过service-url将三个节点连接起来
server:
port: 7001
#Eureka配置
eureka:
instance:
hostname: localhost #eureka服务端的实例名称
client:
register-with-eureka: false #表示是否向eureka注册中心注册自己
fetch-registry: false #如果为flase表示自己为客户注册中心
#别人连它怎么连
service-url: #监控页面,默认为8761端口
defaultZone: http://127.0.0.1:7002/eureka/,http://127.0.0.1:7003/eureka/
将服务提供端8001注册到集群
#Eureka
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:7001/eureka/,http://127.0.0.1:7002/eureka/,http://127.0.0.1:7003/eureka/
instance:
instance-id: springcloud-provider-dept8001 #修改eureka上默认描述信息
6.6、CAP原则
RDBMS (Mysq|. Oracle、 sqlServer) ===>ACID
NoSQL (redis、 mongdb) ===> CAP
-
CAP原则(CA\AP\CP,一般只满足两个)
C (Consistency)强一致性
A (Availability)可用性
P (Partition tolerance)分区容错性
-
CAP理论的核心
- 一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求
- 根据CAP原理,将NoSQL数据库分成了满足CA原则,满足CP原则和满足AP原则三大类:
- CA:单点集群,满足一致性,可用性的系统,通常可扩展性较差
- CP:满足一致性,分区容错性的系统,通常性能不是特别高
- AP:满足可用性,分区容错性的系统,通常可能对一致性要求低一些
-
Eureka保证的是AP
Eureka看明白了这一点, 因此在设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册时,如果发现连接失败,则会自动切换至其他节点,只要有一台Eureka还在,就能保住注册服务的可用性,只不过查到的信息可能不是最新的,除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
-
Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务
2. Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上(即保证当前节点依然可用) 3. 当网络稳定时,当前实例新的注册信息会被同步到其他节点中
-
因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪
7、Ribbon负载均衡
7.1、什么是负载均衡
-
LB,即负载均衡(Load Balance),在微服务或分布式集群中经常用的一种应用。
-
负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA (高可用)。
-
常见的负载均衡软件有Nginx, Lvs 等等
-
dubbo、SpringCloud中均给我们提供 了负载均衡,SpringCloud的负载均衡算法可以自定义
-
负载均衡简单分类:
-
集中式LB
即在服务的消费方和提供方之间使用独立的LB设施,如Nginx,油该设施负责把访问请求通过某种策略转发至服务的提供方!
-
进程式LB
- 将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出-一个合适的服务器。
- Ribbon就属于进程内LB, 它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址!
-
7.2、代码实现
1.80端口导入依赖
<!-- eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<!-- ribbon -->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
2.configBean添加注解
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced //Ribbon
//IRule
//RoundRobinRule 轮询
//RandomRule 随机
//AvailabilityFilteringRule :会先过滤掉跳闸、访问故障的服务,对剩余的进行轮询
//RetryRule:按照轮询获取服务,如果服务获取失败,则会在指定时间内进行重试
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
3.restTemplate访问改为按服务名称访问
//通过ribbon实现的时候,这里的地址是变量,通过服务名来访问,一个服务在三个接口上,根据服务名可以选择三个接口中的一个访问,而写死只能访问固定,达不到负载均衡就效果
//private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT-8001";
4.搭建多个微服务模块
创建SpringCloud-provider-dept-8002模块、SpringCloud-provider-dept-8003模块,拷贝8001三份,修改配置文件
server:
port: 8002
#mybatis配置
mybatis:
#扫包
type-aliases-package: com.springclouod.pojo
#mybatis配置文件映射
config-location: classpath:mybatis/mybatis-config.xml
#mapper映射
mapper-locations: classpath:mybatis/mapper/*.xml
#spirng配置
spring:
application:
name: SpringCloud-provider-dept-8001
#数据源
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/db02?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
#Eureka
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:7001/eureka/,http://127.0.0.1:7002/eureka/,http://127.0.0.1:7003/eureka/
instance:
instance-id: springcloud-provider-dept8002 #修改eureka上默认描述信息
修改主启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class DeptProvider_8002 {
//启动类
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8002.class,args);
}
}
5、启动测试
依次启动7001、7002、7003、8001、8002、8003、80服务测试
第一次查询
第二次访问
第三次访问
实现了负载均衡!
7.3、自定义负载均衡规则
创建自定义的算法(重写IRule接口)
MyRule.java
import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyRule {
@Bean
public IRule Myrule(){
return new JJRule();
}
}
JJRule.java
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class JJRule extends AbstractLoadBalancerRule {
//每个服务访问五次,换下一个服务
//total = 0 , 如果=5,则访问下一个节点
//index = 0 , 如果total=5,则index+1
private Integer total = 0; //当前服务被调用的次数
private Integer currenindex = 0; //当前谁提供的服务
//@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
Server server = null;
while (server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers();//获得活着的服务
List<Server> allList = lb.getAllServers();//获得全部服务
int serverCount = allList.size();
if (serverCount == 0) {
/*
* No servers. End regardless of pass, because subsequent passes
* only get more restrictive.
*/
return null;
}
// int index = chooseRandomInt(serverCount);//生成区间随机数
// server = upList.get(index);//根据随机数从活着的服务获得某一个
//=====================================================================
if(total < 5){
server = upList.get(currenindex);
total++;
}else {
total = 0;
currenindex++;
if (currenindex >= upList.size()){
currenindex = 0;
}
server = upList.get(currenindex);//从活着的服务中获取一个
}
//========================================================================
if (server == null) {
/*
* The only time this should happen is if the server list were
* somehow trimmed. This is a transient condition. Retry after
* yielding.
*/
Thread.yield();
continue;
}
if (server.isAlive()) {
return (server);
}
// Shouldn't actually happen.. but must be transient or a bug.
server = null;
Thread.yield();
}
return server;
}
protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);
}
@Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
// TODO Auto-generated method stub
}
}
实际上是重写了接口
8、Feign负载均衡
8.1、什么是Feign
默认集成Ribbon
- feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似controller调用service。 SpringCloud集成了Ribbon和Eureka,可在使用Feign时提供负载均衡的http客户端。
- 只需要创建一一个接口,然后添加注解即可!
- feign,主要是社区,大家都习惯面向接C编程。这个是很多开发人员的规范。调用微服务访问两种方法
- 微服务名字[ ribbon]
- 接口和注解[feign ]
8.2、Feign能干什么
-
Feign旨在使编写Java Http客户端变得更容易
-
前面在使用Ribbon + RestTemplate时, 利用RestTemplate对Http请求的封装处理,形成了一 套模板化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止- -处, 往往一一个接口会被多处调用, 所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。 所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义,**在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置它(类似于以前Dao接口上标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可)**即可完成对服务提供方的接口绑定,简化了使用Spring Cloud Ribbon时,自动封装服务调用客户端的开发量。
-
**Feign集成了Ribbon。**利用Ribbon维护了MicroServiceCloud-Dept的服务列表信息,并且通过轮询实现了客户端的负载均衡,而与Ribbon不同的是,通过Feign只需要定义服务绑定接口且以声明式的方法,优雅而且简单的实现了服务调用。
8.3、代码实现
只需要在接口上面加fegin注解,就能标注它是fegin配置
1.创建模块SpringCloud-consumer-dept-feign,将80端口复制一份到此模块,模拟Feign负载均衡
2.在SpringCloud-api模块中导入Feign依赖,创建service包,创建DeptClientService接口
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT-8001")
public interface DeptClientService {
@RequestMapping("/dept/get/{id}")
public Dept queryById(@PathVariable("id") Long id);
@RequestMapping("/dept/list")
public List<Dept> queryAll();
@RequestMapping("/dept/add")
public boolean addDept(Dept dept);
}
3.去实现这个接口
@ResponseBody
@RestController
public class DeptConsumerContorller {
@Autowired
private DeptClientService deptClientService;
@RequestMapping("/consumer/dept/add")
public boolean addDept(Dept dept){
return this.deptClientService.addDept(dept);
}
@RequestMapping("/consumer/dept/get/{id}")
public Dept get(@PathVariable("id")Long id){
return this.deptClientService.queryById(id);
}
@RequestMapping("/consumer/dept/list")
public List<Dept> queryAll(){
return this.deptClientService.queryAll();
}
}
之前我们用的是在这个contoller层去通过服务名称去访问方法,现在我们把名称写在了接口注解上
4.启动类注解
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.springcloud"})
public class FeignDeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(FeignDeptConsumer_80.class,args);
}
}
5.启动测试,发现一样实现了负载均衡的效果
9.Hystrix服务熔断(断路由)
分布式系统面临的问题
复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免的失败!
9.1、服务雪崩
多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的“扇出”、如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应"。
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒中内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障,这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
我们需要弃车保帅。
9.2、什么是Hystrix
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等,Hystrix能够保证在一 个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
“断路器”本身是一种开关装置, 当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),**向调用方返回一个服务预期的,可处理的备选响应(FalBack) ,而不是长时间的等待或者抛出调用方法无法处理的异常,这样就可以保证了服务调用方的线程不会被长时间,**不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
9.3、Hystrix能干嘛
- 服务降级
- 服务熔断
- 服务限流
- 接近实时的流量监控
- …
官网资料:https://github.com/Netflix/Hystrix/wiki
9.4、服务熔断
9.4.1、服务熔断是什么
熔断机制是对应雪崩效应的一种微服务链路保护机制。
当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,**进而熔断该节点微服务的调用,快速返回错误的响应信息。**当检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况, 当失败的调用到一定阈值, 缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。
9.4.2、代码实现
1.创建模块SpringCloud-provider-dept-Hystrix-8001,将8001端口完全复制过来,改掉启动类的名字
@SpringBootApplication
@EnableEurekaClient
public class DeptProviderHystrix_8001 {
//启动类
public static void main(String[] args) {
SpringApplication.run(DeptProviderHystrix_8001.class,args);
}
}
2.导入依赖
<!--Hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
3.重写controller类,给方法添加一个备选方法
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@GetMapping("/dept/get/{id}")
//熔断的方案,当服务异常时,指向异常处理方法
@HystrixCommand(fallbackMethod = "hystrixGet")
public Dept get(@PathVariable("id") Long id){
Dept dept = deptService.queryById(id);
if (dept==null){
throw new RuntimeException("id=>"+id+",不存在该用户,信息未找到");
}
return dept;
}
//备选方案,假如上面的方法需要抛出异常
public Dept hystrixGet(@PathVariable("id") Long id){
return new Dept()
.setDeptno(id)
.setDname("id=>+id+,信息未找到,来自Hystrix")
.setDb_source("没有这个database");
}
}
4.添加对熔断的支持
@SpringBootApplication
@EnableEurekaClient//服务启动后自动注册到Eureka中
@EnableDiscoveryClient//服务发现
@EnableCircuitBreaker//添加对熔断的支持,CircuitBreaker翻译断路由
public class DeptProviderHystrix_8001 {
//启动类
public static void main(String[] args) {
SpringApplication.run(DeptProviderHystrix_8001.class,args);
}
}
5.启动7001、7002、7003、Hystrix8001、80测试
-
当我查询我有的数据时(非异常)
-
当我查询我没有的数据时(异常情况下)
发现在不同情况下ia,会执行不同的方法
9.5、服务降级
9.5.1、服务降级是什么
整体资源不够用时,先把一些访问量少的服务关掉,当通过高并发期后,再启动这些服务
通过客户端去实现,不能通过服务端
9.5.2、代码实现
1.给service层编写降级工厂类
//降级
@Component
public class DeptClientServiceFallbackFactory implements FallbackFactory {
@Override
public DeptClientService create(Throwable throwable) {
return new DeptClientService() {
@Override
public Dept queryById(Long id) {
return new Dept()
.setDeptno(id)
.setDname("没有对应的信息,客户端提供了降级服务,这个服务已经被关闭")
.setDb_source("没有数据");
}
@Override
public List<Dept> queryAll() {
return null;
}
@Override
public boolean addDept(Dept dept) {
return false;
}
};
}
}
2.service层和降级类关系在一起
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT-8001",fallbackFactory = DeptClientServiceFallbackFactory.class)
public interface DeptClientService {
@RequestMapping("/dept/get/{id}")
public Dept queryById(@PathVariable("id") Long id);
@RequestMapping("/dept/list")
public List<Dept> queryAll();
@RequestMapping("/dept/add")
public boolean addDept(Dept dept);
}
3.在fegin客户端开启降级fegin.hystrix
#开启降级fegin.hystrix
feign:
hystrix:
enabled: true
4.启动7001、7002、8001、fegin80测试
-
当一切正常运行时
-
服务熔断
-
关闭掉8001服务提供者
发现服务还能运行,此时采用了降级处理,用户还可以访问别的服务,但是此服务已经被关闭。 -
服务熔断:
服务端 某个服务超时或者异常,引起熔断 像保险丝
-
服务降级
客户端 从整体网站请求负载考虑,当某个服务熔断或者关闭之后,服务将不再被调用,此时在客户端我们可以准备一个自己的失败回调(FallbackFactory),返回一个默认的值(缺省的值),整体服务水平下降了,但是好歹能用,比直接挂掉强。
9.6、Dashboard流监控
1.创建模块SpringCloud-consumer-hystrix-Dashboard,复制80端口依赖,导入新依赖
<!--Hystrix依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<!--Hystrix流量监控依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
2.配置文件
server:
port: 9001
3.启动类
@SpringBootApplication
@EnableHystrixDashboard //开启监控服务
public class DeptConsumerDashboard_9001 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumerDashboard_9001.class,args);
}
}
4.服务端监控信息依赖
<!--actuator完善监控信息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
5.启动9001
6.将检测的服务提供端注册(带有熔断的8001)
//增加一个servlet
@Bean
public ServletRegistrationBean HystrixMetricsStreamServlet(){
ServletRegistrationBean RegistrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
RegistrationBean.addUrlMappings("/actuator/hystrix.stream");
return RegistrationBean;
}
7.启动9001、7001、8001,访问8001:http://localhost:8001/actuator/hystrix.stream
可以ping出数据流
8.将要检测的内容填入Dashboard
9.不断地去请求服务,就可以看出流量监控
10.Zuul服务路由网关
10.1、什么是zuul
Zuul包含了对请求的路由和过滤两个最主要的功能:
其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础, 而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础。Zuul和Eureka进行整合, 将ZuuI自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的消息,也即以后的访问微服务都是通过
Zuul跳转后获得。
注意: Zuul服务最终还是会注册进Eureka
提供:代理+路由+过滤三大功能
10.2、zuul能干嘛
-
路由
-
过滤
官网文档: https://github.com/Netflix/zuul
10.3、代码实现
1.创建新模块SpringCloud-zuul-9527
2.导入依赖,将dashboard的依赖导过来,再加入一些自己的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
3.配置文件application.yml
server:
port: 9527
spring:
application:
#名字
name: springcloud-zuul
eureka:
client:
#指向哪些集群
service-url:
defaultZone: http://127.0.0.1:7001/eureka/,http://127.0.0.1:7002/eureka/,http://127.0.0.1:7003/eureka/
instance:
#实例id
instance-id: zuul9527.com
#真实地址隐藏
prefer-ip-address: true
#info页面,可配置一些要展示的东西,也可不配
info:
app.name: jinjie-springcloud
4.主启动类
package com.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy//开启zuul
public class ZuulApplication_9527 {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication_9527.class,args);
}
}
5.为了直观的感受到效果,将域名改一下,到C:\Windows\System32\drivers\etc路径下,新增一个域名解析
6.启动测试,依次启动7001、8001hystrix、9527
两个都被注册进来,正常访问
用我们配置的路由网关去访问
http://www.jinjie.com:9527/springcloud-provider-dept-8001/dept/get/1
http://路由网关:zuul配置的端口号/服务名/具体服务
发现也可以访问到
我们可以通过zuul配置将服务名称替换掉
zuul:
routes:
mydept.serviceId: springcloud-provider-dept-8001
mydept.path: /mydept/**
#不能通过这个路径访问了,"*"隐藏全部的
ignored-services: springcloud-provider-dept-8001
重新启动9527,再去访问一下
发现我们将真实的服务名springcloud-provider-dept-8001替换成了mydept,减少危险
之前的路径不能访问了,这样我们就可以把真实项目的东西隐藏起来,统一只用路由网关管理
我们还可以设置公共前缀
zuul:
routes:
mydept.serviceId: springcloud-provider-dept-8001
mydept.path: /mydept/**
#不能通过这个路径访问了,"*"隐藏全部的
ignored-services: springcloud-provider-dept-8001
prefix: /jin
重新启动测试
这样也访问不到了,我们需要加上公共前缀
访问成功!
11.Config分布式配置
11.1、概述
分布式系统面临的–配置文件的问题
微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务,由于每个服务都需要必要的配置信息才能运行,所以-套集中式的,动态的配置管理设施是必不可少的。SpringCloud提供了ConfigServer来解决这个问题,我们每一个微服务 自己带着一个application.yml, 那上百的配置文件要修改起来,岂不是要发疯!
什么是SpringCloud config分布式配置中心
Spring Cloud Config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环节提供了一个中心化的外部配置。
Spring Cloud Config 分为服务端和客户端两部分
服务端也称为分布式配置中心,它是一 个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密,解密信息等访问接口。
客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。配置服务器默认采用gjit来存储配置信息,这样就有助于对环境配置进行版本管理。并且可以通过git客户端工具来方便的管理和访问配置内容。
11.2、Git环境搭建
创建一个项目springcloudconfig
拉取下来写一个配置文件提交回去,保证可用
spring:
profiles:
active: dev
---
spring:
profiles: dev
application:
name: springcloud-config-dev
---
spring:
profiles: test
application:
name: springcloud-config-test
11.3、服务端连接git配置
1.创建模块springcloud-config-server-3344
2.导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringCloud</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>SpringCloud-config-service-3344</artifactId>
<dependencies>
<!-- config -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
<!-- SpringBoot启动器 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
3.编写配置文件
server:
port: 3344
spring:
application:
name: spring-config-3344
#告诉别人我是谁 命名
cloud:
config:
server:
git:
uri: https://github.com/Josoncube/springcloudconfig.git
# svn:
4.编写主启动类
package com.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
@EnableConfigServer //config注解
public class Config_Server_3344 {
public static void main(String[] args) {
SpringApplication.run(Config_Server_3344.class,args);
}
}
5.启动3344,拿到远程配置文件,通过访问端口号+配置文件名称+具体名称访问
- http://localhost:3344/application-dev.yml
- http://localhost:3344/application-test.yml
通过以下方式都可以访问到
11.4、客户端连接服务端访问远程
1.本地编写配置文件config-client.yml,提交到git
spring:
profiles:
active: dev
---
server:
port: 8201
#spirng配置
spring:
profiles: dev
application:
name: SpringCloud-provider-dept
#Eureka
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:7001/eureka/,http://127.0.0.1:7002/eureka/,http://127.0.0.1:7003/eureka/
---
server:
port: 8202
#spirng配置
spring:
profiles: test
application:
name: SpringCloud-provider-dept
#Eureka
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:7001/eureka/,http://127.0.0.1:7002/eureka/,http://127.0.0.1:7003/eureka/
2.创建模块SpringCloud-config-client-3355,导入客户端依赖
<dependencies>
<!--config-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
<!-- SpringBoot启动器 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
3.编写配置文件
-
bootstrap.yml
#系统级别的配置 spring: cloud: config: uri: http://localhost:3344 name: config-client #需要从git上读取的资源名称,不需要后缀 profile: dev #生产环境 label: master #哪个分支 #这四个属性组成了刚刚的访问地址 #http://localhost:3344/config-client-dev.yml
-
application.yml
#用户级别的配置 spring: application: name: spring-cloud-config-client-3355
4.创建主启动类和配置类
- 配置类ConfigClientController,客户去拿取远程git上的一些信息
package com.springcloud.Controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@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 +
"eurekaServer:"+eurekaServer +
"port:"+port;
}
}
-
启动类
package com.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication(exclude={DataSourceAutoConfiguration.class}) public class ConfigClient_3355 { public static void main(String[] args) { SpringApplication.run(ConfigClient_3355.class,args); } }
5.启动3344看服务端能否拿到
6.启动3355看客户端能否拿到服务端(要访问的是8201端口,因为config-client配置了端口号)
发现可以拿到
7.如果将配置文件中profile:属性改为test,则启动3355时,将启动的时8202端口,访问的也是test
**作用:**动态配置,运维人员直接在git上远程配置,不需要改动后台代码
11.5、动态刷新配置
我们发现客户端每次获取新的配置是需要重启客户端的,这时我们要用动态刷新来避免这个问题
1.导入监控依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.修改yml配置文件,暴露监控端口
management:
endpoints:
web:
exposure:
include: "*"
3.@RefreshScope在业务类Controller修改
@RestController
@RefreshScope
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 +"\n"+
"eurekaServer:"+eurekaServer +"\n"+
"port:"+port;
}
}
4.修改github上的配置
5.3344可随时拿取最新配置,但3355不行
6.发送post请求
curl -X POST “http://localhost:8201/actuator/refresh”
7.刷新成功
总结:
12.RabbitMQ配置
1.安装Erlang语言包
2.配置Erlang语言环境
3.安装mq
4.安装web可视化
5.web端查看localhost:15672,进入登录界面,默认账号密码为guest
13.Bus消息总线
1.什么是消息总线
在微服务架构的系统中,通常会使用轻量级的消息代理来构建一 个共用的消息主题,并让系统中所有微服务实例都连接上来。 由于该主题中产生的消息会被所有实例监听和消费,所以称它为消息总线。在总线上的各个实例,都可以方便地广播一些需要让其他连接在该主题上的实例都知道的消息。
2.bus能做什么
Spring Cloud Bus能管理和传播分布式系统间的消息,就像一个分布式执行器x可用于广播状态更改、事件推送等,也可以当作微服务间的通信通道
3.基本原理
ConfigClient实例都监听MQ中同一个topic(默认是springCloudBus)。当-个服务刷新数据的时候,它会把这个信息放入到Topic中,这样其它监听同一Topic的服务就能得到通知,然后去更新自身的配置。
4.动态刷新全局广播
一次广播,全部生效
1.首先具备良好的RabbitMQ环境
2.以3355为模板再制作一个3366
咋们要通过给服务端3344添加消息总线,来传递到3355、3366
3.添加消息总线RabbitMQ支持
-
导入依赖
<!--Bus-mq,添加mq支持,bus和mq整合--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
-
yml文件修改
spring: application: name: spring-cloud-config-client-3366 rabbitmq: host: mybroker.com port: 5672 username: guest password: guest cloud: bus: enabled: true trace: enabled: true management: endpoints: web: exposure: include: 'bus-refresh' management: endpoints: web: exposure: include: "*"
-
启动类
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class}) @EnableConfigServer //config注解 @EnableEurekaClient @EnableDiscoveryClient @RestController public class Config_Server_3344 { public static void main(String[] args) { SpringApplication.run(Config_Server_3344.class,args); } }
要在服务端和所有客户端都添加mq-bus支持
4.依次启动7001、7002、7003eureka集群、3344、3355、3366
3344
3355
3366
5.然后我们将git上的版本号改为version12,在cmd去post一下,curl -X POST “http://localhost:3344/actuator/bus-refresh”
6.发现3355、3366都同步配置类,这样,我们就实现了一次广播,全部生效,通过3344将配置传了出去
5.动态刷新定点通知
只通知3355、不通知3366
如果我们想要只通知3355不通知3366,只需要在发送post请求时,写指定的服务
比如:curl -X POST “http://localhost:3344/actuator/bus-refresh/spring-cloud-config-client-3355:3355”
格式为:curl -X POST “http://localhost:3344/actuator/bus-refresh/微服务名称:端口号”
6.github配置自动刷新配置
1.到需要配置的项目下
2.添加配置(不能用本地服务器地址)