Spring Cloud 速学

一. 服务架构

1. 单体架构:

将业务的所有功能集中在一个项目中开发,打成一个包部署。
简单方便,高度耦合,扩展性差,适合小型项目

2. 分布式架构:

根据业务功能对系统进行拆分,每个业务模块作为独立项目开发,称为一个服务。
松耦合,扩展性好,但架构复杂,难度大

3. 微服务:

一种良好的分布式架构方案。
拆分粒度更小、服务更独立、耦合度更低,但架构复杂,运维、监控、部署难度高

二. 微服务框架

1. SpringCloud:

        官网地址是:https://spring.io/projects/spring-cloud,是使用最广泛的微服务框架,集成了各种微服务功能组件,Spring Cloud 整合其它组件是基于Spring Boot 自动装配的加持实现。

        理解: 简称为微服务框架,其实本质是一个组件的集合,真正起作用的是组件,其中有五大组件较为常用:1、Eureka实现服务治理;2、Ribbon主要提供客户侧的软件负载均衡算法;3、Hystrix断路器,保护系统,控制故障范围;4、Zuul,api网关,路由,负载均衡等多种作用;5、Config配置管理。

2. Dubbo: 

        是阿里巴巴公司开源的服务框架,提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

3. Spring Cloud Alibaba:

        是阿里巴巴开源中间件跟 Spring Cloud 体系的融合。

4. 技术对比

5. 远程调用

        5.1 在启动类注册RestTemplate的bean

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

        5.2 实现远程调用

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;
    
    //1.注入RestTemplate 
    @Autowired
    private RestTemplate restTemplate;


    public Order queryOrderById(Long orderId) {
        //查询订单
        Order order = orderMapper.findById(orderId);

    //2.实现远程调用

        //2.1 定义远程查询user的url地址/8081为硬编码
        String url ="http://localhost:8081/user/"+order.getUserId();
        //2.2 发起远程调用
        User user = restTemplate.getForObject(url,User.class);
        //2.3 存入order
        order.setUser(user);
        //2.4 返回order
        return order;
    }
}

6.服务调用关系

    服务提供者:暴露接口给其它微服务调用
    服务消费者:调用其它微服务提供的接口
            提供者与消费者角色其实是相对的,一个服务可以同时是服务提供者和服务消费者

三. Eureka注册中心

1. eureka流程

 2. EurekaServer搭建

        2.1 引入SpringCloud为eureka提供的eureka-server依赖

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

        2.2 编写启动类,加@EnableEurekaServer注解,开启eureka

package cn.jqkait.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}

        2.3 编写application.yml配置eureka地址

server:
  port: 10010
spring:
  application:
    name: eureka-server
eureka:
  client:
    service-url: 
      defaultZone: http://127.0.0.1:10010/eureka

3. EurekaClient服务注册

        3.1 在供者的pom文件中引入注册依赖

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

        3.2 配置提供者的yml文件的eureka地址

    spring:
  application:
    name: userservice
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10010/eureka

4. EurekaClient服务拉取

        4.1 在消费者的pom文件中引入注册依赖
        4.2 配置消费者的yml文件的eureka地址
        4.3 消费者启动类bean上添加@LoadBalanced注解
        4.4 修改url地址,用服务提供者的服务名称远程调用

四. Ribbon负载均衡

1. 负载均衡原理

2. 负载均衡原理流程

        2.1 拦截到RestTemplate请求路径
        2.2 RibbonLoadBalancerClient会从请求url中获取服务名称
        2.3 DynamicServerListLoadBalancer根据服务名称到eureka拉取服务列表
        2.4 eureka返回列表中的信息数据
        2.5 IRule利用内置负载均衡规则,从列表中选择一个信息数据
        2.6 RibbonLoadBalancerClient修改请求地址后发起真实的请求

