SpringCloud

SpringCloud

分布式:将一种业务拆分成多个子业务部署在多台服务器上

集群:将多台服务器组合在一起提供同一种服务

Sentinel

下载地址:https://github.com/alibaba/Sentinel/releases

文档:https://sentinelguard.io/zh-cn/docs/quick-start.html

https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6

运行jar默认是8080端口

指定端口运行

java -jar -Dserver.prot=9090 sentinel-dashboard-1.8.0.jar

sentinel:登录账户密码默认为 sentinel

配置

 <!--sentinel-->
 <dependency>
     <groupId>com.alibaba.cloud</groupId>
     <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
 </dependency>
server.port=9999
spring.application.name=sentinel
spring.cloud.nacos.server-addr=127.0.0.1:8848

# 开启 sentinel 保护
spring.cloud.sentinel.enabled=true
# 指定 sentinel dashboard web地址
spring.cloud.sentinel.transport.dashboard=127.0.0.1:8080
# 指定 sentinel dashboard 组件通信地址端口
spring.cloud.sentinel.transport.port=8719

==注意:得调用接口后sentinel dashboard面板才会显示接口信息==

QPS:每秒得请求数
RT:每个请求响应时间

Nacos

下载

文档:https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html

版本对应关系:https://github.com/alibaba/spring-cloud-alibaba/wiki

20200721083526479

问题解决

1,db.num is null 问题

1,mysql 下新建数据库 nacos 字符集 utf8 编码 utf8_general_ci
2,执行 nacos/conf/nacos-mysql.sql 的 sql 脚本文件
3,修改 conf 文件夹下的 application.properties

image-20210416163723734

2,Unable to start web server

解决1,选择 bin 文件夹下的 startup.cmd ,右键编辑,更改集群模式为单机模式 standalone
既 set MODE="cluster" 改为   set MODE="standalone"

解决2,启动命令(standalone代表着单机模式运行,非集群模式):
cmd 中执行 startup.cmd -m standalone

访问

http://127.0.0.1:8848/nacos 默认账户密码 nacos

SpringBoot与Nacos整合

官方文档:https://nacos.io/zh-cn/docs/quick-start-spring-boot.html

官方文档使用的是 nacos-discovery-spring-boot-starter

我这里使用的 spring-cloud-starter-alibaba-nacos-config

1,pom文件

nacos-config这个依赖就相当于SpringCloud Config,nacos-discovery这个依赖就相当于Eureka

<!-- nacos-config这个依赖就相当于SpringCloud -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>

<!-- nacos-discovery这个依赖就相当于Eureka 需要 httpcomponents 包 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
</dependency>

<!--使用feign调用服务提供者-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>

<!--  注意版本问题   -->

2,配置中心nacos-config

Resources目录下创建配置文件bootstrap.yml
spring:
  application:
    # 应用名 
    name: test-v0710
  profiles:
    active: dev
  cloud:
    nacos:
      config:
      # 配置文件的环境:和nacos中一样定义的一样即可
        group: v0710_dev
      # 配置文件的格式
        file-extension: yaml
       # 配置中心的地址
        server-addr: 127.0.0.1:8848
      # 配置文件prefix
        prefix: ${spring.application.name}
      #命名空间 :指向哪个空间的,然后取指向空间的 data id 和 group
        namespace: v0710
      # 动态刷新 然后类上加  @RefreshScope 注解 
        refresh-enabled: true
配置 Data Id

Nacos中的Data Id= ${spring.application.name} - ${spring.profiles.active} . ${file-extension}

以上配置中的 Data Id 就等于指向 test-dev.yaml

默认 namespace(命名空间)为 public ,

新建一个命名空间为v0710,可在 bootstrap.yml 中指定 namespace: v0710 ,此时这个配置文件就指向自己定义的这个v0710空间中,Data Id 就取这个自建的空间v0710的配置 Data Id

image-20210417082730554

image-20210417081529036

image-20210417083238915

image-20210417150447066

Controller
@RestController
@RefreshScope  // 刷新
public class ProvideController {
    // 得到的就是上图的配置的 myname
    @Value("${myname:null}")
    private String name;

    @GetMapping("/getName")
    public String hi(){
        System.err.println(name);
        return name;
    }
}

浏览器访问 http://localhost:8080/getName 即可得到 nacos 的配置值,随时修改随时得到值

3,注册中心nacos-discovery

