SpringCloud的基本使用

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
传统型负载均衡 CLB,每月750个小时 15LCU
简介: 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方案,并且只需要简单配置即可实现:

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
Java 关系型数据库 MySQL
[笔记]Springboot入门《一》springboot+jpa+bootstrap+crud
[笔记]Springboot入门《一》springboot+jpa+bootstrap+crud
|
1月前
|
负载均衡 网络协议 Java
浅谈Springboot与Springcloud的区别
浅谈Springboot与Springcloud的区别
36 1
|
5月前
|
负载均衡 Java 数据库连接
SpringCloud之OpenFeign简单使用
当远程服务调用失败时,会采用熔断降级策略,调用熔断降级的方法返回。
170 2
|
6月前
|
监控 Java 应用服务中间件
SpringBoot3 快速入门及原理分析
SpringBoot3 快速入门及原理分析
|
6月前
|
XML 开发框架 Java
springboot和springcloud有哪些区别?
springboot和springcloud区别有: 1、含义不同;2、作用不同;3、使用方式不同;4、特征不同;5、注释不同;6、优势不同;7、组件不同;8、设计目的不同。 其中,含义不同指的是springboot是一个快速开发框架,而SpringCloud是建立在SpringBoot上的服务框架。
100 4
|
6月前
|
负载均衡 Java API
SpringCloud之gateway基本使用解读
SpringCloud之gateway基本使用解读
|
XML Java Maven
实现springboot的简单使用~
实现springboot的简单使用~
|
XML Java 关系型数据库
SpringBoot的基本使用(整合SSM)
SpringBoot的基本使用(整合SSM)
398 0
SpringBoot的基本使用(整合SSM)
|
Java 编译器 API
springcloud入门超级详解
springcloud入门超级详解
102 0
|
搜索推荐 IDE Java
SpringBoot入门到精通-SpringBoot的基本使用(三)
SpringBoot入门到精通-SpringBoot的基本使用