3.负载均衡策略

        3.1 规则的含义(默认的实现就是ZoneAvoidanceRule,是一种轮询方案)

         3.2 自定义负载均衡策略 (一般用默认的负载均衡规则)

                3.2.1 代码方式: 在提供者中的启动类定义一个新的IRule的bean

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

                3.2.2 配置文件方式: 在提供者的yml文件添加新的配置

userservice: # 给某个微服务配置负载均衡规则,这里是userservice服务
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则 

4. 饥饿加载

        Ribbon默认是采用懒加载,第一次访问时才会去创建LoadBalanceClient,请求时间长,而饥饿加载则会在项目启动时创建,降低第一次的访问耗时

ribbon:
  eager-load:
    enabled: true
    clients: userservice

五. Nacos注册中心

1. Nacos概述

        Nacos是阿里巴巴的产品,现在是SpringCloud中的一个组件。相比Eureka功能更加丰富,在国内受欢迎程度较高,在Nacos的 GitHub主页 提供有下载链接。Nacos的默认端口是8848,进入bin目录打開cmd执行命令startup.cmd -m standalone启动服务,账号和密码都是nacos。

(2条消息) Nacos与Eureka的区别有哪些?_Leon_Jinhai_Sun的博客-CSDN博客_nacos和eureka的区别

2. 将服务注册到nacos

        Nacos是SpringCloudAlibaba的组件,而SpringCloudAlibaba也遵循SpringCloud中定义的服务注册、服务发现规范。因此使用Nacos和使用Eureka对于微服务来说,并没有太大区别。


         2.1 在父工程的pom文件中引入SpringCloudAlibaba的依赖

<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.2 在需要注册的服务pom文件中引入nacos-discovery依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

        2.3 在需要注册的服务yml文件中配置nacos地址

spring:
  cloud:
    nacos:
      server-addr: localhost:8848

3. 配置集群

        3.1 在需要配置集群的服务yml文件中配置集群名称

spring:
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: 集群名称 # 集群名称

        3.2 修改负载均衡规则

userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则 

4. 权重配置

        因服务器设备性能存在差异,我们希望性能好的机器承担更多的用户请求,但默认情况下NacosRule是同集群内随机挑选,不会考虑机器的性能问题,因此Nacos提供了权重配置来控制访问频率,权重越大则访问频率越高,可以在nacos控制台找到实例列表,点击编辑,即可修改权重,如果权重修改为0,则该实例永远不会被访问。

5. 环境隔离

        点击命名空间--->新建命名空间--->创建命名空间--->给微服务配置namespace

spring:
  cloud:
    nacos:
      server-addr: localhost:8848
      discovery:
        cluster-name: 集群名称 # 集群名称
        namespace: 命名空间的id # 命名空间ID

六. Nacos配置中心(管理)

1. nacos中管理配置

(需要热更新的配置才有放到nacos管理的必要。基本不变更的配置保存在微服务本地较好 )

 2.从微服务拉取配置

(微服务拉取nacos中管理的配置,要与本地的application.yml配置合并,才能完成项目启动)

        2.1 引入nacos-config的客户端依赖

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

        2.2 添加一个bootstrap.yaml文件

spring:
  application:
    name: userservice # 服务名称
  profiles:
    active: dev #开发环境,这里是dev 
  cloud:
    nacos:
      server-addr: localhost:8848 # Nacos地址
      config:
        file-extension: yaml # 文件后缀名

        2.3 读取pattern.dateformat配置

@Slf4j
@RestController
@RequestMapping("/user")
@RefreshScope //配置热更新的注解
public class UserController {

    @Autowired
    private UserService userService;

    @Value("${pattern.dateformat}")
    private String dateformat;
    
    @GetMapping("now")
    public String now(){
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
    }

}

3. 配置热更新的方式

        3.1 方式一: 在@Value注入的变量所在类上添加注解@RefreshScope

        3.2 方式二: 使用@ConfigurationProperties注解代替@Value注解

