SpringCloud的基本使用

1.单体架构和分布式架构的区别

1.1 单体架构

在这里插入图片描述

(1)什么是单体架构
将业务的所有功能集中在一个项目中开发,打成一个包部署
(2)单体架构的优缺点
优点:①架构简单②部署成本低
缺点:耦合度高(维护困难、升级困难)

1.2 分布式架构

在这里插入图片描述
(1)什么是分布式架构
根据业务功能对系统开发,每个业务功能模块作为独立项目开发,称为一个服务
(2)分布式架构的优缺点
优点:①降低服务耦合②有利于服务升级和扩展
缺点:服务调用关系错综复杂

2.微服务

2.1 微服务是什么

微服务是一种经过良好架构设计的分布式架构方案,微服务架构特征:
(1)单一职责:微服务拆分粒度更小,每一个服务都对应唯一的业务能力,做到单一职责,避免重复业务开发
(2)面向服务:微服务对外暴露业务接口
(3)自治:团队独立、技术独立、数据独立、部署独立
(4)隔离性强:服务调用做好隔离、容错、降级,避免出现级联问题

在这里插入图片描述

2.2 微服务技术对比

微服务这种方案需要技术框架来落地,全球的互联网公司都在积极尝试自己的微服务落地技术。在国内最知名的就是SpringCloud和阿里巴巴的Dubbo
在这里插入图片描述

2.3 企业需求

在这里插入图片描述

2.4 微服务的远程调用

(1)创建相关数据库和配置如下
①数据库cloud_user中的tb_user表:

在这里插入图片描述

②数据库cloud_order中的tb_order表:

在这里插入图片描述

③userservice服务的application.xml配置

server:
  port: 8081
spring:
  application:
    name: userservice
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_user?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver

④orderservice服务的application.xml配置

server:
  port: 8001
spring:
  application:
    name: ordeservice
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver

(2)创建RestTemplate并注入spring容器
在这里插入图片描述
(3)服务远程调用RestTemplate

在这里插入图片描述
(4)id为103的查询结果如下:
在这里插入图片描述
(2)微服务调用方式总结
①基于RestTemplate发起的http请求实现远程调用
②http请求做远程调用是与语言无关的调用,只要知道对方的ip、端口、接口路径、请求参数即可

2.5 提供者与消费者

(1)服务提供者:一次业务中,被其他微服务调用的服务(提供接口给其他微服务)
(2)服务消费者:一次业务中,调用其他微服务的服务(调用其他微服务提供的接口)
(3)提供者与消费者角色其实是相对的,一个服务可以同时是服务提供者和服务消费者

3.Eureka注册中心

3.1 eureka的作用

(1)消费者该如何获取服务提供者具体信息?
①服务提供者启动时向eureka注册自己的信息
②eureka保存这些信息
③消费者根据服务名称向eureka拉取提供者信息
(2)如果有多个服务提供者,消费者该如何选择?
服务消费者利用负载均衡算法,从服务列表中挑选一个
(3)消费者如何感知服务提供者健康状态?
①服务提供者会每隔30秒向EurekaServer发送心跳请求,报告健康状态
②eureka会更新记录服务列表信息,心跳不正常会被剔除
③消费者就可以拉取到最新的信息

3.2 在Eureka架构中,微服务角色有两类

  • EurekaServer:服务端,注册中心
    (1)记录服务信息
    (2)心跳监控
  • EurekaClient:客户端
    (1)Provider:服务提供者,例如案例中的 user-service
    ①注册自己的信息到EurekaServer
    ②每隔30秒向EurekaServer发送心跳
    (2)consumer:服务消费者,例如案例中的 order-service
    ①根据服务名称从EurekaServer拉取服务列表
    ②基于服务列表做负载均衡,选中一个微服务后发起远程调用

3.3 搭建EurekaServer

(1)创建项目,引入spring-cloud-starter-netflix-eureka-server的依赖

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

(2)编写启动类,添加@EnableEurekaServer注解
(3)添加application.yml文件,编写配置

server:
  port: 10086
spring:
  application:
    name: eurekaserver # eureka的服务器名称
eureka:
  client:
    service-url: # eureka的地址信息
      defaultZone: http://127.0.0.1:10086/eureka/

3.4 Eureka注册

  • 将user-service服务注册到EurekaServer步骤如下:
    (1)在user-service项目中引入spring-cloud-starter-netflix-eureka-client的依赖
<!--eureka客户端依赖-->
 <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  </dependency>

(2)在application.yml文件中,编写配置

