- Spring 最初最核心的两大核心功能 Spring Ioc 和 Spring Aop 成就了 Spring,Spring 在这两大核心的功能上不断的发展,才有了 Spring 事务、Spring Mvc 等一系列伟大的产品,最终成就了 Spring 帝国,到了后期 Spring 几乎可以解决企业开发中的所有问题。
- Spring Boot 是在强大的 Spring 帝国生态基础上面发展而来,发明 Spring Boot 不是为了取代 Spring ,是为了让人们更容易的使用 Spring 。就比如自动化配置,一键启动
Spring Cloud 是一系列框架的有序集合。它利用 Spring Boot 的开发便利性巧妙地简化了分布式系统基础设施的开发,都可以用 Spring Boot 的开发风格做到一键启动和部署。比如 以Spring boot项目做注册中心 - Spring Cloud 是为了解决微服务架构中服务治理而提供的一系列功能的开发框架,并且 Spring Cloud 是完全基于 Spring Boot 而开发,Spring Cloud 利用 Spring Boot 特性整合了开源行业中优秀的组件,整体对外提供了一套在微服务架构中服务治理的解决方案。
用一组不太合理的包含关系来表达它们之间的关系。
Spring ioc/aop > Spring > Spring Boot > Spring Cloud
springcloud
说道springboot+springcloud框架,我想首先说一下我使用springboot的感受,搭建项目快,配置简单只需要一个properties或者Yml完成配置,它跟我们之前使用xml的那种框架搭建方式会简化很多。另外它通过maven进行配置一些开箱即用的资源比如Mybatis,redis,mysql,web,start。同时它还内嵌了tomcat,通过一个mian和@SpringBootApplaction注解进行启动,部署的话只需要将项目打成jar,使用java -jar 包名就能启动了。
基于这些优点,我们拿它来做微服务框架的接口开发特别适合,首先将我们的项目按照功能模块的划分拆分成一个个的微服务,比如我在做电商项目是,将商品管理服务,订单服务,库存服务,用户服务,资源统一管理服务,购物车服务等块拆分成一个个的子模块,使用springboot框架快速搭建起来。那么就会出现一个问题,这么多的服务到底如何进行统一管理,相互之间如何调用的问题就凸显出来了?
其实springboot框架在设计之初就考虑到这些问题,那就是springcloud,它是基于springboot的微服务框架的实现,它提供了丰富的组件化开发。
下面我就给你介绍一下我常用到的组件。首先是eurake注册中心,主要是来注册保存我们的服务的地址列表,为消费者提供订阅服务的功能,它在搭建时需要引用eureka-server,然后在配置文件配上server端口号,然后配置register-with-eureka不注册自己,fetch-registry=false不去检索服务,然后在启动类上加上@EnableEurekaServer注解开启服务,这样注册中心就搭建完成了。注册中心主要功能是服务的注册与发现,生产者和消费者都需要将服务注册到注册中心上,注册中心会保存这些地址。并且服务会主动向注册中心发送续约请求,在一段时间不续约后就认为该服务已经挂掉了,就需要从注册中的地址列表中剔除。这个检查剔除服务的时间间隔可以在注册中心上配置。
如果我们要实现微服务之间调用的我们就要用到ribbon。它的负载均衡是软负载,也就是客户端服务器从Eureka Server拉取已注册的服务信息,然后根据负载均衡策略,直接发送请求,这整个过程都是在客户端完成的,并不需要注册中心的参与,SpringCloud中客户端负载均衡, 都是Ribbon组件,它是基于Netflix Ribbon实现的,通过SpringCloud的封装,可以轻松地面向服务的Rest服务请求,自动转换成客户端,负载均衡服务调用,RestTemplate,Feign,以及后面我们的网关服务gateway都使用到了Ribbon,SpringCloud在结合了Ribbon的负载均衡的实现中,封装增加了HTTP Client,和OKHttp两种实现。
默认使用Ribbon对Eureka服务发现的负载均衡,我这里介绍一下RestTempalte的实现方式,其中通过添加@LoadBalanced注解,@LoadBalanced,其实用到的就是Ribbon的组件,添加@LoadBalanced注解后,Ribbon会通过@LoadBalanced自动帮助你基于某种规则,比如简单的轮询,随机连接,去连接目标服务,从而很容易的实现负载均衡的算法,Ribbon实现负载均衡,核心有三点,
第一是服务发现,也就是发现服务的列表,就是依据服务的名字,把该服务下所有的实例,都找出来,
第二点是服务选择规则,依据规则策略,如何从一个服务中选择一个有效的,
最后一点是服务监听,也就是检测失效的服务,做到高效剔除。
ribbon的主要组件有ServerList,IRule,ServerListFilter等,他的整个流程是这样子的,首先,通过ServerList,获取所有的可用服务列表,然后通过ServerListFilter,过滤掉一部分地址,最后剩下的地址中,通过IRule选择一个实例,作为最终目标结果
ribbon还有自己的重试机制,比如我们通过一个服务有两台:A,B,从注册中心获取全部可调用的服务地址列表,筛选出本次需要调用的服务地址列表,然后通过负载均衡算法默认是轮询,找出一个地址进行访问,如果被访问的服务一旦服务挂掉,就会立即返回服务调用失败,这种情况下就需要重试机制。
在服务调之间的调用时我们还会用到feign,使用流程是在pom.xml文件中引入openfeign。因为fegin调用是基于接口的服务调用,同时它集成了ribbon,还能完成负载均衡和重试,因此我们在使用是要将我们发布的restful风格接口抽象化成一个方法,然后在该接口类上加上@FeignClient,并配置服务名,同时在启动类上加上@EnableFeignClients让feign注解生效,在调用接口是需要注意的是get请求传参时必须要加上@RequestParam注解,如果post请求传递的参数是一个实体对象还要加上@RequestBody,使用feign我觉他的好处就是像调用方法一样调用接口用起来比较简单。
我们的项目是前后端分离项目,前端项目需要调用微服务的接口,这个时候我们就需要springcloud的另一个组件gateway路由网关。他有三方面的功能Route(路由),Predicate(断言),Filter(过滤器)。
首先时router路由,路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由。具体使用就是通过ribbon进行路由和负载均很。
Predicate(断言):指的是Java 8 的 Function Predicate。输入类型是Spring框架中的ServerWebExchange。这使开发人员可以匹配HTTP请求中的所有内容,例如请求头或请求参数。如果请求与断言相匹配,则进行路由;
Filter(过滤器):指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前后对请求进行修改。
我们项目主要用的filter比较多一些,过滤器的生命周期只有两个:“pre” 和 “post”。
PRE : 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
POST :这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
我们配置是分为两种进行配置分别是全局过滤器和局部过滤器。
全局过滤器【GlobalFilter】作用在全部路由上的,可以自定义实现主要是用来进行统一的权限校验,安全性认证等功能,我实现过进行jwt的token值校验。具体实现是实现接口GlobalFilter,重写里边的filter方法,里边分别有两个参数分别是【ServerWebExchange】这个是前后台交互的对象可以获得request和respose,前台浏览器发过来的请求信息都在这个对象中,还有一个参数是【GatewayFilterChain】这个是filter的责任链,是执行下个过滤器的对象。具体就是在【chain.filter】执行之前完成过滤校验如果不通过就返回自定义的response,通过就执行下一个过滤器。如果有多个过滤器我们使用@Order注解声明过滤器的执行顺序,数字越小越先执行。
我们还可以定义局部过滤器作用在单个路由上,一般用来对一些重要的服务做限流和安全校验。gateway给提供了一些定义好的过滤器可以直接配置使用比如AddRequestHeader过滤不需要添加一些头信息,Hystrix熔断,StripPrefix原始请求路径截取,RequestRateLimit服务或者接口的限流。我这里说一下限流的配置,我这里是按照ip地址进行限流。因为限流要用到redis我们的额项目还要整合redis。首先要先定义一个bean在这边通过exchange.getRequest().getRemoteAddress().getHostName(),获取访问的Ip地址,然后在配置文件配置name: RequestRateLimiter 过滤器名称
redis-rate-limiter.replenishRate: 1 #每秒允许处理的请求数量
redis-rate-limiter.burstCapacity: 2 #每秒最大处理的请求数量
key-resolver: “#{@ipKeyResolver}” #限流策略,对应策略的Bean,这样我们就可以对具体的路由进行限流了。
当然我们也可以自定义局部拦截器工厂,每个过滤器工厂都对应一个实现类,并且这些类的名称必须以 GatewayFilterFactory 结尾,这是Spring Cloud Gateway的一个约定。具体流程是编写一个过滤器类实现GatewayFilter接口,加上@Component 和@Order(10),重写里边的filter方法,定义自己的过滤规则。然后编写一个过滤器工厂需要去继承AbstractGatewayFilterFactory类,重写apply方法将自定拦截器类给注入进来,这个时候我们就可以在配置文件中的具体路由中,通-拦截器名称来使用这个拦截器类。
微服务框架搭建好了在使用过程中并不是没有问题的,比如如果出现某个服务响应时间过长,或者服务已经挂掉,如果不做处理就会造成,调用该服务的其他服务大量线程挂起,从而引起服务雪崩式的瘫痪。这个时候就要用到分布式框架中的短路器的功能,避免一些无法相应的请求一直发送,并且断路器有自我检测并恢复的能力.当Hystrix Command请求后端服务失败数量超过一定比例(默认50%), 断路器会切换到开路状态(Open). 这时所有请求会直接失败而不会发送到后端服务. 断路器保持在开路状态一段时间后(默认5秒), 自动切换到半开路状态(HALF-OPEN). 这时会判断下一次请求的返回情况, 如果请求成功, 断路器切回闭路状态(CLOSED), 否则重新切换到开路状态(OPEN).