// 3.2.1 在user-service服务中,添加一个类,读取patterrn.dateformat属性
@Component
@Data
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
    private String dateformat;
}


// 3.2.2 在UserController中使用这个类代替@Value
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;
    //注入patternProperties
    @Autowired
    private PatternProperties patternProperties;
    //编写测试方法
    @GetMapping("now")
    public String now(){
        return LocalDateTime
            .now()
            .format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));
    }
}

实现 nacos 中的配置热更新的两种方式

4.配置共享

        4.1 添加一个环境共享配置

         4.2 在服务中读取共享配置 

                4.2.1 修改PatternProperties类

    @Component
    @Data
    @ConfigurationProperties(prefix = "pattern")
    public class PatternProperties {
        private String dateformat;
        private String envSharedValue; //添加字段
    }

               4.2.2 添加一个测试方法

    //测试3  数据共享
    @GetMapping("prop")
    public PatternProperties prop(){
        return patternProperties;
    }

5. 配置共享的优先级

 6.搭建Nacos集群

        6.1 集群结构图

        6.2 搭建集群步奏

                6.2.1 搭建数据库,初始化数据库表结构

                6.2.2 下载nacos安装包

                6.2.3 配置nacos

                6.2.4 启动nacos集群

                6.2.5 nginx反向代理

(2条消息) nacos集群搭建详细教程_听者vae的博客-CSDN博客_nacos集群搭建

七. Feign远程调用

1. Feign远程调用的概述

        Feign官网是一个声明式的http客户端,它使编写 Java http 客户端变得更容易,其作用就是帮助我们优雅的实现http请求的发送。

2. Feign替代RestTemplate步骤

        2.1 在服务的pom文件中引入feign的依赖

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

        2.2 在服务的启动类上加@EnableFeignClients注解开启Feign的功能

        2.3 新建FeignClient接口编写Feign的客户端

@FeignClient("userservice") //Feign调用服务的注解
public interface UserClient {
    @GetMapping("/user/{id}") //请求参数+路径+参数+返回值 ,从controller里复制
    User findById(@PathVariable("id") Long id);
}

        2.4 使用FeignClient中定义的方法代替RestTemplate

    @Autowired
    private OrderMapper orderMapper;    
    @Autowired
//    private RestTemplate restTemplate;被替换掉
    private UserCliens userCliens;
    public Order queryOrderById(Long orderId) {
        //1. 查询订单
        Order order = orderMapper.findById(orderId);
        //2. 定义远程查询user的url地址
//        String url ="http://userservice/user/"+order.getUserId(); 替换掉
        //3. 发起远程调用
        User user = userCliens.queryById(order.getUserId());
        //4. 存入order
        order.setUser(user);
        //5.返回order
        return order;
    }

3. 自定义配置

(2条消息) Feign自定义配置详解_流楚丶格念的博客-CSDN博客_feignconfig

4. Feign使用优化

        为提高Feign的性能,主要手段就是使用连接池代替默认的URLConnection

        4.1 Apache的HttpClient演示

                4.1.1 在服务的pom文件中引入Apache的HttpClient依赖

<!--httpClient的依赖,连接池优化 -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

                4.1.2 在服务的application.yml中配置连接池

#    HttpClient线程池优化配置
feign:
  client:
    config:
      default: # default全局的配置
        loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
  httpclient:
    enabled: true # 开启feign对HttpClient的支持
    max-connections: 200 # 最大的连接数
    max-connections-per-route: 50 # 每个路径的最大连接数

八. Gateway服务网关

1.Gateway服务网关的概述

        Gateway是Cloud的全新项目,主要作用是身份认证,权限校验,服务路由,负载均衡,请求限流。

2. 快速入门

        2.1 创建SpringBoot工程gateway,引入网关依赖

<!--网关-->
<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.2 编写启动类