spring:
  application:
    name: userservice # user服务的服务名称
eureka:
  client:
    service-url:  # eureka的地址信息
      defaultZone: http://127.0.0.1:10086/eureka
      

(3)模拟多实例部署(为了避免端口冲突,需要修改端口设置)
在这里插入图片描述

  • 将order-service服务注册到EurekaServer步骤如下:
    在这里插入图片描述

3.5 服务拉取

服务拉取是基于服务名称获取服务列表,然后再对服务列表做负载均衡;在order-service完成服务拉取
(1)修改OrderService的代码,修改访问的url路径,用服务名代替ip、端口号:

  String url = "http://userservice/user/" + order.getUserId();

(2)在order-service项目的启动类OrderApplication中的RestTemplate添加负载均衡注解:

 @LoadBalanced
 @Bean
 public RestTemplate restTemplate()  {
        return new RestTemplate();
    }

4.Ribbon负载均衡

4.1 负载均衡流程

在这里插入图片描述

在这里插入图片描述

当请求进入Ribbon类以后,请求会被LoadBalancerInterceptor负载均衡拦截器给拦截,会得到请求中的服务名称(如userservice)。把它交给RibbonLoadBalancerClient,而RibbonLoadBalancerClient会把服务交给DynamicServiceListLoadBalancer,DynamicServiceListLoadBalancer它就会去eureka-server里拉取服务列表,得到多个服务的信息,找IRule做负载均衡,IRule会基于规则(比如轮询)把值返回给RibbonLoadBanlancerClient

4.2 负载均衡策略

在这里插入图片描述

在这里插入图片描述

4.3 修改负载均衡策略

(1)代码方式(全局配置,访问任何服务都可以):在order-service中的OrderApplication类中,定义一个新的IRule

 @Bean
    public IRule randomRule(){
        return new RandomRule();
    }

(2)配置文件方式(针对某个微服务而言):在order-service的application.yml文件中,添加新的配置也可以修改规则

userservice:  # 服务名称  
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #负载均衡规则

4.4 加载方式

Ribbon默认采用的是懒加载,即第一次访问时才会创建LoadBalanceClient,请求时间会很长。而饥饿加载则会在
项目启动时创建,降低第一次访问的耗时,通过下面的配置开启饥饿加载:

 ribbon:
    eager-load:
      enabled: true # 开启饥饿加载
      clients: userservice # 指定对userservice这个服务饥饿加载
      

补充:

clients:  # 指定对多个服务饥饿加载
	- userservice
	- xxxservice

5.Nacos注册中心

5.1 认识Nacos

Nacos是阿里巴巴的产品,现在是SpringCloud中的一个组件。相比Eureka功能更加丰富,在国内更受欢迎。
(1)在Nacos的GitHub页面,提供有下载链接,可以下载编译好的Nacos服务端或者源代码:
①GitHub主页:https://github.com/alibaba/nacos
②GitHub的Release下载页:https://github.com/alibaba/nacos/releases
(2)启动
进入bin目录,然后执行windows命令 startup.cmd -m standalone 单机启动
(3)成功页面如下(默认登陆账号密码都为nacos)
在这里插入图片描述

5.2 服务注册到Nacos

(1)在cloud-demo父工程中添加spring-cloud-alibaba的管理依赖

<!--    spring-cloud-alibaba -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.6.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

(2)在order-service和user-service中添加nacos的客户端依赖

  <!--   Nacos的客户端依赖     -->
       <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
       </dependency>

(3)配置user-service&order-service中的application.yml文件

spring:
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos服务端地址

(4)启动并测试
在这里插入图片描述

5.3 Nacos服务分级存储模型

(1)一级是服务,例如userservice(一个服务可以包含多个实例)
(2)二级是集群,例如上海或杭州
(3)三级是实例,例如杭州机房的某一台机器部署了userservice的服务器

在这里插入图片描述

5.4 集群

(1)在order-service中设置实例的集群属性

spring:
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos服务端地址
      discovery:
        cluster-name: HZ # 配置集群名称,也就是机房的位置,例如杭州

(2)在order-service中设置负载均衡的IRule为NacosRule,这个规则优先会寻找与自己同集群的服务:

userservice:  # 要做配置的微服务名称
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule #负载均衡规则

补充:NacosRule负载均衡策略
①优先选择同集群服务实例列表
②本地集群找不到提供者,才去其他集群寻找,并且会报警告
③确定了可用实例列表后,再采用随机负载均衡挑选实例

5.5 根据权重负载均衡

