新SpringCloud学习笔记

介绍
Spring Cloud是一系列技术的有序整合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发。
Spring Boot擅长的是集成,把世界上最好的框架集成到自己项目中,Spring Cloud也是一样,把非常流行的微服务的技术整合到一起。
Spring Cloud从架构层面上降低了对大型系统构建的要求和难度,使我们以非常低的成本(技术或者硬件)搭建一套高效、分布式、容错的平台,但Spring Cloud也不是没有缺点,小型独立的项目不适合使用。

基础架构图

在这里插入图片描述

SpringCloud与SpringBoot版本匹配关系

SpringBootSpringCloud
1.2.xAngel版本
1.3.xBrixton版本
1.4.xCamden版本
1.5.xDalston版本、Edgware
2.0.xFinchley版本
2.1.xGreenwich GA版本 (2019年2月发布)

注册中心 Spring Cloud Eureka

简介:

Eureka解决了第一个问题:服务的管理,注册和发现、状态监管、动态路由。
Eureka负责管理记录服务提供者的信息。服务调用者无需自己寻找服务,Eureka自动匹配服务给调用
者。
Eureka与服务之间通过 心跳 机制进行监控;

原理图

在这里插入图片描述

整合注册中心Eureka

1.创建eureka_server的springboot工程。
2.勾选坐标

  • Spring Boot DevTools (热部署插件)
  • Eureka Server (Eureka服务端)
  1. 在启动类EurekaServerApplication声明当前应用为Eureka服务使用 @EnableEurekaServer 注解
  2. 编写配置文件application.yml
# 端口
server:
  #  从jvm中拿值,如果没有使用默认配置8001(在VM options中配 -Dport=10086)
  port: ${port:10086}
spring:
  application:
    name: eureka-server # 应用名称,会在Eureka中作为服务的id标识(serviceId)
# 服务注册中心
eureka:
  client:
    service-url: # EurekaServer的地址,现在是自己的地址,如果是集群,需要写其它Server的地址。
      defaultZone: http://127.0.0.1:10086/eureka
    # 是否抓取注册列表
    fetch-registry: false
    # 是否注册服务中心Eureka
    register-with-eureka: false

5.启动EurekaServerApplication
6.测试访问地址http://127.0.0.1:10086,如下信息代表访问成功
在这里插入图片描述

服务提供者-注册服务中心

1.在服务提供者user_service工程中添加Eureka(客户端)依赖

<!--eureka客户端starter-->
<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
	</dependency>
</dependencies>
<!--SpringCloud所有依赖管理的坐标-->
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>Greenwich.SR1</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

2.在启动类上开启Eureka客户端发现功能 @EnableDiscoveryClient
3.修改配置文件:spring.application.name指定应用名称,作为服务ID使用

server:
  #  从jvm中拿值,如果没有使用默认配置8001(在VM options中配 -Dport=8001)
  port: ${port:8001}