bootstrap.yml的nacos节点下增加配置
      discovery:
        # 服务地址
        server-addr: 127.0.0.1:8848
        # 组名
        group: v0710_dev
        # 空间名
        namespace: v0710

注:如果配置中心与当前应用的配置文件都配置了相同的key,优先使用配置中心的配置。
在启动类上添加 @EnableDiscoveryClient 注解 开启自动发现服务即可自动添加到nacos的注册中心中

4,Springboot配置文件的加载先后顺序

  • 优先加载操作系统层面的配置、命令行
  • 由jar包外向jar包内进行寻找,优先查找config目录。
  • 优先加载带profile(application-{profile}.yml)的,后加载不带profile(application.yml)的
  • 高优先级的配置覆盖低优先级的配置,所有的配置会形成互补配置
# 以Nacos为例:默认远程配置优先级最高
spring:
  cloud:
    config:
      # 是否允许本地配置覆盖远程配置
      allow-override: true
      # 是否一切以本地配置为准,默认false
      override-none: false
      # 系统环境变量或系统属性才能覆盖远程配置文件的配置
      # 本地配置文件中配置优先级低于远程配置,默认true
      override-system-properties: true

案例

生产者消费者都要注册到nacos

1,添加pom

2,添加配置文件

3,添加注解

生产者

提供服务接口供消费者调用

@RestController
@RefreshScope  // 刷新
public class ProvideController {

    @Value("${myname:null}")
    private String name;

    @GetMapping("/getName")
    public String hi(){
        System.err.println(name);
        return name;
    }
}

消费者

消费调用生产者提供的接口这里采用 fegin 方式调用

启动类添加注解 @EnableFeignClients

创建

@FeignClient(name = "test-v0710") // 服务提供者的 spring.application.name
public interface ConsumerClient {
    @GetMapping("/getName")
    String ConsumerGetName();
}

调用

@RestController
public class ConsumerController {    
    @Autowired // 注入创建的 Feign    
    private ConsumerClient consumerClient;    
    
    @GetMapping("/consumer")   
    public String consumer(){       
        String name = consumerClient.ConsumerGetName();        
        System.err.println("consumer=>"+name);       
        return name;    
    }}

Gateway 网关

文档,https://docs.spring.io/spring-cloud-gateway/docs/2.2.7.RELEASE/reference/html/

1,原理

Spring Cloud Gateway Diagram

  • Route 路由:gateway的基本构建模块。它由ID、目标URI、断言集合和过滤器集合组成。如果聚合断言结果为真,则匹配到该路由。

  • Predicate 断言:这是一个Java 8 Function Predicate。输入类型是 Spring Framework ServerWebExchange。这允许开发人员可以匹配来自HTTP请求的任何内容,例如Header或参数或请求路径等。

  • Filter 过滤器:这些是使用特定工厂构建的 Spring FrameworkGatewayFilter实例。所以可以在返回请求之前或之后修改请求和响应的内容。

2,使用

导入pom依赖

我这里版本是在父依赖中引入
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

配置文件