(1)在Nacos控制台可以设置实例的权重值(0~1之间)
在这里插入图片描述
(2)同集群内的多个实例,权重越高被访问的频率越高
(3)权重设置为0则完全不会被访问

5.6 环境隔离-namespace

Nacos中服务器和数据存储的最外层都是一个名为namespace的东西,用来做最外层隔离
在这里插入图片描述
(1)在Nacos控制台可以创建namespace,用来隔离不同环境
在这里插入图片描述
(2)然后填写一个新的命名空间信息
在这里插入图片描述
(3)保存之后会在控制台看到这个命名空间的id
在这里插入图片描述
(4)修改order-service的application.yml,添加namespace

spring:
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos服务端地址
      discovery:
        cluster-name: HZ # 配置集群名称,也就是机房的位置,例如杭州
        namespace: 94cc0d41-4020-40fc-bc84-5ac7045a224e # 命名空间,填ID

(5)重启order-service后,再来看控制台:
在这里插入图片描述
(6)此时访问order-service,因为namespace不同,会导致找不到userservice,控制台会报错
在这里插入图片描述
补充:
①每个namespace都有唯一id
②服务设置namespace时要写id而不是全称
③不同namespace下的服务互相不可见

5.7 临时实例和非临时实例

服务注册到Nacos时,可以选择注册为临时或非临时实例,通过下面的配置来设置:

spring:
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos服务端地址
      discovery:
        cluster-name: HZ # 配置集群名称,也就是机房的位置,例如杭州
          ephemeral: false # 设置为非临时实例

临时实例宕机时,会从nacos的服务列表中剔除,而非临时实例则不会

5.8 Nacos与eureka的异同点

(1)Nacos与eureka的共同点
①都支持服务注册和服务拉取
②都支持服务提供者心跳方式做健康检测
(2)Nacos与Eureka的区别
①Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式
②临时实例心跳不正常会被剔除,非临时实例则不会被剔除
③Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
④Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式

6.Nacos配置管理

6.1 统一配置管理

在这里插入图片描述
(1)在Nacos中添加配置信息
在这里插入图片描述
(2)在弹出表单中填写配置信息:
在这里插入图片描述①Data ID:服务名称+当前项目的运行环境.后缀名(如:userservice-dev.yaml)
②Group:一般不用改,默认就行
③描述:介绍配置文件是干什么的
④配置内容:有热更新需求的配置在这里

(3)引入Nacos的配置管理客户端依赖:

<!--nacos配置管理依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

(4)在userservice的resource目录下添加一个bootstrap.yml文件在这里插入图片描述
在这里插入图片描述
注意:bootstrap.yml比application.yml优先级高很多,把nacos地址、文件相关信息等放到bootstrap.yml里面,就可以完成nacos配置文件的读取

6.2 配置自动刷新

Nacos中的配置文件变更后,微服务无需重启就可以感知。不过需要通过下面两种配置实现:
(1)方式一:在使用@Value注入的变量所在的类上添加注解@RefreshScope
在这里插入图片描述
(2)方式二:使用@ConfigurationProperties注解
在这里插入图片描述
在这里插入图片描述

6.3 多环境配置共享

微服务启动时会从nacos中读取多个配置文件:
(1)服务名-环境.后缀,例如:userservice-dev.yaml
(2)服务名.后缀,例如:userservice.yaml
无论环境如何变化,服务名.后缀这个文件一定会被加载。因此,多环境共享配置可以写入这个文件
(3)多种配置的优先级:
在这里插入图片描述

6.4 Nacos生产环境下一定要部署为集群状态

在这里插入图片描述

7.http客户端Feign

7.1 RestTemplate方式调用存在的问题

(1)我们先来看看以前利用RestTemplate发起远程调用的代码:

    String url = "http://userservice/user/" + order.getUserId();
    User user = restTemplate.getForObject(url, User.class);

(2)存在下面的问题:
①代码可读性差,编程体验不统一
②参数复杂的URL难以维护

7.2 Feign的使用

Feign是一个声明式的http客户端,其作用就是帮助我们优雅的实现http请求的发送,解决RestTemplate
方式调用所存在的问题
(1)引入依赖:

  <!--    Feign的依赖    -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

(2)在调用者(order-service)的启动类上添加注解并开启Feign的功能
在这里插入图片描述
(3)创建clients包,编写Feign的客户端

@FeignClient("userservice")
public interface UserClient {
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

Feign的客户端主要是基于SpringMVC的注解来声明远程调用的信息,比如:
①服务名称:userservice
②请求方式:GET
③请求路径:/user/{id}
④请求参数:Long id
⑤返回值类型:User
(4)用Feign客户端代替RestTemplate

