一、介绍
Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子,它只是将各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
1.1、Springboot和Springcloud的关系
- SpringBoot专注于开发方便的开发单个个体微服务
- SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务,整合并管理起来,为各个微服务之间提供:配置管理、服务发现、断路器、路由、为代理、事件总栈、全局锁、决策竞选、分布式会话等等集成服务
- SpringBoot可以离开SpringCloud独立使用,开发项目,但SpringCloud离不开SpringBoot,属于依赖关系
- SpringBoot专注于快速、方便的开发单个个体微服务,SpringCloud关注全局的服务治理框架
springboot可以单独使用,它不依赖于springcloud
而springcloud必然依赖于springboot,属于依赖关系
最大区别:Spring Cloud 抛弃了Dubbo的RPC通信,采用的是基于HTTP的REST方式
1.2、Springboot和Springcloud版本兼容关系
| SpringBoot | SpringCloud | 关系 |
|---|---|---|
| 1.2.x | Angel版本(天使) | 兼容SpringBoot1.2x |
| 1.3.x | Brixton版本(布里克斯顿) | 兼容SpringBoot1.3x,也兼容SpringBoot1.4x |
| 1.4.x | Camden版本(卡姆登) | 兼容SpringBoot1.4x,也兼容SpringBoot1.5x |
| 1.5.x | Dalston版本(多尔斯顿) | 兼容SpringBoot1.5x,不兼容SpringBoot2.0x |
| 1.5.x | Edgware版本(埃奇韦尔) | 兼容SpringBoot1.5x,不兼容SpringBoot2.0x |
| 2.0.x | Finchley版本(芬奇利) | 兼容SpringBoot2.0x,不兼容SpringBoot1.5x |
| 2.1.x | Greenwich版本(格林威治) |
1.3、五大核心组件
- 服务发现——Netflix Eureka客服端
- 负载均衡——Netflix Ribbon
- 断路器——Netflix Hystrix
- 服务网关——Netflix Zuul(本文以gateway取代)
- 分布式配置——Spring Cloud Config
二、环境搭建
2.1、搭建父工程
-
创建一个纯maven项目
-
pom.xml文件
<!--打包方式为pom--> <packaging>pom</packaging> <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> <!--springcloud依赖--> <dependency> <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> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> <!--log4j--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}}</version> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> </dependencies> </dependencyManagement>
2.2、搭建api工程
-
pom.xml文件
<!--当前的module自己需要的依赖,如果父依赖已经配置了版本这里就不用写--> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> <version>1.4.6.RELEASE</version> </dependency> </dependencies> -
创建pojo项目结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9dAKYpJc-1663401681471)(C:\Users\22341\AppData\Roaming\Typora\typora-user-images\image-20220912141340366.png)]
-
编写Dept实体类
@Data @NoArgsConstructor @Accessors(chain = true)//链式写法 public class Dept implements Serializable { //Dept 实体类 orm 类表关系映射 private Long deptno;//主键 private String dname; //这个数据存在哪个数据库的字段~ 微服务,一个服务对应一个数据库,同一个信息可能存在不同的数据库 private String db_source; public Dept(String dname){ this.dname = dname; } } -
数据库成功对应实体类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zkdSp4sk-1663401681472)(C:\Users\22341\AppData\Roaming\Typora\typora-user-images\image-20220912141512888.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-llb4H2Zl-1663401681473)(C:\Users\22341\AppData\Roaming\Typora\typora-user-images\image-20220912141528847.png)]
2.3、搭建服务提供者
-
pom.xml文件
<dependencies> <!--我们需要拿到实体类,所以要配置api module--> <dependency> <groupId>org.luffy</groupId> <artifactId>springcloud-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <!--test--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--jetty--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <!--热部署工具--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies> -
搭建项目路径创建对应文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IGhZQSaJ-1663401681473)(C:\Users\22341\AppData\Roaming\Typora\typora-user-images\image-20220912142124978.png)]
-
application.yaml
server: port: 8001 # mybatis配置 mybatis: type-aliases-package: com.luffy.springcloud.pojo # config-location: classpath:mybatis/mybatis-config.xml mapper-locations: classpath:mybatis/mapper/*.xml # 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=utf8&useSSL=false username: root password: root -
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> <!--开启二级缓存--> <setting name="cacheEnabled" value="true"/> </settings> </configuration> -
DeptMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.luffy.springcloud.dao.DeptDao"> <insert id="addDept" parameterType="Dept"> insert into dept (dname, db_source) values (#{dname}, DATABASE()) </insert> <select id="queryById" resultType="Dept" parameterType="Long"> select * from dept where deptno = #{deptno} </select> <select id="queryAll" resultType="Dept"> select * from dept </select> </mapper> -
DeptDao
@Mapper @Repository public interface DeptDao { boolean addDept(Dept dept); Dept queryById(Long id); List<Dept> queryAll(); } -
DeptService
public interface DeptService { boolean addDept(Dept dept); Dept queryById(Long id); List<Dept> queryAll(); } -
DeptServiceImpl
@Service public class DeptServiceImpl implements DeptService{ @Autowired private DeptDao deptDao; @Override public boolean addDept(Dept dept) { return deptDao.addDept(dept); } @Override public Dept queryById(Long id) { return deptDao.queryById(id); } @Override public List<Dept> queryAll() { return deptDao.queryAll(); } } -
DeptController
@RestController public class DeptController { @Autowired private DeptService deptService; @PostMapping("/dept/add") public boolean addDept(@RequestBody Dept dept) { return deptService.addDept(dept); } @GetMapping("/dept/get/{id}") public Dept get(@PathVariable("id") Long id) { Dept dept = deptService.queryById(id); if (dept == null) { throw new RuntimeException("Fail"); } return dept; } @GetMapping("/dept/list") public List<Dept> queryAll() { return deptService.queryAll(); } } -
启动类
@SpringBootApplication public class DeptProvider_8001 { public static void main(String[] args) { SpringApplication.run(DeptProvider_8001.class, args); } }
2.4、搭建服务消费者
-
pom.xml文件
<dependencies> <dependency> <groupId>org.luffy</groupId> <artifactId>springcloud-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies> -
搭建项目路径创建对应文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-juQdFBVj-1663401681473)(C:\Users\22341\AppData\Roaming\Typora\typora-user-images\image-20220912142535263.png)]
-
application.yaml
server: port: 80 -
ConfigBean
@Configuration public class ConfigBean { // 配置负载均衡 // IRule // RoundRobinRule 轮询 // RandomRule 随机 // AvailabilityFilteringRule 会先过滤,跳闸,访问故障的服务,对剩下的进行轮询 // RetryRule:会先按照论照轮询获取服务~如果服务获取失败,则会在指定的时间内进行,重试 @LoadBalanced @Bean public RestTemplate getRestTemplate() { return new RestTemplate(); } } -
DeptConsumerController(消费者没有Service层)
@RestController public class DeptConsumerController { //理解:消费者,不应该有service层 //RestTemplate ... 供我们直接调用就可以了!注册到spring中 @Autowired private RestTemplate restTemplate; //提供多种远程便捷访问远程http服务的方法 //使用ribbon作为负载均衡,这里的地址应该是一个变量,通过服务名来访问 private static final String REST_URL_PREFIX = "http://localhost:8001"; @RequestMapping("/consumer/dept/add") public boolean add(Dept dept) { return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class); } //没有service层,通过http://localhost:8001/dept/list返回 @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> list() { return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class); } } -
启动类
@SpringBootApplication public class DeptConsumer_80 { public static void main(String[] args) { SpringApplication.run(DeptConsumer_80.class,args); } }
2.5、运行思路
- 服务提供者是8001端口,在8001端口运行Controller里的路径代码即可本地调用
- 服务消费者是80端口,默认的也是80端口,所以一般都会把消费者放在80端口
- 在80端口调用Controller的路径代码,会通过RestTemplate对象调用即实现远程调用
三、Eureka服务注册与发现
3.1、什么是Eureka
-
Netflix在设计Eureka时,遵循的就是AP原则
-
Eureka是Netflix的一个子模块,也是核心模块之-。 Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移,服务注册与发现对于微服务来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于Dubbo的注册中心,比如Zookeeper
Eureka三大角色
-
Eureka Server:提供服务注册与发现。和zookeeper客户端一样
-
Service Provider:将自身服务注册到Eureka中,从而使消费方能够找到
-
Service Consumer:服务消费方从Eureka中获取注册服务列表,从而找到消费服务
、
3.2、Eureka服务消费 注册、信息配置、自我保护机制
前言
- 理解的不是非常透彻,这里写的是个人感悟
- Eureka是类似于注册中心,所有服务都在此注册,他们都有一个服务端口,一个服务突发情况崩了别的端口可以继续使用
一、springcloud-eureka-7001 maven项目
-
pom.xml
<!--Eureka注册中心 7001--> <artifactId>springcloud-eureka-7001</artifact <dependencies> <!--eureka的服务提供者包--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--热部署工具--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies> -
application.yaml
server: port: 7001 #Eureka配置 eureka: instance: hostname: localhost #Eureaka服务端的实例名称 client: register-with-eureka: false #表示是否向Eureka注册中心注册自己 fetch-registry: false #如果fetch-registry为false,则表示自己为注册中心 service-url: #监控页面 #点进去参考源码,可看到默认的url端口配置为8761,我们设置为自己的端口。 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka -
启动类
@SpringBootApplication @EnableEurekaServer //表示为Eureka服务端的启动类,可以接收别人注册进来 public class EurekaServer_7001 { public static void main(String[] args) { SpringApplication.run(EurekaServer_7001.class,args); } } -
运行7001端口可进入注册中心自带的网址,可查看已注册的服务
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iLy1VLsV-1663401681474)(C:\Users\22341\AppData\Roaming\Typora\typora-user-images\image-20220913153451643.png)]
二、springcloud-provider-dept-8001项目
-
pom.xml
<!--Eureka服务 没有server--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency> -
application.yaml
#Eureka的配置。 服务注册到Eureka中,需要一个路径地址 eureka: client: service-url: defaultZone: http://localhost:7001/eureka instance: #修改Eureka中status的默认描述信息。不配置默认为DESKTOP-XXX描述 instance-id: springcloud-provider-dept8001 -
启动类
@SpringBootApplication @EnableEurekaClient//在服务启动后,自动注册到Eureka注册中心中 @EnableDiscoveryClient //注册进来的微服务,获取一些信息。服务发现,扩展内容 public class DeptProvider_8001 { public static void main(String[] args) { SpringApplication.run(DeptProvider_8001.class,args); } } -
Controller
//获取一些配置的信息,得到具体的微服务 @Autowired private DiscoveryClient client; //注册进来的微服务,获取一些信息。没有实际作用 @RequestMapping("/dept/discovery") public Object discovery(){ //获取微服务列表的清单 List<String> services = client.getServices(); System.out.println("discovery=>services "+services); //得到一个具体的微服务信息,通过具体的微服务id,7001中的applicationName List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT"); for (ServiceInstance instance : instances) { System.out.println( instance.getHost()+"\t\t\t"+ instance.getPort()+"\t\t\t"+ instance.getUri()+"\t\t\t"+ instance.getServiceId()); } return this.client; }
三、自我保护机制
- 在Eureka注册中心的服务关闭之后,不会立即消失死亡,会存留几分钟,这就是Eureka的自我保护机制
- 一句话总结: 某时刻某一个微服务不可以用了 , eureka不会立刻清理,依旧会对该微服务的信息进行保存!
- 默认情况下,如果EurekaServer在一定时间内没有接收到某 个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。 但是当网络分区故障发生时,微服务与Eureka之间无法正常通行,以上行为可能变得非常危险了---- 因为微服务本身其实是健康的,此时本不应该注销这个服务。Eureka通过 自我保护机制来解决这个问题–当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障) , 那么这个节点就会进入自我保护模式。一旦进入该模式,EurekaServer就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务) .当网络故障恢复后,该EurekaServer节 点会自动退出自我保护模式。
- 在自我保护模式中,EurekaServer会保护服务注册表中的信息, 不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该EurekaServer节点就会 自动退出自我保护模式。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话:好死不如赖活着
- 综上,自我保护模式是-种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮和稳定
- 在SpringCloud中, 可以使用 eureka. server. enable-self-preservation = false 禁用自我保护模式[不推荐关闭自我保护机制]
四、Eureka监控信息info
监控信息是添加在服务项目里的
-
pom.xml
<!--Eureka的status链接xx/info点击后监控信息--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> -
application.yaml
#info配置 Eureka的status的xx/info链接点开后的info监控信息。没有太大意义 info: app.name: Love Zhao Jinmai company.name: Love Zhao Jinmai -
在Eureka界面对应的服务点击,即可显示application.yaml里info写的信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vzJIJ0uq-1663401681474)(C:\Users\22341\AppData\Roaming\Typora\typora-user-images\image-20220913154501689.png)]
3.3、Eureka集群环境配置
-
复制两个7001项目名为7002,7003,除了别名其他全部一致
-
修改C:\Windows\System32\drivers\etc路径下的hosts文件,在末尾增加如下代码
127.0.0.1 eureka7001.com 127.0.0.1 eureka7002.com 127.0.0.1 eureka7003.com -
三个项目的yaml文件要修改,增加集群代码
server: port: 7001 #Eureka配置 eureka: instance: hostname: eureka7001.com #Eureaka服务端的实例名称 client: register-with-eureka: false #表示是否向Eureka注册中心注册自己 fetch-registry: false #如果fetch-registry为false,则表示自己为注册中心 service-url: #监控页面 #单机:点进去参考源码,可看到默认的url端口配置为8761,我们设置为自己的端口。 #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka #集群(除自身外 关联其他所有) defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ -
修改8001项目的yaml文件,将服务添加到集群
#Eureka的配置。 服务注册到Eureka中,需要一个路径地址 eureka: client: service-url: defaultZone: http://localhost:7001/eureka,http://localhost:7002/eureka,http://localhost:7003/eureka instance: #修改Eureka中status的默认描述信息。不配置默认为DESKTOP-XXX描述 instance-id: springcloud-provider-dept8001 #info配置 Eureka的status的xx/info链接点开后的info监控信息。没有太大意义 info: app: love Zhao Jinmai company.name: love Zhao Jinmai -
访问7001或7002、7003都会挂载其他两个不同的集群
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IaPPKBSF-1663401681475)(C:\Users\22341\AppData\Roaming\Typora\typora-user-images\image-20220913155454163.png)]
-
当一个集群崩了不会影响其他集群
3.4、CAP原则及对比Zookeeper
理论核心
-
一个分布式系统不可能同时很好的满足-致性,可用性和分区容错性这三个需求
-
根据CAP原理,将NoSQL数据库分成了满足CA原则,满足CP原则和满足AP原则三大类:
-
CA:单点集群,满足-致性,可用性的系统,通常可扩展性较差
-
CP: 满足- -致性,分区容错性的系统,通常性能不是特别高
-
AP:满足可用性。分区容错性的系统,通常可能对一致性要求低一些
-
Eureka保证的是AP
Zookeeper保证的是CP
ACID是什么?
-
A (Atomicity)原子性
-
C (Consistency)- 致性
-
I (Isolation) 隔离性
-
D (Durability) 持久性
CAP是什么?
- C (Consistency) 强一致性
- A (Availabilty)可用性
- P (Partition tolerance)分区容错性
四、Ribbno
4.1、Ribbon介绍
- Spring Cloud Ribbon是基于Netflix Ribbon实现的一套 客户端负载均衡的工具。
- 简单的说,Ribbon是Netflix发布的开源项目, 主要功能是提供客户端的软件负载均衡算法,将NetFlix的中间层服务连接在一起。 Ribbon的客户端组件提供一系列完整的配置项如:连接超时、重试等等。简单的说,就是在配置文件中列出LoadBalancer (简称LB: 负载均衡)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法!
负载均衡简单分类:
- 集中式LB
- 即在服务的消费方和提供方之间使用独立的LB设施,如Nginx, 由该设施负责把访问请求通过某种策略转发至服务的提供方!
- 进程式LB
- 将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。
Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址!
- 将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。
**理解:**负载均衡就是不要把压力全部放到一个服务上,让它们平摊
4.2、集成Ribbon在消费者客户端
-
把8001
-
pom.xml
<!--Eureka--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--Ribbon负载均衡--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.4.6.RELEASE</version> </dependency> -
ConfigBean
@Configuration public class ConfigBean {//@Configuration=spring的 application.xml //配置负载均衡实现RestTemplate @Bean @LoadBalanced //ribbon负载均衡的作用 public RestTemplate getRestTemplate(){ return new RestTemplate(); } } -
application.yaml
server: port: 80 #Eureka配置 eureka: client: register-with-eureka: false #不向Eureka中注册自己 service-url: defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/ -
Controller
//声明提供者的localhost路径 //private static final String rest_url_prefix = "http://localhost:8001"; //通过ribbon去实现负载均衡,这里服务应该是一个变量,通过服务名来访问 * private static final String rest_url_prefix = "http://SPRINGCLOUD-PROVIDER-DEPT"; -
启动类
//消费者 运行方式80可省略 例:localhost/consumer/dept/list //Ribbon 和 Eureka 整合后,客户端可直接调用,不用关心Ip地址和端口号,会在定义的多个地址中随机选择 @SpringBootApplication @EnableEurekaClient//在服务启动后,自动注册到Eureka注册中心中 public class DeptConsumer_80 { public static void main(String[] args) { SpringApplication.run(DeptConsumer_80.class,args); } } -
启动7001、7002、7003、8001、80,可以正常查出数据,但因为服务只有一个,所有负载均衡效果不明显
4.3、使用Ribbon实现负载均衡
-
复制两个8001项目名为8002,8003,除了别名其他全部一致,数据库的db_source字段更改,代表数据源不一样,对应端口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LymKxE9J-1663401681475)(C:\Users\22341\AppData\Roaming\Typora\typora-user-images\image-20220913160859488.png)]
CREATE TABLE `dept` (
`deptno` bigint(20) NOT NULL AUTO_INCREMENT,
`dname` varchar(60) DEFAULT NULL,
`db_source` varchar(60) DEFAULT NULL,
PRIMARY KEY (`deptno`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='部门表'
INSERT INTO dept(dname,db_source) VALUES ('开发部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('项目部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('研发部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('运维部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('市场部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('人事部',DATABASE());
- 按照4.2的步骤,可以发现,每次查询的数据,数据源的值不一致,证明负载已经被均衡
4.4、Ribbon自定义负载均衡算法
-
在最底层目录的上一级创建myrule文件夹(否则会被扫描到)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wpLH5cun-1663401681475)(C:\Users\22341\AppData\Roaming\Typora\typora-user-images\image-20220913161124356.png)]
-
RuleConfig
//自定义Ribbon配置的负载均衡类,客户端RibbonConfiguration中已存在的组件与FooConfiguration中的任何组件组成(后者通常会覆盖前者) //自定义的组件请注意 它不在|程序的上下文的ComponentScan中,所以要放在单独的不重叠的包中 @Configuration public class RuleConfig { @Bean public IRule myRule() { //默认是轮询,现在我们自定义为DiyRandomRule 自定义负载均衡 return new DiyRandomRule(); } } -
DiyRandomRule
public class DiyRandomRule extends AbstractLoadBalancerRule { //代码全是复制的 DiyRandomRule.class的,自定义负载均衡需要自己修改 //当前自定义负载均衡: //每个服务访问5次。换下一个服务 //total=0,默认=0,如果=5,指向下一个服务节点 //index=0,默认0,如果total=5,则inedx+1 private int totla=0;//被调用的次数 private int currentIndex=0;//当前是谁在提供服务 public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { return null; } else { 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) { return null; } //int index = this.chooseRandomInt(serverCount);//生成区间随机数 //server = (Server) upList.get(index);//从活着的服务中,随机获取一个 //================自定义负载均衡算法================== if(totla<5){ server = upList.get(currentIndex); totla++; }else{ totla=0; currentIndex++; if (currentIndex>=upList.size()){//当前节点大于活着的数量 currentIndex = 0; } server=upList.get(currentIndex);//从活着的服务中,获取指定的服务来进行操作 } //==================================================== if (server == null) { Thread.yield(); } else { if (server.isAlive()) { return server; } server = null; Thread.yield(); } } return server; } } protected int chooseRandomInt(int serverCount) { return ThreadLocalRandom.current().nextInt(serverCount); } public Server choose(Object key) { return this.choose(this.getLoadBalancer(), key); } public void initWithNiwsConfig(IClientConfig clientConfig) { } } -
启动类
@SpringBootApplication @EnableEurekaClient//在服务启动后,自动注册到Eureka注册中心中 //在微服务启动的时候就能去加载我们自定义Ribbon配置的负载均衡类,自定义为跳转5次切换节点 @RibbonClient(name="SPRINGCLOUD-PROVIDER-DEPT",configuration = RuleConfig.class) public class DeptConsumer_80 { public static void main(String[] args) { SpringApplication.run(DeptConsumer_80.class,args); } } -
因为自定义了负载均衡类就会代替自带的负载均衡
-
自定义的负载均衡执行后效果是每执行五次换一次数据源
五、Feign负载均衡
5.1、Feign 简介
-
feign 主要是社区,大家都习惯面向接口编程。这个是很多开发人员的规范。调用微服务访问两种方法
-
Feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似controller调用service. SpringCloud集成了Ribbon和Eureka,可在使用Feign时提供负载均衡的http客户端。
-
只需要创建一一个接口,然后添加注解即可!
5.2、Ribbon和Feign的区别
Ribbon和Feign都是用于调用其他服务的,不过方式不同。
Ribbon RestFul风格
Feign 面向接口
- 启动类使用的注解不同,Ribbon用的是@RibbonClient,Feign用的是@EnableFeignClients。
- 服务的指定位置不同,Ribbon是在@RibbonClient注解上声明,Feign则是在定义抽象方法的接口中使用@FeignClient声明。
- 调用方式不同,Ribbon需要自己构建http请求,模拟http请求然后使用RestTemplate发送给其他服务,步骤相当繁琐。
5.3、Feign使用接口方法调用服务
feign项目(客户端)
-
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <!--Eureka--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--Ribbon负载均衡--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--Feign--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> <version>1.4.6.RELEASE</version> </dependency> <dependency> <groupId>org.luffy</groupId> <artifactId>springcloud-api</artifactId> <version>1.0-SNAPSHOT</version> <scope>compile</scope> </dependency> </dependencies> -
在service中创建DeptClientService(这里由于项目结构原因创建在api项目中)
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT") public interface DeptClientService { @GetMapping("/dept/get/{id}") public Dept queryById(@PathVariable("id") Long id); @PostMapping("/dept/list") public List<Dept> queryAll(); @GetMapping("/dept/add") public boolean addDept(Dept dept); } -
启动类
//消费者 运行方式80可省略 例:localhost/consumer/dept/list @SpringBootApplication @EnableEurekaClient //在服务启动后,自动注册到Eureka注册中心中 @EnableFeignClients(basePackages = {"com.luffy.springcloud"}) //Feign被扫描到 public class DeptConsumer_feign { public static void main(String[] args) { SpringApplication.run(DeptConsumer_feign.class,args); } } -
ConfigBean
@Configuration public class ConfigBean { //配置负载均衡实现RestTemplate @Bean @LoadBalanced //ribbon负载均衡的作用 public RestTemplate getRestTemplate(){ return new RestTemplate(); } } -
controller
@RestController public class DeptConsumerController { //Feign面向接口编程 @Autowired private DeptClientService deptClientService =null; //添加数据 @RequestMapping("/consumer/dept/add") public boolean add(Dept dept){ return deptClientService.addDept(dept); } //通过id查询 @RequestMapping("/consumer/dept/get/{id}") public Dept get(@PathVariable("id") Long id){ return deptClientService.queryById(id); } //查询所有 @RequestMapping("/consumer/dept/list") public List<Dept> queryAll(){ return deptClientService.queryAll(); } }
六、Hystrix服务熔断
熔断制机,主要用于应对雪崩效应的一种保护机制。指的是为了保全整体牺牲局部。编程中的熔断主要是为了避免整个服务崩溃,所以行相应的处理,比如将服务降级。
6.1、服务雪崩
-
多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的“扇出”、如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应"。
-
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒中内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障,这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
6.2、Hystrix介绍
-
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等,Hystrix能够保证在一 个依赖出问题的情况下, 不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
-
“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝) , 向调用方返回-一个服务预期的,可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方法无法处理的异常,这样就可以保证了服务调用方的线程不会被长时间,不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩
-
服务降级
-
服务熔断
-
服务限流
-
接近实时的监控
-
·····
6.3、服务熔断
- 熔断机制是对应雪崩效应的一种微服务链路保护机制。
- 当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况, 当失败的调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand.
理解:熔断是存于服务器的,通常是服务器异常崩掉的情况下启用熔断,在被动的情况下显示启动异常或预备的方案代码
6.4、Hystrix服务熔断环境搭建
springcloud-provider-dept-hystrix-8001
是一个服务器
-
pom.xml(在正常8001上添加一个依赖)
<!--Hystrix--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.4.6.RELEASE</version> </dependency> -
controller
//提供Restful服务 @RestController public class DeptController{ @Autowired private DeptService deptService; @RequestMapping("/dept/get/{id}") @HystrixCommand(fallbackMethod = "hystrixGet") //如果失败 去调用Hystrix的备选方案 public Dept get(@PathVariable("id") Long id){ Dept dept = deptService.queryById(id); if (dept==null){//如果当前id值为空 抛出异常 throw new RuntimeException("id=> "+ id+"不存在该用户,或者该信息无法找到"); } return dept; } //如果出现异常 采取Hystrix的备选方案 public Dept hystrixGet(@PathVariable("id") Long id){ return new Dept() .setDeptno(id) .setDname("id=> "+id+"没有找到相关信息,null by Hystrix") .setDb_source("not found database in mysql"); } } -
启动类
@SpringBootApplication @EnableEurekaClient//在服务启动后,自动注册到Eureka注册中心中 @EnableDiscoveryClient //注册进来的微服务,获取一些信息。服务发现,扩展内容 @EnableCircuitBreaker //添加Hystrix服务熔断 断路器的支持 public class DeptProviderHystrix_8001 { public static void main(String[] args) { SpringApplication.run(DeptProviderHystrix_8001.class, args); } } -
其余文件通过8001项目copy正常修改
-
访问数据库没有的数据会服务异常,这时候就会启动服务熔断启用controller里的备选方案
6.5、服务降级
- 所谓降级,就是当某个服务出现异常之后,服务器将不再被调用,此时服务端可以自己准备一个本地的fallback回调,返回一个缺省值。
- 这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强
理解:降级是存于客户端的,在我们选择关闭服务器的时候,主动选择显示给客户端的数据
6.5、Hystrix 服务降级环境修改
修改代码
-
在api项目的service层添加DeptClientServiceFallbackFactory类
//Hystrix 降级,当服务端关闭后的提示信息 @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("id=>" +id+"没有对应的信息,客户端提供了降级的信息,这个服务现在已经关闭") .setDb_source("已降级 未查找到数据"); } @Override public List<Dept> queryAll() { return null; } @Override public boolean addDept(Dept dept) { return false; } }; } } -
DeptClientService接口(在FeignClient注解增加服务降级功能,在api项目)
@Component//注册到Spring容器 @FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class) public interface DeptClientService { @GetMapping("/dept/get/{id}") public Dept queryById(@PathVariable("id") Long id); @GetMapping("/dept/list") public List<Dept> queryAll(); @PostMapping("/dept/add") public boolean addDept(Dept dept); } -
application.yaml(在feign项目)
#开启降级Feign Hystrix feign: hystrix: enabled: true -
测试运行一切正常,关闭服务器之后会按照降级的方案执行
6.6、Dashboard流监控
新建Maven项目 springcloud-consumer-hystrix-dashboard(客户端)
-
pom.xml
<!--Hystrix服务熔断依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--dashboard流监控--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> <version>1.4.6.RELEASE</version> </dependency> -
application.yaml
#Hystrix的dashboard流监控 端口 server: port: 9001 -
启动类
@SpringBootApplication @EnableHystrixDashboard//开启监控 public class DeptConsumerDashboard_9001 { public static void main(String[] args) { SpringApplication.run(DeptConsumerDashboard_9001.class,args); } } -
进入localhost:9001/hystrix可以查看官方主页
springcloud-provider-dept-hystrix-8001项目(服务端)
-
启动类
@SpringBootApplication @EnableEurekaClient//在服务启动后,自动注册到Eureka注册中心中 @EnableDiscoveryClient //注册进来的微服务,获取一些信息。服务发现,扩展内容 @EnableCircuitBreaker //添加Hystrix服务熔断 断路器的支持 public class DeptProviderHystrix_8001 { public static void main(String[] args) { SpringApplication.run(DeptProviderHystrix_8001.class,args); } //端口号是被监控的项目端口,在页面输入这个网址即可监控 //增加一个servlet,配合dashboard监控使用,固定的代码 http://localhost:8001/actuator/hystrix.stream访问监控 @Bean public ServletRegistrationBean hystrixMetricsStreamServlet(){ ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet()); registrationBean.addUrlMappings("/actuator/hystrix.stream"); return registrationBean; } } -
根据监控的网址进入指定项目的监控页面,指定的项目只要进行了操作监控页面都会有响应
七、Zuul路由网关
7.1、Zuul介绍
Zuul包含了对请求的路由和过滤两个最主要的功能:
- 其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础,而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础。
- Zuul和Eureka进行整合, 将Zuu自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得。
注意:Zuul服务最终还是会注册进Eureka
提供:代理+路由+过滤 三大功能
7.2、Zuul项目搭建
创建maven项目 `springcloud/springcloud-zuul-9527
-
pom.xml
<!--Zuul路由网关--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> <version>1.4.6.RELEASE</version> </dependency> -
C:\Windows\System32\drivers\etc\hosts修改这个文件模拟地址
//在最后添加 127.0.0.1 www.luffy.com -
启动类
@SpringBootApplication @EnableZuulProxy//zuul路由注解 public class zuulApplication_9527 { public static void main(String[] args) { SpringApplication.run(zuulApplication_9527.class,args); } } -
application.yaml
zuul: routes: mydept.serviceId: springcloud-provider-dept #之前的查询链接地址 http://www.luffy.com:9527/springcloud-provider-dept/dept/get/1 #现在的查询链接地址,配置后为 http://www.luffy.com:9527/mydept/dept/get/1 #两者都皆可访问(原路径+现配路径)。配置自定义的前缀后 可不让客户端知道真实的ip地址 mydept.path: /mydept/** #加上此配置后 原路径不能访问(springcloud-provider-dept/dept/get/6),只能通过自定义的规则路径访问。 ignored-services: springcloud-provider-dept #星号(*) 隐藏全部的项目真实名字 ignored-services: "*" prefix: /li #设置公共的地址前缀 配置后链接为:www.luffy.com:9527/li/mydept/dept/get/11 -
再次启动zuul启动类,可看到是我们自定义的路由规则,可有效的隐藏真实服务名及地址。
-
访问:www.luffy.com:9527/li/mydept/dept/get/2
八、SpringCloud config分布式配置
8.1、SpringCloud config介绍
Spring Cloud Config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环节提供了一个中心化的外部配置。
Spring Cloud Config 分为服务端和客户端两部分
-
服务端也称为分布式配置中心,它是一 个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密,解密信息等访问接口。
-
客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。配置服务器默认采用git来存储配置信息,这样就有助于对环境配置进行版本管理。并且可以通过git客户端工具来方便的管理和访问配置内容。
作用
- 集中管理配置文件
- 不同环境,不同配置,动态化的配置更新,分环境部署,比如/dev /test/ /prod /beta /release
- 运行期间动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息。
- 当配置发生变动时,服务不需要重启,即可感知到配置的变化,井应用新的配置
- 将配置信息以REST接口的形式暴露
8.2、git配合基础操作
git初始基础命令
# 显示当前的Git配置
$ git config --list
# 设置提交代码时的用户信息
$ git config --global user.name "[name]"
$ git config --global user.email "[email address]"
git提交远程仓库命令
git add . 将文件添加到暂存区
git status 查看状态
git commit -m “一次提交” 本地提交,-m为提交时写的信息
git push origin master 提交到远程的当前路径分枝
将这段代码提交到码云(application.yaml)
spring:
profiles:
active: dev
---
spring:
profiles: dev
application:
name: springcloud-config-dev
---
spring:
profiles: test
application:
name: springcloud-config-test
8.3、服务端连接Git配置
新建maven项目springcloud-config-server-3344
-
pom.xml
<!--服务端连接Git--> <artifactId>springcloud-config-server-3344</artifactId> <dependencies> <!--springboot启动--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--springcloud-config的配置--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> <version>2.1.1.RELEASE</version> </dependency> </dependencies> -
application.yaml
server: port: 3344 spring: application: name: springcloud-config-server #连接远程的仓库 cloud: config: server: git: uri: https://gitee.com/xxx/springcloud-config.git #自己远程仓库的https地址 # 通过 config-server可以连接到git,访问其中的资源以及配置~ -
启动类
@SpringBootApplication @EnableConfigServer //开启配置服务 public class Config_Server_3344 { public static void main(String[] args) { SpringApplication.run(Config_Server_3344.class,args); } } -
输入localhost:3344/application-test.yaml可以访问之前的application.yaml里的test内容
-
输入localhost:3344/application-dev.yaml可以访问之前的application.yaml里的dev内容
8.4、客户端连接服务端访问远程配置
创建一个要读取的yaml放到远程
-
config-client.yaml
#启动环境选择的配置 spring: profiles: active: dev #springboot启动多环境的配置 --- server: port: 8201 #spring的配置 spring: profiles: dev application: name: springcloud-config-client-dev #Eureka的配置。 服务注册到Eureka中,需要一个路径地址 eureka: client: service-url: defaultZone: http://eureka7001.com:7001/eureka/ --- server: port: 8202 #spring的配置 spring: profiles: test application: name: springcloud-config-client-test #Eureka的配置。 服务注册到Eureka中,需要一个路径地址 eureka: client: service-url: defaultZone: http://eureka7001.com:7001/eureka/
新建Maven项目springcloud-config-client-3355
-
pom.xml
<dependencies> <!--springboot启动--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--springcloud-config启动的配置 和服务端的不同--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> <version>2.1.1.RELEASE</version> </dependency> </dependencies> -
application.yaml
#用户级别的配置 配置去读取谁 spring: application: name: springcloud-config-client-3355 -
bootstrap.yaml
# 系统级别的配置 spring: cloud: config: name: config-client # 需要从git上读取的资源名称,不要后缀 profile: dev #dev环境端口:8201 test环境端口:8202 label: master #需要在git上的哪个分支拿 #连接到3344服务,中转站的形式连接服务端访问远程地址 uri: http://localhost:3344 -
controller
//@Value为git上的client-config的值 @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; } } -
启动类
@SpringBootApplication public class Config_Client_3355 { public static void main(String[] args) { SpringApplication.run(Config_Client_3355.class,args); } } -
启动3344和3355,因3355中的bootstrap.yml配置的git仓库中的dev环境,dev环境的端口为8201,所以是通过8201访问项目
-
访问localhost:8201/config即可将远程仓库的数据读取显示
8.5、远程配置实战测试
-
远程仓库创建config-eureka.yaml
#启动环境选择的配置 spring: profiles: active: dev --- server: port: 7001 #spring的配置 spring: profiles: dev application: name: springcloud-config-eureka-dev #Eureka配置 eureka: instance: hostname: eureka7001.com #Eureaka服务端的实例名称 client: register-with-eureka: false #表示是否向Eureka注册中心注册自己 fetch-registry: false #如果fetch-registry为false,则表示自己为注册中心 service-url: #监控页面 #单机:点进去参考源码,可看到默认的url端口配置为8761,我们设置为自己的端口。 #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka #集群(除自身外 关联其他所有) defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ --- server: port: 7001 #spring的配置 spring: profiles: test application: name: springcloud-config-eureka-test #Eureka配置 eureka: instance: hostname: eureka7001.com #Eureaka服务端的实例名称 client: register-with-eureka: false #表示是否向Eureka注册中心注册自己 fetch-registry: false #如果fetch-registry为false,则表示自己为注册中心 service-url: #监控页面 #单机:点进去参考源码,可看到默认的url端口配置为8761,我们设置为自己的端口。 #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka #集群(除自身外 关联其他所有) defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ -
远程仓库创建config-dept.yaml
#启动环境选择的配置 spring: profiles: active: dev --- server: port: 8001 #mybatis配置 mybatis: type-aliases-package: com.luffy.springcloud.pojo config-location: classpath:mybatis/mybatis-config.xml mapper-locations: classpath:mybatis/mapper/*.xml #spring的配置 spring: profiles: dev application: name: springcloud-config-dept #数据源的配置 datasource: type: com.alibaba.druid.pool.DruidDataSource #数据源为druid driver-class-name: com.mysql.jdbc.Driver #数据库驱动 url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8&servetTimeZone=Asia/Shanghai username: root password: root #Eureka的配置。 服务注册到Eureka中,需要一个路径地址 eureka: client: service-url: defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/ instance: #修改Eureka中status的默认描述信息。不配置默认为DESKTOP-XXX描述 instance-id: springcloud-provider-dept8001 prefer-ip-address: true #改为true后 Eureka中的status就会显示真实ip地址 #info配置 Eureka的status的xx/info链接点开后的info监控信息。没有太大意义 info: app.name: ti zi zui bang,jiayou company.name: tizi.lemon.com test.name: hahah test --- server: port: 8001 #mybatis配置 mybatis: type-aliases-package: com.luffy.springcloud.pojo config-location: classpath:mybatis/mybatis-config.xml mapper-locations: classpath:mybatis/mapper/*.xml #spring的配置 spring: profiles: test application: name: springcloud-config-dept #数据源的配置 datasource: type: com.alibaba.druid.pool.DruidDataSource #数据源为druid driver-class-name: com.mysql.jdbc.Driver #数据库驱动 url: jdbc:mysql://localhost:3306/db02?useUnicode=true&characterEncoding=utf-8&servetTimeZone=Asia/Shanghai username: root password: root #Eureka的配置。 服务注册到Eureka中,需要一个路径地址 eureka: client: service-url: defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/ instance: #修改Eureka中status的默认描述信息。不配置默认为DESKTOP-XXX描述 instance-id: springcloud-provider-dept8001 prefer-ip-address: true #改为true后 Eureka中的status就会显示真实ip地址 #info配置 Eureka的status的xx/info链接点开后的info监控信息。没有太大意义 info: app.name: ti zi zui bang,jiayou company.name: tizi.lemon.com test.name: hahah test
创建Maven项目springcloud-config-eureka-7001 客户端
-
pom.xml
<dependencies> <!--eureka服务提供者包--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--springcloud-config启动的配置--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> <version>2.1.1.RELEASE</version> </dependency> </dependencies> -
复制 springcloud-eureka-7001 项目所有的内容,删掉application.yaml所有配置
-
application.yaml
spring: application: name: sorubgckiyd-config-eureka-7001 -
bootstrap.yaml
# 系统级别的配置 spring: cloud: config: name: config-eureka # 需要从git上读取的资源名称,不要后缀 profile: dev #dev环境端口:8201 test环境端口:8202 label: master #需要在git上的哪个分支拿 #连接到3344服务,中转站的形式连接服务端访问远程地址 uri: http://localhost:3344
创建Maven项目springcloud-config-dept-8001 服务端
-
pom.xml
<dependencies> <!--eureka服务提供者包--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--springcloud-config启动的配置--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> <version>2.1.1.RELEASE</version> </dependency> </dependencies> -
复制 springcloud-config-dept-8001 项目所有的内容,删掉application.yaml所有配置
-
application.yaml
spring: application: name: springcloud-config-dept-8001 -
bootstrap.yaml
#系统级的配置 # 系统级别的配置 spring: cloud: config: name: config-dept # 需要从git上读取的资源名称,不要后缀 profile: dev #dev环境端口:8201 test环境端口:8202 label: master #需要在git上的哪个分支拿 #连接到3344服务,中转站的形式连接服务端访问远程地址 uri: http://localhost:3344
运行
- 启动config这个7001和8001还有3344
- 3344会git连接远程仓库
- 这里项目获取的配置都是远程的配置
- 8001加入7001集群
- 这里是根据bootstrap.yaml里的name值读取远程仓库指定的文件
- 从而读取指定区域数据
注意:远程代码更新需要重新push,否则代码没更新会报错
1573

被折叠的 条评论
为什么被折叠?