spring:
  application:
    # 应用名称
    name: test-gateway
  cloud:
    nacos:
      discovery:
        # 注册中心地址
        server-addr: 127.0.0.1:8848
        group: v0710_dev
        namespace: v0710
    # 网关配置
    gateway:
      discovery:
        locator:
          # 开启从注册中心动态创建路由的功能,利用微服务名称进行路由
          enabled: true
      routes:
        - id: test-gateway
          # 用nacos注册中心的服务名称进行路由
          uri: lb://test-v0710
          # 匹配规则
          predicates:
            # **:通配符 ;断言,路径相匹配的进行路由,我这里匹配的是以 getName 开头的接口
            - Path=/getName/**
      enabled: true
server:
  port: 777

3,过滤器

  1. 全局过滤器与其他2类过滤器(自定义,默认)相比,永远是最后执行的;它的优先级只对其他全局过滤器起作用
  2. 当默认过滤器与自定义过滤器的优先级一样时,优先出发默认过滤器,然后才是自定义过滤器

filters 下的值可以是 每个GatewayFilterFactory类的后缀,例如AddRequestHeaderGatewayFilterFactory,则filters 下可配置

AddRequestHeade过滤

image-20210419185315972

3-1,路径过滤器 Path

Path过滤器可以实现 url 路径重写,通过重写隐藏真实路径提高安全

……………………………等,使用的时候在进行记录

3-2,自定义…Filter

Spring Cloud Gateway 的自定义Filter分为GatewayFilter局部过滤器和GlobalFilter全局过滤器

GatewayFilter : 需要通过spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过spring.cloud.default-filters配置在全局,作用在所有路由上

GlobalFilter : 全局过滤器,不需要在配置文件中配置,作用在所有的路由上,最终通过GatewayFilterAdapter包装成GatewayFilterChain可识别的过滤器

GatewayFilter局部过滤器

如果自定义工厂后缀是以GatewayFilterFactory 结尾,配置文件 filters 下就可以写 GatewayFilterFactory 的前缀

例如:类名 CustomerGatewayFilterFactory – 配置中 filters : Customer

如果自定义工厂后缀不以 GatewayFilterFactory 结尾,配置文件 filters 下就的写具体类的全名

例如:类名 CustomerFilter – 配置中 filters : CustomerFilter

自定义工厂

// @Component
public class CustomerGatewayFilterFactory extends AbstractGatewayFilterFactory {
    @Override
    public GatewayFilter apply(Object config) {
        return new CostomerGatewayFilter();
    }
}

也可以把 CostomerGatewayFilter.filter 中逻辑处理放在 CustomerGatewayFilterFactory 的 apply 方法下 若依就是这样实现

自定义局部过滤器

@Slf4j
public class CostomerGatewayFilter implements GatewayFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("自定义局部过滤器:{}====================", "CustomerGatewayFilter");
        return chain.filter(exchange);
    }
 
    /**
     * 值越小,优先级越高,
     *
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

在配置类中将自定义过滤器工厂注册到容器中,当然也可以在自定义过滤器工厂类上加 @Component 注解

@Configuration
public class GatewayConfig {
 
    @Bean
    public CustomerGatewayFilterFactory myGatewayFilterFactory() {
        return new CustomerGatewayFilterFactory();
    }
 
}

配置文件

spring:
  application:
    name: service-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
        - id: service-provider
          uri: lb://service-provider
          predicates:
            - Path=/provider/**
          filters:
            - Customer # CustomerGatewayFilterFactory 可省略GatewayFilterFactory
 

https://www.cnblogs.com/zhaoxiangjun/p/13042189.html

https://www.cnblogs.com/westlin/p/10909799.html

GlobalFilter全局过滤器

自定义全局过滤器需要实现 GlobalFilterOrdered 接口

@Slf4j
public class LoginFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        String token = request.getHeaders().getFirst("token");
        log.info("访问的路径:{}", path);
        log.info("token: {}==================", token);
 
        if (token == null) {
            ServerHttpResponse response = exchange.getResponse();
            response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
            ResponseData responseData = new ResponseData(401, "请登录");
            String res = null;
            try {
                res = new ObjectMapper().writeValueAsString(responseData);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            DataBuffer wrap = response.bufferFactory().wrap(res.getBytes(StandardCharsets.UTF_8));
            return response.writeWith(Mono.just(wrap));
        }
        return chain.filter(exchange);
    }
 
    @Override
    public int getOrder() {
        // 值越小 优先级越高 只对全局过滤器起作用,在自定义过滤器后执行
        return 0;
    }
}

在配置类中注册全局过滤器,这样这个全局过滤器就是全局过滤了

@Configuration
public class GatewayConfig {
 
    @Bean
    public GlobalFilter loginFilter() {
        return new LoginFilter();
    }
}

OpenFeign 远程调用

注意 feign 是内部调用 不走网关

1,feign调用传递请求头

@Configuration
public class FeignConfiguration implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        String authorization = request.getHeader("Authorization");
        System.err.println("feign设置header:" + authorization);
        requestTemplate.header("Authorization", authorization);
    }
}

2,feign调用请求超时时间设置

feign:
  client:
    config:
      qzd-jeepay-pay:#设置为服务名既给该服务单独设置请求超时时间
        connectTimeout: 5000 #连接服务时间
        readTimeout: 60000 #请求超时时间

3,异步调用获取不到token

image-20240711111952892

解决:

feign接口中添加请求头如下

image-20240711112604488


日夜颠倒头发少 ,单纯好骗恋爱脑 ,会背九九乘法表 ,下雨只会往家跑 ,搭讪只会说你好 ---- 2050781802@qq.com

×

喜欢就点赞,疼爱就打赏

相册 说点什么