package cn.jqkait.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

        2.3 编写基础配置和路由规则

    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/开头就符合要求

        2.4 启动网关服务进行测试

        重启网关,访问http://localhost:10010/user/1时,符合/user/**规则,请求转发到uri:http://userservice/user/1,得到了结果:

快速搭建一个网关服务,动态路由、鉴权的流程(含流程图)_独行侠梦的博客-CSDN博客

3. 路由断言工厂的种类(规则)

名称说明示例
After是某个时间点后的请求- After=2037-01-20T17:42:47.789-07:00[America/Denver]
Before是某个时间点之前的请求- Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]
Between是某两个时间点之前的请求- Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver]
Cookie请求必须包含某些cookie- Cookie=chocolate, ch.p
Header请求必须包含某些header- Header=X-Request-Id, \d+
Host请求必须是访问某个host(域名)- Host=.somehost.org,.anotherhost.org
Method请求方式必须是指定方式- Method=GET,POST
Path请求路径必须符合指定规则- Path=/red/{segment},/blue/**
Query请求参数必须包含指定参数- Query=name, Jack或者- Query=name
RemoteAddr请求者的ip必须是指定范围- RemoteAddr=192.168.1.1/24
Weight权重处理

4.过滤器工厂

        4.1 路由过滤器的种类

                Spring提供了31种不同的路由过滤器工厂

名称说明
AddRequestHeader给当前请求添加一个请求头
RemoveRequestHeader移除请求中的一个请求头
AddResponseHeader给响应结果中添加一个响应头
RemoveResponseHeader从响应结果中移除有一个响应头

RequestRateLimiter

限制请求的流量

... ...

... ...

        4.2 请求头过滤器及默认过滤器

以AddRequestHeader 为例给单个或所有进入userservice的请求添加一个请求头。

spring:
  cloud:
    gateway:
      routes:
      - id: user-service 
        uri: lb://userservice 
        predicates: 
        - Path=/user/** 
#        给单个进入userservice的请求添加一个请求头
#        filters: # 过滤器
#       - AddRequestHeader=Truth, JQKAIT GOOD ! # 添加请求头

#        默认过滤器,给所有进入userservice的请求添加一个请求头
        default-filters: # 默认过滤项
        - AddRequestHeader=Truth, JQKAIT GOOD !

        4.3 全局过滤器

                4.3.1 全局过滤器定义方式: 实现GlobalFilter接口

 public interface GlobalFilter {
    /**
     *  处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
     *
     * @param exchange 请求上下文,里面可以获取Request、Response等信息
     * @param chain 用来把请求委托给下一个过滤器 
     * @return {@code Mono<Void>} 返回标示当前过滤器业务结束
     */
    Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

                4.3.2 自定义全局过滤器: 在gateway定义一个过滤器

package cn.jqkait.gateway.filters;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Order(1) //多个过滤器是  数值越小就会先执行
@Component
public class AuthorizeFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1.获取请求参数
        MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
        // 2.获取authorization参数
        String auth = params.getFirst("authorization");
        // 3.校验
        if ("admin".equals(auth)) {
            // 放行
            return chain.filter(exchange);
        }
        // 4.拦截
            // 4.1.禁止访问,设置状态码
        exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
            // 4.2.结束处理
        return exchange.getResponse().setComplete();
    }
}

5.跨域问题

        5.1 跨域问题的概述

        域名不一致就是跨域,主要包括:域名不同以及域名相同,端口不同,跨域问题是指浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题,而解决方案是CORS

        5.2 一般解决跨域问题

spring:
  cloud:
    gateway:
      # 。。。
      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
        corsConfigurations:
          '[/**]':
            allowedOrigins: # 允许哪些网站的跨域请求 
              - "http://localhost:8090"
            allowedMethods: # 允许的跨域ajax的请求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许在请求中携带的头信息
            allowCredentials: true # 是否允许携带cookie
            maxAge: 360000 # 这次跨域检测的有效期

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10JQK炸

如果对您有所帮助,请给点鼓励吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值