本文主要介绍 SpringCloud 的入门一、SpringCloud 的五大组件(需要牢牢记住他们 , 现在混个眼熟 , 下面会详细介绍 。)

文章插图
自学参考文档:
- SpringCloud 官方文档(汉化版):https://springcloud.cc/spring-cloud-dalston.html
- SpringCloud中国社区:http://springcloud.cn/
- SpringCloud中文网:https://springcloud.cc
- 一文详解微服务架构:https://www.cnblogs.com/skabyy/p/11396571.html
- 微服务架构是什么?:https://www.zhihu.com/question/65502802
- kuangstudy:https://www.kuangstudy.com/course/play/1321005531116863490

文章插图
微服务(Microservice Architecture) 是近几年流行的一种架构思想 , 关于它的概念很难一言以蔽之 。究竟什么是微服务呢?我们在此引用ThoughtWorks 公司的首席科学家 Martin Fowler 于2014年提出的一段话:
原文:https://martinfowler.com/articles/microservices.html
中文:https://www.cnblogs.com/liuning8023/p/4493156.html
就目前而言 , 对于微服务 , 业界没有一个统一的标准定义 。通常而言 , 微服务架构是一种架构模式 , 或者说是一种架构风格 , 它提倡将单一的应用程序划分为一组小的服务 , 每个服务运行在其独特的自己的进程内 , 服务之间互相协调 , 互相配置 , 为用户提供最终价值 。服务之间采用轻量级的通信机制互相沟通 , 每个服务都围绕着具体的业务进行构建 , 并且能够被独立的部署到生产环境中 。另外 , 应尽量避免统一的 , 集中式的服务管理机制 , 对具体的一个服务而言 , 应根据业务上下文 , 选择适合的语言 , 工具对其进行构建 , 可以有一个非常轻量级的集中管理来协调这些服务 , 可以用不同的语言来编写服务 , 也可以使用不同的数据库 。(牢牢记住上面这段概念 , 几乎每句话都有微服务的关键点)
三、传统开发模式 VS 微服务
- 传统的web开发方式

文章插图
优点:
集中式管理 , 开发简单 , 功能都在本地 , 没有分布式的管理和调用 。
缺点:
1.效率低 , 开发都在同一个项目改代码 , 互相等待 , 冲突不断;
2.稳定性差 , 一个微小的问题 , 可能导致整个程序挂掉;
3.维护性难 , 代码高耦合 , 内部关系难以摸清楚;
4.扩展性差 , 无法满足高并发下的业务需求;
- 随着业务的发展 , 移动端兴起

文章插图
这一阶段 , 架构设计存在着很多不合理的地方:
1.网站和移动端存在着很多相同业务逻辑的重复代码;
2.数据库被多个应用依赖 , 无法重构和优化;
3.数据有时候通过数据库共享 , 有时候通过接口调用传输 , 接口调用关系杂乱;
4.单个应用为了给其他应用提供接口 , 设计得越来越复杂 , 包含本不属于它得逻辑;
5.应用之间界限模糊 , 功能归属混乱 , 出现问题后各部门职责很难划分 , 出现分歧或争端;
6.所有的应用都在一个数据库上操作 , 数据库出现性能瓶颈;
7.管理后台保障级别比较低 , 添加新的功能可能影响到其他应用;
8.开发、部署、维护、升级愈发困难;
- 下一阶段 , 除去大量的冗余代码

文章插图
在这一阶段 , 服务已经被拆分开了 , 但是数据库依然是共用的 。会出现一些问题:
1.数据库性能瓶颈 , 而且存在一定的风险;
2.数据库表结构可能被多个服务依赖 , 维护困难;
- 提高系统的实时性 , 再次升级架构(微服务)