	@Autowired
    private UserClient userClient;
    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        //2.利用Feign发起http请求,查询用户
        User user = userClient.findById(order.getUserId());
        //3.封装User到Order
        order.setUser(user);
        //4.返回
        return order;

7.3 自定义Feign的配置

(1)Feign运行自定义配置来覆盖默认配置,可以修改的配置如下:
在这里插入图片描述
注意:一般我们需要配置的就是日志级别
(2)配置Feign日志有两种方式
方式一:配置文件方式
①全局生效
在这里插入图片描述
②局部生效
在这里插入图片描述
方式二:java代码方式,需要先声明一个Bean:
(1)自定义一个配置类

public class FeignClientConfiguration {
    @Bean
    public Logger.Level feignLogLevel(){
        return Logger.Level.BASIC;
    }
}

①如果是全局配置,把它放到@EnableFeignClients这个注解中

@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class)
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

②如果是局部配置,把它放到@FeignClient这个注解中

@FeignClient(value = "userservice",configuration = FeignClientConfiguration.class)
public interface UserClients {
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

8.统一网关GateWay

8.1 网关功能

(1)身份认证和权限较验
(2)服务路由(选择需要的微服务)、负载均衡
(3)请求限流

8.2 网关的技术实现

在SpringCloud中网关的实现包括两种:
(1)gateway(2)zuul
Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。

8.3 搭建网关服务的步骤

(1)创建新的module,引入SpringCloudGateway的依赖和Nacos的服务发现依赖:

  <!--    网关依赖    -->
   <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-gateway</artifactId>
   </dependency>
  <!-- nacos服务发现依赖-->
   <dependency>
         <groupId>com.alibaba.cloud</groupId>
         <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
   </dependency>

(2)编写路由配置及nacos地址

server:
  port: 10010 # 网关端口
spring:
  application:
    name: gateway # 服务名称
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址
    gateway:
      routes: # 网关路由配置
        - id: user-service # 路由id,自定义,只要唯一即可
          # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
          uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
          predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
            - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
        - id: order-service # 路由id,自定义,只要唯一即可
            uri: lb://orderservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
            predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
              - Path=/order/** # 这个是按照路径匹配,只要以/order/开头就符合要求

在这里插入图片描述
(3)网关路由可以配置的内容包括:
①路由id:路由唯一标识
②uri:路由目的地,支持lb和http两种
③predicates:路由断言,判断请求是否符合要求,符合则转发到路由目的地
④filters:路由过滤器,处理请求或响应

8.4 路由断言工厂Route Predicate Factory

(1)我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件。例如Path=/user/**是按照路径匹配,这个规则是由org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类来处理的
像这样的断言工厂在SpringCloudGateway还有十几个
(2)Spring提供了11种基本的Predicate工厂:

在这里插入图片描述

8.5 路由过滤器 GatewayFilter

(1)GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理:
在这里插入图片描述
(2)Spring提供了31种不同的路由过滤器工厂。例如:
在这里插入图片描述
(3)案例:给所有进入userservice的请求添加一个请求头:Truth=itcast is freaking awesome!
实现方式:在gateway中修改application.yml文件,给userservice的路由添加过滤器:

在这里插入图片描述
(4)默认过滤器:如果要对所有的路由都生效,则可以将过滤器工厂写到default下。格式如下:
在这里插入图片描述

8.6 全局过滤器

(1)全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。区别在于GatewayFilter是通过配置去定义,处理逻辑是固定的。而GlobalFilter的逻辑需要自己写代码实现。定义方式是去实现GlobalFilter接口。

在这里插入图片描述

(2)案例:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:
参数中是否有authorization,authorization参数值是否为admin;如果同时满足则放行,否则拦截
①自定义类,实现GlobalFilter接口,添加@Order注解:

在这里插入图片描述

8.7 过滤器执行顺序

在这里插入图片描述
(1)过滤器执行顺序
①每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前。
②GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定
③路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。
④当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。

8.8 跨域问题处理

(1)跨域:域名不一致就是跨域,主要包括:
①域名不同: www.taobao.com 和 www.taobao.org 和 www.jd.com 和 miaosha.jd.com
②域名相同,端口不同:localhost:8080和localhost8081
(2)跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
(3)解决方案:CORS
(4)网关处理跨域采用的同样是CORS方案,并且只需要简单配置即可实现:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值