spring:
  application:
    name: provider-service  # 应用名称,会在Eureka中作为服务的id标识
  #  数据源配置
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://127.0.0.1/springcloud?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
# mybatis配置
mybatis:
  #  扫描接口对应的XML映射文件
  mapper-locations: classpath:mapper/*.xml
  #  起别名
  type-aliases-package: top.zhenghy123.pojo
# 配置eureka
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka



4.客户端代码会自动把服务注册到EurekaServer中
5.在Eureka监控页面可以看到服务注册成功信息

服务消费者-注册服务中心

1.在服务消费者spring_cloud_itcast_consumer_service工程中添加Eureka(客户端)依赖

<!-- Eureka客户端 -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--SpringCloud所有依赖管理的坐标-->
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>Greenwich.SR1</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

2.在启动类开启Eureka客户端 @EnableDiscoveryClient
3.修改配置文件:加入EurekaServer地址

server:
  #  从jvm中拿值,如果没有使用默认配置8001(在VM options中配 -Dport=9002)
  port: ${port:9002}
spring:
  application:
    name: provider-service  # 应用名称,会在Eureka中作为服务的id标识
# 配置eureka
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
# 修改服务地址轮询策略,默认是轮询,配置之后变随机
# 配置访问(PROVIDER-SERVICE)服务的负债均衡策略
# RandomRule随机策略
# RoundRobinRule轮询策略
PROVIDER-SERVICE:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
feign:
  hystrix:
    # 开启feign熔断器的支持
    enabled: true
  compression:
    # 请求压缩
    request:
      enabled: true
      # 起步压缩大小
      min-request-size: 1024
      # 请求压缩的数据类型
      mime-types: text/xml,application/xml,josn
    # 响应压缩
    response:
      enabled: true

4.启动服务,在服务中心查看是否注册成功

消费者通过Eureka访问提供者

什么是Feign:

Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单。使用Feign,只需要创建一个接口并注解。它具有可插拔的注解特性,可使用Feign 注解和JAX-RS注解。Feign支持可插拔的编码器和解码器。Feign默认集成了Ribbon并和Eureka结合默认实现了负载均衡的效果
简而言之:

  • Feign 采用的是基于接口的注解
  • Feign 整合了ribbon

1.添加Feign依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2.在启动类上加入@EnableFeignClients注解开启Feign的功能
3.定义一个UserService接口,通过@ FeignClient(value=“服务名”,fallback = 指定熔断降级处理类),来指定调用哪个服务。比如在代码中调用了provider-service服务的“/user/findAll”接口

@ FeignClient的fallback属性:fallback指定熔断降级处理类
编写一个类实现此接口在类上加@Component注解即可(下方Feign使用Hystrix实现降级有介绍)

代码如下:

@FeignClient(value = "PROVIDER-SERVICE", fallback = UserServiceImpl.class)
//value为目标服务的ID,fallback指定熔断降级处理类 编写一个类实现此接口在类上加@Component注解即可(下方**Feign使用Hystrix实现降级**有介绍)
public interface UserService {
    @RequestMapping("/user/findAll")
    List<User> findAll();
}

4.在controller层,注入UserService来消费服务

@RestController
@RequestMapping("test")
public class UserController {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private UserService userService;

    @RequestMapping("findAll")
    public String findAll() {
        return restTemplate.getForObject("http://PROVIDER-SERVICE/user/findAll", String.class);
    }

    @RequestMapping("test")
    public List test(){
        return userService.findAll();
    }
}

Feign使用Hystrix实现降级

服务雪崩

在这里插入图片描述如图-1,如果所有服务A/B/C网络/应用等都正常,同时能够快速的处理请求并返回,服务之间就可以正常的调度。

在这里插入图片描述
如图-2,如果A服务出现异常情况(网络异常/内部数据库异常等)无法在指定的时间内返回B服务结果,那么由于C服务会持续的请求B服务,最终导致B服务积压了大量的请求而服务器奔溃不可用。

在这里插入图片描述
如图-3,B服务由于A服务的不可用导致自身请求积压而崩溃,所以所有的请求蔓延到下游的C服务,最终也导致C服务不可用崩溃,如图-4所示。

在这里插入图片描述
综上所述:服务雪崩就是由于上游(例如A)的服务异常不可用,最终蔓延到下游的所有服务,导致所有相关下游的微服务应用不可用而系统崩溃。

Hystrix简介

Hystrix是由Netfix开源的一个延迟和容错工具库,用于解决远程调用/服务或者第三方库防止级联失败提示系统的可用性和容错性。
1.Maven依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

2.修改配置文件

feign:
  hystrix:
    # 开启feign熔断器的支持
    enabled: true
  compression:
    # 请求压缩
    request:
      enabled: true
      # 起步压缩大小
      min-request-size: 1024
      # 请求压缩的数据类型
      mime-types: text/xml,application/xml,josn
    # 响应压缩
    response:
      enabled: true

3.添加降级类
Feign服务熔断降级其实是通过调度超时就调用本地的方法,而不是一直等待服务返回。Feign调度服务是通过接口+注解方式的,我们需要实现该接口用于实现服务降级调用本地方法。

@Component
public class UserServiceImpl implements UserService {
    @Override
    public List findAll() {
        ArrayList<String> list = new ArrayList<>();
        list.add("服务器异常");
        return list;
    }
}

Feign接口类

主要是通过@FeignClient的fallback属性定义降级后调用那个类的方法,这里方法名称等都是一致才可以。
@FeignClient(value = "PROVIDER-SERVICE", fallback = UserServiceImpl.class)
public interface UserService {
    @RequestMapping("/user/findAll")
    List<User> findAll();
}

负载均衡 Spring Cloud Ribbon

Ribbon 简介

解决了集群服务中,多个服务高效率访问的问题。

什么是Ribbon?

Ribbon是Netflix发布的负载均衡器,有助于控制HTTP客户端行为。为Ribbon配置服务提供者地址列表
后,Ribbon就可基于负载均衡算法,自动帮助服务消费者请求。
Ribbon默认提供的负载均衡算法:轮询,随机其他…。当然,我们可用自己定义负载均衡算法
在这里插入图片描述

实现负载均衡访问用户服务。
如果想要做负载均衡,我们的服务至少2个以上。所有第一步目标
步骤:

  1. 启动多个user_service服务
    修改UserServiceApplication的application.yml配置文件
server:
  #  从jvm中拿值,如果没有使用默认配置8001(在VM options中配 -Dport=8001)
  port: ${port:8001}
  1. 编辑应用启动配置
    在这里插入图片描述

  2. 复制一份UserServiceApplication
    在这里插入图片描述

  3. 启动多个Application应用

  4. Eureka服务中心可查看,注册成功.

开启消费者调用负载均衡

Feign和Eureka都默认集成了Ribbon,所以无需引入依赖。
注:这里使用的是Feign默认实现了负载均衡的效果

  • 直接在配置文件中配置即可
# 修改服务地址轮询策略,默认是轮询,配置之后变随机
# 配置访问(PROVIDER-SERVICE)服务的负债均衡策略
# RandomRule随机策略
# RoundRobinRule轮询策略
PROVIDER-SERVICE: #对应的服务ID
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

网关 Spring Cloud Gateway

简介

Spring Cloud Gateway 是Spring Cloud团队的一个全新项目,基于Spring
5.0、SpringBoot2.0、 Project Reactor 等技术开发的网关。 旨在为微服务架构提供一种简单有效统一的REST 请求路由管理方 式。 Spring Cloud Gateway 作为SpringCloud生态系统中的网关,目标是替代Netflix
Zuul。Gateway不仅 提供统一路由方式,并且基于Filter链的方式提供网关的基本功能。例如:安全,监控/指标,和限流。
本身也是一个微服务,需要注册到Eureka

网关的核心功能:过滤(权限)、路由
核心概念:

  • List item 路由(route):
  • 断言Predicate函数:路由转发规则
  • 过滤器(Filter):
    在这里插入图片描述
  • 不管是来自客户端的请求,还是服务内部调用。一切对服务的请求都可经过网关。
  • 网关实现鉴权、动态路由等等操作。
  • Gateway是我们服务的统一入口
搭建网关微服务,实现服务路由分发

实现步骤:

  1. 创建SpringBoot工程gateway_server
  2. 勾选starter:网关、Eureka客户端
  3. 编写基础配置
  4. 编写路由规则
  5. 启动网关服务进行测试

实现过程:

  1. 创建SpringBoot工程gateway_server

  2. 勾选Starter:网关、Eureka客户端
    在这里插入图片描述

  3. 启动引导类加@EnableDiscoveryClient注解开启注册中心Eureka客户端发现

  4. 编写基础配置

server:
  #  从jvm中拿值,如果没有使用默认配置8001(在VM options中配 -Dport=8001)
  port: ${port :10010} #模板问题¥需要改成英文 $
spring:
  application:
    name: api-gatewat # 应用名称,会在Eureka中作为服务的id标识(serviceId)
# 服务注册中心
eureka:
  client:
    service-url: # EurekaServer的地址,现在是自己的地址,如果是集群,需要写其它Server的地址。
      defaultZone: http://127.0.0.1:10086/eureka

  1. 编写路由规则
    需要用网关来路由user_service服务,查看服务ip和端口
    在这里插入图片描述
    修改gateway_server的配置文件application.yml,配置网关内容
spring:
  cloud:
    #  配置网关内容
    gateway:
      # 路由si(集合)
      routes:
        # id唯一标识(路由id,可以随便写)
        - id: consumer-service-route
          # 路由服务地址
          uri: http://127.0.0.1:9002
          # 断言
          predicates:
            - Path=/user/**
将符合 path 规则的请求,路由到 uri 参数指定地址。
举例:http://localhost:10010/user/findById?id=1 路由转发到http://localhost:9091/user/findById?id=1
  1. 启动GatewayApplication进行测试
    访问路径中,必须包含路由规则的映射路径/user才会被路由
    在这里插入图片描述
动态路由

在这里插入图片描述
刚才路由规则中,我们把路径对应服务地址写死了!如果服务提供者集群的话,这样做不合理。应该是
根据服务名称,去Eureka注册中心查找服务对应的所有实例列表,然后进行动态路由!

  • 修改映射配置:通过服务名称获取
    因为已经配置了Eureka客户端,可以从Eureka获取服务的地址信息,修改application.yml文
    件如下
# 注解版
spring:
  cloud:
    #  配置网关内容
    gateway:
      # 路由si(集合可以配置多个服务)
      routes:
        # id唯一标识(路由id,可以随便写)
        - id: consumer-service-route
          # 路由服务地址
          # uri: http://127.0.0.1:9002
          # 采用lb协议,会从Eureka注册中心获取服务请求地址
          # 路由地址如果通过lb协议加服务名称时,会自动使用负载均衡访问对应服务(默认使用随机的策略)
          # 规则:lb协议+服务名称
          uri: lb://consumer-service
          # 断言
          predicates:
            - Path=/test/**
路由配置中uri所用的协议为lb时,gateway将把user-service解析为实际的主机和端口,并通
过Ribbon进行负载均衡。
  • 启动GatewayApplication测试
    在这里插入图片描述
    这次gateway进行路由时,会利用Ribbon进行负载均衡访问。日志中可以看到使用了负载均
    衡器。
    在这里插入图片描述
路由前缀

第一:添加前缀:
在gateway中可以通过配置路由的过滤器PrefixPath 实现映射路径中的前缀添加。可以起到隐藏接口地
址的作用,避免接口地址暴露。

  1. 配置请求地址添加路径前缀过滤
  cloud:
    #  配置网关内容
    gateway:
      # 路由si(集合可以配置多个服务)
      routes:
        # id唯一标识(路由id,可以随便写)
        - id: consumer-service-route
          # 采用lb协议,会从Eureka注册中心获取服务请求地址
          # 路由地址如果通过lb协议加服务名称时,会自动使用负载均衡访问对应服务(默认使用随机的策略)
          # 规则:lb协议+服务名称
          uri: lb://consumer-service
          # 断言
          predicates:
            - Path=/**
          # 请求地址添加路径前缀过滤器
          filters:
            - PrefixPath=/test
  1. 重启GatewayApplication
  2. 配置完成的效果:

在这里插入图片描述

第二:去除前缀:

在gateway中通过配置路由过滤器StripPrefix,实现映射路径中地址的去除。通过StripPrefix=1来指定
路由要去掉的前缀个数
。如:路径/api/user/1将会被路由到/user/1。

  1. 配置去除路径前缀过滤器
  cloud:
    #  配置网关内容
    gateway:
      # 路由si(集合可以配置多个服务)
      routes:
        # id唯一标识(路由id,可以随便写)
        - id: consumer-service-route
          # 采用lb协议,会从Eureka注册中心获取服务请求地址
          # 路由地址如果通过lb协议加服务名称时,会自动使用负载均衡访问对应服务(默认使用随机的策略)
          # 规则:lb协议+服务名称
          uri: lb://consumer-service
          # 断言
          predicates:
            - Path=/api/test/**
          # 去除路径前缀过滤器
          filters:
            - StripPrefix=1 # 写1会去除 /api 
  1. 重启GatewayApplication
  2. 访问查看效果
    在这里插入图片描述
过滤器

简介:过滤器作为网关的其中一个重要功能,就是实现请求的鉴权。前面的(路由前缀和去除前缀)章节中的功能也是使用过滤器实现的。
Gateway自带过滤器有几十个,常见自带过滤器有:

过滤器名称说明
AddRequestHeader对匹配上的请求加上Header
AddRequestParameters对匹配上的请求路由
AddResponseHeader对从网关返回的响应添加Header
StripPrefix对匹配上的请求路径去除前缀
PrefixPath对匹配上的请求路径添加前缀

详细说明官方链接
使用场景:

  • 请求鉴权:如果没有访问权限,直接进行拦截 (最常用)
  • 异常处理:记录异常日志
  • 服务调用时长统计
过滤器配置

**过滤器类型:**Gateway有两种过滤器

  • 局部过滤器:只作用在当前配置的路由上。
  • 全局过滤器:作用在所有路由上。
    配置全局过滤器:

对输出的响应设置其头部属性名称为i-love,值为yuge

  1. 修改配置文件
  cloud:
    #  配置网关内容
    gateway:
      # 配置全局默认过滤器
      default-filters:
        # 往响应过滤器中加入信息
        - AddResponseHeader=i-love,yuge
自定义全局过滤器

需求:模拟一个登录的校验。基本逻辑:如果请求中有token参数,则认为请求有效,放行。
实现步骤:

  1. 在gateway_server工程编写全局过滤器类MyGlobalFilter
  2. 编写业务逻辑代码:判断如果包含token值,则放行请求,如果不包含则拦截
  3. 访问接口测试,加token和不加token。
    实现过程:
  4. 在gateway_server工程编写全局过滤器类MyGlobalFilter
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        //1、获取参数中的token,以及token的值
        String token = request.getQueryParams().getFirst("token");
        //2、如果token的值为空,则拦截
        if (StringUtils.isBlank(token)) {
            //响应未授权状态码401
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            //拦截
            return response.setComplete();
        }
        //放行
        return chain.filter(exchange);
    }

    /**
     * 定义过滤器执行顺序
     * 返回值越小,越靠前执行
     *
     * @return
     */
    @Override
    public int getOrder() {
        return 0;//
    }
}
  1. 在全局过滤器里面配上自定义的过滤器即可
  cloud:
    #  配置网关内容
    gateway:
      # 配置全局默认过滤器
      default-filters:
        - MyGlobalFilter
  1. 访问:http://localhost:10010/api/user/findById?id=1
    在这里插入图片描述

  2. 访问:http://localhost:10010/api/user/findById?id=1&token=11
    在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值