文章插图
此时 , 拆分后的各个服务可以采用异构的技术 。比如 , 数据分析服务可以使用数据仓库作为持久化层 , 以便于高效地做一些统计计算;促销服务访问比较频繁 , 因此可以加入缓存机制 。
微服务 , 它是具体解决某一个问题/提供落地对应服务的一个服务应用 , 狭义的看 , 可以看作是IDEA中的一个个微服务工程 , 或者Moudel 。IDEA 工具里面使用Maven开发的一个个独立的小Moudel , 它具体是使用SpringBoot开发的一个小模块 , 专业的事情交给专业的模块来做 , 一个模块就做着一件事情 。强调的是一个个的个体 , 每个个体完成一个具体的任务或者功能 。
微服务的优点:
1.单一职责原则;
2.每个服务足够内聚 , 足够小 , 代码容易理解;
3.开发效率高 , 一个服务可能就是专一的只干一件事;
4.微服务能够被小团队单独开发 , 这个团队只需2-5个开发人员组成;
5.松耦合 , 无论是在开发阶段或部署阶段都是独立的;
6.可以使用不同的语言开发;
7.易于和第三方集成 , 微服务允许容易且灵活的方式集成自动部署 , 通过持续集成工具 , 如jenkins , Hudson , bamboo;
8.每个微服务都有自己的存储能力 , 可以有自己的数据库 , 也可以有统一的数据库;
微服务的缺点:
1.开发人员要处理分布式系统的复杂性;
2.多服务运维难度 , 随着服务的增加 , 运维的压力也在增大;
3.各个服务间的通信成本问题;
4.整个应用分散成多个服务 , 定位故障相对困难;
5.一个服务故障可能产生雪崩效用 , 导致整个系统故障;
整体解决思路如下:

文章插图
四、SpringCloud入门官网:http://projects.spring.io/spring-cloud/

文章插图
SpringCloud没有采用数字编号的方式命名版本号 , 而是采用了伦敦地铁站的名称 , 同时根据字母表的顺序来对应版本时间顺序 , 比如最早的Realse版本:Angel , 第二个Realse版本:Brixton , 然后是Camden、Dalston、Edgware , 目前最新的是Hoxton SR4 CURRENT GA通用稳定版 。
- 微服务技术栈有那些?
- 各微服务框架对比
- Rest 搭建学习环境
<?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>com.zhou</groupId><artifactId>springcloud</artifactId><version>1.0-SNAPSHOT</version><modules><module>springcloud-consumer-dept-80</module><module>springcloud-provider-dept-8001</module><module>springcloud-api</module></modules><!--打包方式 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><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>0.2.0.RELEASE</version><type>pom</type><scope>import</scope></dependency><!--SpringCloud的依赖--><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Greenwich.SR1</version><type>pom</type><scope>runtime</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.2.5</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>${log4j.version}</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins><!--Maven 资源过滤问题--><resources><resource><directory>src/main/java</directory><includes><include>**/*.*</include></includes><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><includes><include>**/*.*</include></includes><filtering>false</filtering></resource></resources></build></project>注意:父工程为 springcloud , 其下有多个子 module2.创建子模块 springcloud-api , 它只负责接管 pojo
pom 依赖
<?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>com.zhou</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>springcloud-api</artifactId><dependencies><!--当前的module自己需要的依赖 , 如果父类中已经配置了版本 , 这里就不需要写了--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies></project>3.在SQLyog中创建数据库 db01
文章插图
idea连接此数据库并创建一些字段和数据

文章插图
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.创建实体类package com.zhou.springcloud.pojo;import lombok.Data;import lombok.NoArgsConstructor;import lombok.experimental.Accessors;import java.io.Serializable;@Data@NoArgsConstructor@Accessors(chain = true) //链式编程 , 默认 boolean chain() default false;public class Dept implements Serializable { //Dept 实体类private Long deptno;//主键private String dname;//这个数据存在那个数据库的字段 , 微服务 , 一个服务对应一个数据库 , 同一个信息可能存在不同的数据库private String db_source;public Dept(String dname) {this.dname = dname;}}5.创建子模块 springcloud-provider-dept-8001 (服务的提供者)子模块 springcloud-provider-dept-8001 的整体项目结构如下:

文章插图
pom 依赖
<?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>com.zhou</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>springcloud-provider-dept-8001</artifactId><dependencies><!--我们需要拿到实体类 , 所以要配置 api module--><dependency><groupId>com.zhou</groupId><artifactId>springcloud-api</artifactId><version>1.0-SNAPSHOT</version></dependency><!--junit--><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></project>application.yamlserver:port: 8001#mybatis 配置mybatis:type-aliases-package: com.zhou.springcloud.pojoconfig-location: classpath:mybatis/mybatis-config.xmlmapper-locations: classpath:mybatis/mapper/*.xml#speing 配置spring:application:name: springcloud-provider-deptdatasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8username: rootpassword: rootmybatis-config.xml<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><settings><!--开启二级缓存--><setting name="cacheEnabled" value="https://tazarkount.com/read/true"/></settings></configuration>DeptMapper 接口package com.zhou.springcloud.mapper;import com.zhou.springcloud.pojo.Dept;import org.apache.ibatis.annotations.Mapper;import org.apache.ibatis.annotations.Param;import org.springframework.stereotype.Repository;import java.util.List;@Mapper@Repositorypublic interface DeptMapper {boolean addDept(Dept dept);Dept queryById(@Param("id") Long id);List<Dept> queryAll();}DeptMapper.xml<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.zhou.springcloud.mapper.DeptMapper"><insert id="addDept" parameterType="Dept">insert into dept (dname, db_source)values (#{dname},DATABASE());</insert><select id="queryById" parameterType="Long" resultType="Dept">select * from dept where deptno=#{id};</select><select id="queryAll" resultType="Dept">select * from dept</select></mapper>DeptService 接口package com.zhou.springcloud.service;import com.zhou.springcloud.pojo.Dept;import java.util.List;public interface DeptService {boolean addDept(Dept dept);Dept queryById(Long id);List<Dept> queryAll();}DeptServiceImpl.javapackage com.zhou.springcloud.service;import com.zhou.springcloud.mapper.DeptMapper;import com.zhou.springcloud.pojo.Dept;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.util.List;@Servicepublic class DeptServiceImpl implements DeptService{@Autowiredprivate DeptMapper deptMapper;@Overridepublic boolean addDept(Dept dept) {return deptMapper.addDept(dept);}@Overridepublic Dept queryById(Long id) {return deptMapper.queryById(id);}@Overridepublic List<Dept> queryAll() {return deptMapper.queryAll();}}DeptController.javapackage com.zhou.springcloud.controller;import com.zhou.springcloud.pojo.Dept;import com.zhou.springcloud.service.DeptService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RestController;import java.util.List;//提供Restful服务@RestControllerpublic class DeptController {@Autowiredprivate DeptService deptService;@GetMapping("/dept/add")//方便此时的测试 , 这里用了Get , 没有用Postpublic boolean addDept(Dept dept) {return deptService.addDept(dept);}@GetMapping("/dept/get/{id}")public Dept getDept(@PathVariable("id") Long id){return deptService.queryById(id);}@GetMapping("/dept/list")public List<Dept> queryAll(){return deptService.queryAll();}}6.启动类package com.zhou.springcloud;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;//启动类@SpringBootApplicationpublic class DeptProvider_8001 {public static void main(String[] args) {SpringApplication.run(DeptProvider_8001.class,args);}}7.Run 测试访问:http://localhost:8001/dept/list (测试成功!)
访问:http://localhost:8001/dept/get/1 (测试成功!)
访问:http://localhost:8001/dept/add?dname=地狱部 (测试成功!)
查询数据库

文章插图
1.创建子模块 springcloud-consumer-dept-80 (服务的消费者)
pom 依赖
<?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>com.zhou</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>springcloud-consumer-dept-80</artifactId><dependencies><!--不需要连接数据库 , 需要实体类+web--><dependency><groupId>com.zhou</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></project>application.ymlserver:port: 80ConfigBean.javapackage com.zhou.springcloud.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.client.RestTemplate;@Configuration //@Configuration 相当于 spring中 applicationContext.xmlpublic class ConfigBean {@Beanpublic RestTemplate getRestTemplate(){return new RestTemplate();}}RestTemplate 部分源码:
文章插图
DeptConsumerController.java
package com.zhou.springcloud.controller;import com.zhou.springcloud.pojo.Dept;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.client.RestTemplate;import java.util.List;@Controllerpublic class DeptConsumerController {//理解:消费者 , 不应该有 service 层//RestTemplate.... 供我们直接调用就可以了 , 注册到Spring中@Autowiredprivate RestTemplate restTemplate;//http://localhost:8081/dept/add?dname=地狱部private static final String REST_URL_PREFIX="http://localhost:8081";@RequestMapping("/consumer/dept/add")@ResponseBodypublic boolean add(Dept dept){return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept,Boolean.class);}@RequestMapping("/consumer/dept/get/{id}")@ResponseBodypublic Dept get(@PathVariable("id") Long id){return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);}@RequestMapping("/consumer/dept/list")@ResponseBodypublic List<Dept> list(){return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);}}DeptConsumer_80.java 启动类package com.zhou.springcloud;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class DeptConsumer_80 {public static void main(String[] args) {SpringApplication.run(DeptConsumer_80.class,args);}}2.修改:springcloud-provider-dept-8001 它的 DeptController.java类的addDept()方法(否则 , 在下面测试中 , 使用浏览器url传参的方式来插入数据时 , 数据库中显示dname的值为null)

文章插图
@PostMapping("dept/add")public boolean addDept(@RequestBody Dept dept){return deptService.addDept(dept);}3.启动首先 , 启动服务的提供者 springcloud-provider-dept-8001 的启动类 DeptProvider_8001
其次 , 启动服务的消费者 springcloud-consumer-dept-80 的启动类 DeptConsumer_80

文章插图
4.Run 测试
访问:http://localhost/consumer/dept/list

文章插图
访问:http://localhost/consumer/dept/get/5

文章插图
访问:http://localhost/consumer/dept/add?dname=架构师3

文章插图
查看数据库

文章插图
五、Eureka 服务注册中心
- Eureka 定义

文章插图
在云中 , 应用程序不能总是知道其他服务的确切位置 。一个服务注册中心 , 比如Netflix Eureka , 或者一个sidecar解决方案 , 比如HashiCorp Consul , 都会有所帮助 。springcloud为流行的注册中心提供DiscoveryClient实现 , 比如Eureka、Consul、Zookeeper , 甚至Kubernetes的内置系统 。还有一个springcloud负载均衡器可以帮助您在服务实例之间小心地分配负载 。
官方介绍:https://spring.io/projects/spring-cloud-netflix

文章插图
springcloudnetflix通过自动配置并绑定到Spring环境和其他Spring编程模型习惯用法 , 为Spring启动应用程序提供Netflix操作系统集成 。通过一些简单的注释 , 您可以快速启用和配置应用程序中的常见模式 , 并使用经过测试的Netflix组件构建大型分布式系统 。提供的模式包括服务发现(Eureka)、断路器(Hystrix)、智能路由(Zuul)和客户端负载平衡(Ribbon)
- Dubbo 和 SpringCloud对比
二者解决的问题域不一样:Dubbo的定位是一款RPC框架 , 而SpringCloud的目标是微服务架构下的一站式解决方案 。
DubboSpringCloud服务注册中心ZookeeperSpring Cloud Netfilx Eureka服务调用方式RPCREST API服务监控Dubbo-monitorSpring Boot Admin断路器不完善Spring Cloud Netfilx Hystrix服务网关无Spring Cloud Netfilx Zuul分布式配置无Spring Cloud Config服务跟踪无Spring Cloud Sleuth消息总栈无Spring Cloud Bus数据流无Spring Cloud Stream批量任务无Spring Cloud Task严格来说 , 这两种方式各有优劣 。虽然从一定程度来说 , SpringCloud牺牲了服务调用的性能 , 但也避免了上面提到的原生RPC带来的问题 。而且REST相比RPC更为灵活 , 服务提供方和调用方的依赖只依靠一纸契约 , 不存在代码级别的强依赖 , 这个优点在当下强调快速演化的微服务环境下 , 显得更加合适 。
- Eureka基本的架构
2.Eureka采用了C-S的架构设计 , EurekaServer作为服务注册功能的服务器 , 他是服务注册中心.
3.系统中的其他微服务 , 使用Eureka的客户端连接到EurekaServer并维持心跳连接 。(方便监控系统中各个微服务是否正常运行)

文章插图
- 与Dubbo架构对比

文章插图
- 构建 Eureka 代码示例
pom 依赖
<artifactId>springcloud-eureka-7001</artifactId> <!--导入依赖--><dependencies> <!--spring-cloud-starter-netflix-eureka-server 依赖--> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-server --> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId><version>2.2.7.RELEASE</version> </dependency> <!--热部署--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId> </dependency></dependencies>application.yamlserver:port: 7001# Eureka 部署eureka:instance:# Eureka服务端的实例名字hostname: localhostclient:# 表示是否向 Eureka 注册中心注册自己(这个模块本事是服务器 , 所以不需要)register-with-eureka: false# fetch-registry 如果为 false , 则表示自己为注册中心 , 客户端的为 truefetch-registry: false# Eureka 监控页面service-url:#public static final String DEFAULT_URL = "http://localhost:8761/eureka/";defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/启动类 EurekaServer_7001.javapackage com.zhou.springcloud;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;/** * @Auther: zhouzhou * @Description: 启动之后 , 访问 http://127.0.0.1:7001/ */@SpringBootApplication@EnableEurekaServer //服务端的启动类 , 可以接受别人注册进来public class EurekaServer_7001 {public static void main(String[] args) {SpringApplication.run(EurekaServer_7001.class,args);}}Run 测试报错信息:Caused by: java.lang.ClassNotFoundException: org.springframework.boot.context.properties.ConfigurationPropertiesBean

文章插图
观察报错信息 , 得出有可能是版本冲突问题 , 解决办法是将 spring-cloud-starter-netflix-eureka-server 依赖的版本降为
2.1.4.RELEASE【注意】:报错原因是版本问题 , 可以选择到官网查看版本是否一致 , 比如 SPRINGCLOUD的版本 , 我的父依赖用的是
GREENWICH.SR1你如果用了
HOXTON.SR10 甚至更新的 , 请自行查找对应的版本依赖 。继续测试 , Run 成功!

文章插图
访问:http://localhost:7001/

文章插图
- Eureka 服务注册 信息配置以及自我保护机制
1.在上面创建的子模块 springlouc-provider-dept-8001 的 pom 中添加依赖
<!--Eureka:spring-cloud-starter-netflix-eureka-client 依赖--><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client --><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.1.4.RELEASE</version></dependency>2.application.yaml 中添加设置# Eureka配置:配置注册中心地址eureka:client:service-url:defaultZone: http://localhost:7001/eureka/3.启动类中使用 @EnableEurekaClient注解package com.zhou.springcloud;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.eureka.EnableEurekaClient;//启动类@SpringBootApplication@EnableEurekaClientpublic class DeptProvider_8001 {public static void main(String[] args) {SpringApplication.run(DeptProvider_8001.class,args);}}4.先启动7001服务端 , 再启动8001客户端进行测试 , 访问监控页:http://localhost:7001/ 产看结果如图 , 成功
文章插图
5.修改 Eureka 上的默认描述信息
# Eureka配置:配置注册中心地址eureka:client:service-url:defaultZone: http://localhost:7001/eureka/instance:instance-id: springcloud-provider-dept8001 # 修改eureka上的默认描述信息prefer-ip-address: true查看:
文章插图
6.配置关于服务加载的监控信息(springcloud-provider-dept-8001)
没配置之前 , 访问:springcloud-provider-dept8001

文章插图
跳出的页面如下:

文章插图
配置服务加载的监控信息步骤如下:
pom.xml中添加依赖
<!--actuator完善监控信息--><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId></dependency>application.yaml 中添加配置# info配置info:# 项目名称app.name: zhouzhou-springcloud# 公司名称company.name: blog.zhouzhou.com7.Run 再刷新页面 , 继续访问:springcloud-provider-dept8001 , 跳出页面如下
文章插图
- EureKa自我保护机制
固定时间内大量实例被注销 , 可能会严重威胁某个微服务架构的可用性 , 为了解决这个问题 , Eureka开发了自我保护机制 。
Eureka Server在运行期间会去统计心跳失败比例在15分钟之内是否低于85% , 如果低于85% , Eureka Server即进入自我保护机制 。
Eureka Server触发自我保护机制后 , 页面会出现提示:

文章插图
Eureka Server进入自我保护机制 , 会出现以下几种情况:
(1)Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务;
(2)Eureka仍然能够接受新服务的注册和查询 , 但是不会被同步到其它节点上(即保证当前节点依然可用);
(3)当网络稳定后 , 当前实例新的注册信息会被同步到其它节点上;
Eureka自我保护机制是为了防止误杀服务而提供的一种机制 。当个别客户端出现心跳失联时 , 则认为是客户端的问题 , 剔除客户端;当Eureka 捕获到大量的心跳失败时 , 则认为可能是网络问题 , 进入自我保护机制;当客户端心跳恢复时 , Eureka会自动退出自我保护机制 。
如果在保护期内刚好这个服务提供者非正常下线了 , 此时服务消费者就会拿到一无效的服务实例 , 则会调用失败 。对于这个问题需要服务消费者要有一些容错机制 , 比如重试 , 断路器等 。
- 注册进来的微服务 , 获取其中的一些信息(团队开发)

文章插图
2.观察 DiscoveryClient 源码:

文章插图
3.在 springcloud-provider-dept-8001 的 DeptController.java中添加 discovery() 方法
//DiscoveryClient 可以用来获取一些配置的信息 , 得到具体的微服务@Autowiredprivate DiscoveryClient discoveryClient;/*** 获取一些注册进来的微服务的信息* @return*/@GetMapping("dept/discovery")public Object discovery(){//获取微服务列表清单System.out.println("getServices()=>"+discoveryClient.getServices());System.out.println("description()=>"+discoveryClient.description());List<ServiceInstance> instances = discoveryClient.getInstances("SPRINGCLOUD-PROVIDER-DEPT");for (ServiceInstance instance : instances) {System.out.println(instance.getHost()+"\t"+ //主机名称instance.getPort()+"\t"+ //端口号instance.getUri()+"\t"+ //uriinstance.getInstanceId() //服务id);}returnthis.discoveryClient;}4.上面 discoveryClient.getInstances()的参数 ---> SPRINGCLOUD-PROVIDER-DEPT
文章插图
5.主启动类中加入 @EnableDiscoveryClient 注解
package com.zhou.springcloud;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;import org.springframework.cloud.netflix.eureka.EnableEurekaClient;//启动类@SpringBootApplication//@EnableEurekaClient 开启Eureka客户端注解 , 在服务启动后自动向注册中心注册服务@EnableEurekaClient//@EnableDiscoveryClient 开启服务发现客户端的注解 , 可以用来获取一些配置的信息 , 得到具体的微服务@EnableDiscoveryClientpublic class DeptProvider_8001 {public static void main(String[] args) {SpringApplication.run(DeptProvider_8001.class,args);}}6.Run 测试先启动 springcloud-eureka-7001 中的住启动类 EurekaServer_7001 ,
再启动 springcloud-provider-dept-8001 中的主启动类 DeptProvider_8001 ,
访问:http://localhost:7001/ 一切正常

文章插图
继续访问:http://localhost:8001/dept/discovery

文章插图
springcloud-provider-dept-8001 控制台输出:

文章插图
- Eureka:集群环境配置

文章插图
1.新建 子模块springcloud-eureka-7002 和 springcloud-eureka-7003
2.添加 pom 依赖 (与springcloud-eureka-7001相同)
3.application.yml配置 (与springcloud-eureka-7001相同)
(端口号用各自的 7001、7002和7003)
4.主启动类 (与springcloud-eureka-7001相同)
5.集群成员相互关联
配置一些自定义本机名字 , 在
C:\Windows\System32\drivers\etc找到本机hosts文件 , 在hosts文件最后加上 , 要访问的本机名称(默认是localhost)
文章插图
127.0.0.1eureka7001.com127.0.0.1eureka7002.com127.0.0.1eureka7003.com【注意】:修改hosts文件后一定要保存 , 如果遇到 修改hosts文件无权限的问题 , 参考下图配置:
文章插图
6.修改 各自的 application.yml 的配置
(1)设置各自的 服务端的实例名字(hostname)
(2)设置各自的 集群(关联)
springcloud-eureka-7001 的 application.yaml
server:port: 7001# Eureka 部署eureka:instance:# Eureka服务端的实例名字hostname: eureka7001.comclient:# 表示是否向 Eureka 注册中心注册自己(这个模块本事是服务器 , 所以不需要)register-with-eureka: false# fetch-registry 如果为 false , 则表示自己为注册中心 , 客户端的为 truefetch-registry: false# Eureka 监控页面service-url:# public static final String DEFAULT_URL = "http://localhost:8761/eureka/";# 单机:defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/# 集群(关联):7001关联 7002、7003defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/springcloud-eureka-7002 的 application.yamlserver:port: 7002eureka:instance:# Eureka服务端的实例名字hostname: eureka7002.comclient:register-with-eureka: falsefetch-registry: falseservice-url:# 集群(关联):7002关联 7001、7003defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/springcloud-eureka-7003 的 application.yamlserver:port: 7003eureka:instance:# Eureka服务端的实例名字hostname: eureka7003.comclient:register-with-eureka: falsefetch-registry: falseservice-url:# 集群(关联):7003关联 7001、7002defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/7.通过 springcloud-provider-dept-8001 的yaml配置文件 , 修改 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: springcloud-provider-dept8001 # 修改eureka上的默认描述信息prefer-ip-address: true8.模拟集群搭建完毕 。(可以把一个项目挂载到三个服务器上了)测试 , 访问:http://localhost:7001/

文章插图
测试 , 访问:http://localhost:7002/

文章插图
测试 , 访问:http://localhost:7003/

文章插图
- Eureka与Zookeeper 的对比
- RDBMS (MySQL\Oracle\sqlServer) ===> ACID
- NoSQL (Redis\MongoDB) ===> CAP
- A (Atomicity) 原子性
- C (Consistency) 一致性
- I (Isolation) 隔离性
- D (Durability) 持久性
- C (Consistency) 一致性
- A (Availability) 可用性
- P (Partition tolerance) 分区容错性
4.CAP理论的核心
一个分布式系统不可能同时很好的满足一致性 , 可用性和分区容错性这三个需求
根据CAP原理 , 将NoSQL数据库分成了满足CA原则 , 满足CP原则和满足AP原则三大类
- CA:单点集群 , 满足一致性 , 可用性的系统 , 通常可扩展性较差
- CP:满足一致性 , 分区容错的系统 , 通常性能不是特别高
- AP:满足可用性 , 分区容错的系统 , 通常可能对一致性要求低一些
著名的CAP理论指出 , 一个分布式系统不可能同时满足C (一致性) 、A (可用性) 、P (容错性) , 由于分区容错性P再分布式系统中是必须要保证的 , 因此我们只能再A和C之间进行权衡 。
Zookeeper 保证的是 CP —> 满足一致性 , 分区容错的系统 , 通常性能不是特别高
Eureka 保证的是 AP —> 满足可用性 , 分区容错的系统 , 通常可能对一致性要求低一些
- Zookeeper保证的是CP
- Eureka保证的是AP
(1)Eureka不在从注册列表中移除因为长时间没收到心跳而应该过期的服务
(2)Eureka仍然能够接受新服务的注册和查询请求 , 但是不会被同步到其他节点上 (即保证当前节点依然可用)
(3)当网络稳定时 , 当前实例新的注册信息会被同步到其他节点中
因此 , Eureka可以很好的应对因网络故障导致部分节点失去联系的情况 , 而不会像zookeeper那样使整个注册服务瘫痪 。
六、Ribbon:负载均衡(基于客户端)Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具 。
Ribbon 是 Netflix 发布的开源项目 , 主要功能是提供客户端的软件负载均衡算法 , 将 Netflix 的中间层服务连接在一起 。Ribbon 的客户端组件提供一系列完整的配置项 , 如:连接超时、重试等 。
- LB , 即负载均衡 (LoadBalancer) , 在微服务或分布式集群中经常用的一种应用 。
- 负载均衡简单的说就是将用户的请求平摊的分配到多个服务上 , 从而达到系统的HA (高用) 。
- 常见的负载均衡软件有 Nginx、Lvs 等等 。
- Dubbo、SpringCloud 中均给我们提供了负载均衡 , SpringCloud 的负载均衡算法可以自定义 。
(1)集中式LB
即在服务的提供方和消费方之间使用独立的LB设施 , 如Nginx(反向代理服务器) , 由该设施负责把访问请求通过某种策略转发至服务的提供方!
(2) 进程式 LB
将LB逻辑集成到消费方 , 消费方从服务注册中心获知有哪些地址可用 , 然后自己再从这些地址中选出一个合适的服务器 。
Ribbon 就属于进程内LB , 它只是一个类库 , 集成于消费方进程 , 消费方通过它来获取到服务提供方的地址 。
- 集成 Ribbon
<!--Ribbon--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-ribbon</artifactId><version>1.4.6.RELEASE</version></dependency><!--Eureka: Ribbon需要从Eureka服务中心获取要拿什么--><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:register-with-eureka: false # 不向 Eureka 注册自己service-url: # 从三个注册中心随机取一个去访问defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/主启动类加上@EnableEurekaClient注解 , 开启 Eurekapackage com.zhou.springcloud;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.eureka.EnableEurekaClient;//Ribbon 和 Eureka 整合以后 , 客户端可以直接调用 , 不用关心IP地址和端口号@SpringBootApplication@EnableEurekaClient //开启 Eureka 客户端public class DeptConsumer_80 {public static void main(String[] args) {SpringApplication.run(DeptConsumer_80.class,args);}}自定义Spring配置类:ConfigBean.java 配置负载均衡实现RestTemplatepackage com.zhou.springcloud.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.client.RestTemplate;@Configuration //@Configuration 相当于 spring中 applicationContext.xmlpublic class ConfigBean {//配置负载均衡实现RestTemplate@Beanpublic RestTemplate getRestTemplate(){return new RestTemplate();}}修改conroller:DeptConsumerController.java//http://localhost:8081/dept/add?dname=地狱部//private static final String REST_URL_PREFIX="http://localhost:8081";private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";- 使用Ribbon实现负载均衡

文章插图
1.参照springcloud-provider-dept-8001 , 新建两个服务提供者 Moudle:springcloud-provider-dept-8002、springcloud-provider-dept-8003 依次为另外两个Moudle添加pom.xml依赖 、resourece下的mybatis和application.yml配置 , Java代码
2.启动所有服务测试 , 访问 http://eureka7001.com:7002/
七、Feign:负载均衡(基于服务端)Feign是声明式Web Service客户端 , 它让微服务之间的调用变得更简单 , 类似controller调用service 。SpringCloud集成了Ribbon和Eureka , 可以使用Feigin提供负载均衡的http客户端 。
Feign 主要是社区版 , 大家都习惯面向接口编程 。这个是很多开发人员的规范 。调用微服务访问两种方法
- 微服务名字 【ribbon】
- 接口和注解 【feign】
所以 , Feign 在此基础上做了进一步的封装 , 由他来帮助我们定义和实现依赖服务接口的定义 , 在 Feign 的实现下 , 我们只需要创建一个接口并使用注解的方式来配置它 (类似以前Dao接口上标注 Mapper 注解 , 现在是一个微服务接口上面标注一个 Feign 注解) , 即可完成对服务提供方的接口绑定 , 简化了使用 Spring Cloud Ribbon 时 , 自动封装服务调用客户端的开发量 。
Feign默认集成了Ribbon【springcloud SpringCloud学习笔记】利用Ribbon维护了MicroServiceCloud-Dept的服务列表信息 , 并且通过轮询实现了客户端的负载均衡 , 而与Ribbon不同的是 , 通过Feign只需要定义服务绑定接口且以声明式的方法 , 优雅而简单的实现了服务调用 。
- 创建springcloud-consumer-fdept-feign模块
- 春季老年人吃什么养肝?土豆、米饭换着吃
- 三八妇女节节日祝福分享 三八妇女节节日语录
- 老人谨慎!选好你的“第三只脚”
- 校方进行了深刻的反思 青岛一大学生坠亡校方整改校规
- 脸皮厚的人长寿!有这特征的老人最长寿
- 长寿秘诀:记住这10大妙招 100%增寿
- 春季老年人心血管病高发 3条保命要诀
- 眼睛花不花要看四十八 老年人怎样延缓老花眼
- 香槟然能防治老年痴呆症? 一天三杯它人到90不痴呆
- 老人手抖的原因 为什么老人手会抖
